open-standards/.github/workflows/wai-conformance.yml
Transaction Science 1ae28b8407
Some checks failed
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 8s
WAI conformance / does this change touch it (pull_request) Successful in 8s
WAI energy receipts / does this change touch it (pull_request) Successful in 6s
WAI HTTP delivery / WAI HTTP · does this change touch it (pull_request) Successful in 6s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Has been skipped
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 5s
wai-web wasm32 / does this change touch it (pull_request) Successful in 5s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Has been cancelled
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Has been cancelled
wai-pack / wai-pack · linux (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Has been cancelled
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
Merge remote-tracking branch 'origin/main' into wai/live-ads
# Conflicts:
#	.github/workflows/wai-conformance.yml
#	wai/CHANGELOG.md
#	wai/REGISTRY.md
#	wai/SPEC.md
#	wai/live-conformance/README.md
#	wai/wai-rs/Cargo.toml
#	wai/wai-rs/src/codecs/registry.rs
#	wai/wai-rs/src/lib.rs
#	wai/wai-rs/tests/int_kernels_vectors.rs
2026-10-20 13:07:05 -04:00

1372 lines
89 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: WAI conformance
# WAI's load-bearing claim is bit-exact reconstruction on every machine,
# no tolerance parameter. This workflow enforces it mechanically: every
# cargo-class corpus — and the integer-exact neural decoders, which make the
# same promise (the registry's NeuralIntegerExact class: i64-only, no float
# ONNX) — is re-derived on every OS/arch leg of the matrix below (x86-64 and
# arm64) and must reproduce its frozen BLAKE3 hashes; and the integer
# byte-equality goldens (rANS / int_synth / JPEG-AI mANS, generated once on
# a reference machine) must decode identically everywhere. All of it is pure
# Rust (no C codec chain, no ONNX Runtime), so the matrix needs no system
# dependencies.
# One run per branch at a time. A push supersedes the run before it.
#
# There is one `macos` runner and it is the dev Mac, so every macOS job in this
# repo queues on it. With no concurrency group, a session pushing four versions
# of a branch queued four complete sets of runs and every one of them had to
# drain: on 2026-10-05 a PR's 21 contexts settled none in 70 minutes behind a
# backlog of 25 runs, and the queue grew faster than it cleared. Only the newest
# commit's verdict is wanted, so the older runs are cancelled.
#
# Verified on this forge (Forgejo 16.0.5) in `ci-test` before being added here:
# the key parses, and a newer push moves an older run to `cancelled` even while
# it is still queued, which is the case that matters.
#
# `cancel-in-progress: true` also applies to `main`. That is deliberate and
# safe here: main advances by merge commits whose tree contains the commits
# before them, so the newer run covers the older one's changes.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
pull_request:
paths:
- 'wai/wai-rs/**'
# wai-rs path-depends on wai-quantum, and the quantum corpora below are
# verified through it: a change there changes what this workflow checks.
- 'wai/wai-quantum/**'
# The integer decoders that decode through the integer operator set depend on it.
- 'wai/wai-ops/**'
- 'wai/*-conformance/**'
- 'wai/byte-exact-conformance/**'
# The registry export and the two library tests that read files outside
# wai-rs (the codec glossary, SPEC.md) must fire this workflow too: a
# hand edit of an exported file, of SPEC §5 or of the glossary is checked
# here. vocab/v1's and v2's pin terms are checked by a library test.
- 'wai/registry/**'
- 'wai/vocab/**'
- 'wai/glossary/**'
- 'wai/SPEC.md'
- 'wai/REGISTRY.md'
# A library test checks SPEC §5's pinned integer payloads against this
# extension's sections, so an edit of it is checked here too.
- 'wai/extensions/integer-payloads.md'
# A library test (staged::tests::staged_delivery_text_lists_the_codes) checks
# that this extension's §4.2 and A.6 list the codes the sink reports.
- 'wai/extensions/staged-delivery.md'
# A library test (codecs::registry::tests::wire_identifiers_are_in_their_documents)
# checks every wire identifier against the section of these texts it names, and
# staged::moq::tests::moq_streaming_format_lists_the_codes checks §4.1's codes.
- 'wai/extensions/http-delivery.md'
- 'wai/extensions/moq-streaming-format.md'
- 'wai/extensions/jwp-receipts.md'
# The quantum referee requires this extension's Appendix B to state its phase tables.
- 'wai/extensions/quantum-sim.md'
# tests/live_events.rs requires this extension's §9 to list the codes the reference
# reports, and the registry's wire identifiers test reads its sections.
- 'wai/extensions/live-events.md'
# tests/live_room.rs requires this extension's §11 to list the codes the reference
# reports, and the registry's wire identifiers test reads its sections.
- 'wai/extensions/live-rooms.md'
# tests/capture_take.rs requires this extension's §12 to list the codes the reference
# reports, and the registry's wire identifiers test reads its sections.
- 'wai/extensions/capture-binding.md'
# tests/live_compose.rs requires this extension's §10 to list the codes the reference
# reports, and the registry's wire identifiers test reads its sections.
- 'wai/extensions/live-compose.md'
# tests/live_record.rs requires this extension's §9 to list the codes the reference
# reports, and the registry's wire identifiers test reads its sections.
- 'wai/extensions/live-recording.md'
# tests/timed_text.rs requires this extension's §12 to list the codes the reference
# reports, and the registry's wire identifiers test reads its sections.
- 'wai/extensions/timed-text.md'
# tests/live_metering.rs requires this extension's §9 to list the codes the reference
# reports, live_metering_verify.py reads that table, and the registry's wire identifiers
# test reads its sections.
- 'wai/extensions/live-metering.md'
# tests/energy_steering.rs requires this extension's §10 to list the codes the reference
# reports, energy_steering_verify.py reads that table, and the registry's wire
# identifiers test reads its sections.
- 'wai/extensions/energy-steering.md'
# tests/live_moderation.rs requires this extension's §10 to list the codes the reference
# reports, live_moderation_verify.py reads its §9.5, §9.6 and §10 tables, and the
# registry's wire identifiers test reads its sections.
- 'wai/extensions/live-moderation.md'
# tests/live_watermark.rs requires this extension's §11 to list the codes the reference
# reports, live_watermark_verify.py reads that table, and the registry's wire identifiers
# test reads its sections.
- 'wai/extensions/forensic-watermark.md'
# e2ee_verify.py reads this extension's §13 table, and the registry's wire identifiers
# test reads its sections.
- 'wai/extensions/confidentiality.md'
# tests/live_ads.rs requires this extension's §10 to list the codes the reference
# reports, live_ads_verify.py reads that table, and the registry's wire identifiers test
# reads its sections.
- 'wai/extensions/live-ads.md'
- 'wai/wai-web/**'
# The audio provenance check below reads the corpora above with this tool.
- 'wai/tools/wai_audio_provenance_check.py'
- '.github/workflows/wai-conformance.yml'
# No global `shell:` default. The Windows runner is a host executor whose
# `bash` is the WSL stub (a different OS), so shell-specific steps below pick
# their shell per-OS: bash on unix, pwsh on Windows. Bare `cargo …` steps take
# each runner's native default, which runs cargo identically either way. The
# Windows legs are out of the matrices for now (see the comment on each matrix);
# their pwsh steps stay, inactive, so restoring a leg is a one-line change.
schedule:
- cron: '20 5 * * *'
jobs:
# Does this pull request's own diff touch the paths below? This forge matches a
# workflow's `paths:` against the push, so a merge of main into a branch fires the
# workflow whatever the pull request changes; every job here waits on this answer.
# A push to main, a schedule, or anything the script cannot determine answers
# `true` (scripts/pr-touches-paths.py).
relevant:
name: does this change touch it
runs-on: linux-arm64
outputs:
run: ${{ steps.gate.outputs.run }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- id: gate
run: |
set -euo pipefail
r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-conformance.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches wai-conformance: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
cargo-classes:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: cargo-class corpora · ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Self-hosted fleet labels. Both architectures: x86_64 by linux, arm64
# by linux-arm64 + macos — what matters for the Fx integer floor is the
# arch, not the OS. No Intel-Mac runner exists in the fleet, and it
# would add no arch coverage anyway.
# Windows x86_64 leg removed 2026-09-30: runner offline. Restore by
# re-adding `windows` here once the runner is back online.
os: [linux, linux-arm64, macos]
steps:
- uses: actions/checkout@v5
# unix: the docker runners (linux / linux-arm64) ship no Rust, so rustup
# is bootstrapped; the macOS `host` runner has it but launchd's PATH omits
# ~/.cargo/bin. dtolnay/rust-toolchain is unusable — it calls a `rustup`
# the docker image lacks.
- name: Install Rust 1.98.0 (unix)
if: matrix.os != 'windows'
shell: bash
run: |
export PATH="$HOME/.cargo/bin:$PATH"
command -v rustup >/dev/null 2>&1 || \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
rustup component add --toolchain 1.98.0 clippy
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# Windows: a host executor with rustup already installed. Only ensure the
# pinned toolchain is present + default. pwsh, never bash (that is WSL here).
- name: Install Rust 1.98.0 (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
- name: Build the cargo classes (pure Rust, no C codec chain)
working-directory: wai/wai-rs
# neural_int joins the pure-Rust set: the integer-synthesis decoder is
# i64-only (no ONNX, no float), so it carries the same bit-exact promise
# and is checkable on this matrix with no ONNX Runtime present. receipt_claims
# is in the set because the reference meters (wai_meter, wai_world_meter) write a
# measurement report by default and require it: without it they would drop out
# of this build on every leg of this matrix, without a word. staged and the integer
# media features build the staged-delivery core, its corpus tool and `wai stage`;
# stage_measure builds the staged-measurement core and wai_stage_measure; telemetry
# the delivery-telemetry mapping and wai_telemetry; http the HTTP delivery binding,
# its corpus tool and `wai http`.
run: cargo build --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,receipt_claims,staged,video_int,audio_int,splat_int,stage_measure,telemetry,http
# video_package runs the package receipt's dedup tests, which content_dedup feeds.
# The dev profile keeps overflow checks on, so an arithmetic overflow in the HTTP
# binding (http_binding::tests, among them a seeded test of every parser of untrusted
# input) fails here rather than wrapping.
- name: Library unit tests (the fixed-point determinism floors)
working-directory: wai/wai-rs
run: cargo test --lib --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,oer,receipt_claims,key_discovery,staged,video_int,audio_int,splat_int,stage_measure,telemetry,video_package,http
# The JPEG AI exact decoder reproduces across platforms only if no platform math
# library is on its path. Two guards, each failing the step: clippy's
# disallowed-methods (wai-rs/clippy.toml), which each module on the decode path
# denies, rejects a listed float method however it is spelled; and
# tests/jpegai_decode_symbols.rs lists the linked decoder's symbols with `nm` and
# rejects any C math-library function it imports, whatever made the call, and any
# it defines other than the round-to-integral ones (see its doc). `-A clippy::all`
# keeps the output to that guard. Unix legs only: `nm` is not on the Windows
# runner, and for clippy the unix legs already cover both architectures.
- name: JPEG AI exact decode calls no platform math library (unix)
if: matrix.os != 'windows'
shell: bash
working-directory: wai/wai-rs
run: |
set -euo pipefail
cargo clippy --lib --no-default-features --features neural_int -- -A clippy::all
cargo test --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film --test jpegai_decode_symbols
# Each extension container refuses a count its bytes cannot hold, without reserving
# it first (found by the coverage-guided fuzzer, wai-rs/fuzz/, target `containers`),
# and a declared duration past the reader limits it shares with SPEC §2.
- name: Extension containers reserve no more than their bytes hold, and are held to their duration limits
shell: bash
working-directory: wai/wai-rs
run: cargo test --no-default-features --features world,audio_scene,haptic,splat4d,score,film --test container_reservations --test extension_duration_limits
# The integer decoders run fast kernels (src/int_kernels.rs) that must give
# the same integer as the scalar reference kernels for every output element.
# The feature list above leaves out audio_int, video_int, world_int and
# splat_int, so without these two steps int_audio's kernel-equivalence tests
# and tests/int_kernels_vectors.rs (every committed integer-decoder vector
# decoded under the reference and under each fast policy, against its frozen
# hash) would run nowhere. `--lib` also carries the other kernels' equivalence
# modules; tests/int_kernels_geometry.rs runs edge geometry (strides up to
# usize::MAX, padding far beyond the kernel) through the public decoders
# under every policy. Both profiles, because the overflow-parity tests assert
# different things in each: with overflow checks on (dev) that the fast path panics
# where the reference panics, with them off (release) that it returns the
# same integers. All pure Rust, so every leg runs them.
# tests/int_synth_ops.rs holds wai.neural.int_synth to its lowering through the
# integer operator set (extensions/integer-operators.md §13.1): every committed set
# lowers to its committed graph and loads with its certificate's verdict, decodes
# through it to every committed golden, and refuses whatever the direct decode
# refuses. tests/int_ops_differential.rs (feature legacy_int: the direct decode,
# test-only) decodes random sets and payloads both ways: the same output or both
# refused, except on the planned breaks of integer-operators §15.3, where the decode
# through the operator set refuses. wai-ops-differential.yml runs it for an hour in
# each profile, nightly. tests/int_splat_ops.rs holds wai.splat.int_codec to its
# lowering whm1/1 the same way (integer-operators §13.2): its committed set lowers,
# from its bytes and from the model this crate parses, to its committed graph, and
# loads with its certificate's verdict. tests/int_audio_ops.rs does the same for
# wai.audio.int_codec and its lowering wam1/1 (§13.3), and tests/int_hyper_ops.rs
# for wai.neural.int_hyper and the keyframe of wai.video.int_hyper (whm1/1: h_s,
# then g_s with the RGB8 step), and tests/int_mlicpp_ops.rs for wai.neural.int_mlicpp
# (wmb1/1: h_s, entropy, then g_s with the RGB8 step), and tests/int_world_ops.rs for
# wai.world.model's integer renderer (world/1, informative: T with its action planes,
# then g_s with the RGB8 step).
# tests/int_mlicpp.rs decodes the committed wai.neural.int_mlicpp vector against
# its pinned hashes (image, every scale bucket, every symbol) under every kernel
# policy and thread count, and checks that damaged payloads are refused rather than
# overflowing — which is why it runs in both profiles too.
# tests/int_mlicpp_preflight.rs (its own binary: it installs a counting global
# allocator) checks that a header the model cannot fit is refused before the
# decode allocates anything sized from it.
# tests/int_audio.rs and tests/int_splat.rs decode the committed wai.audio.int_codec and
# wai.splat.int_codec vectors against the hashes the Python integer reference computed at
# export, and check each vector's metadata. `--lib` runs int_payload's unit tests: each
# binary payload (WIV1, WIH1, WIA1, WIS1) against the JSON it is converted from, under
# every kernel policy, and decode_int for every integer capability in this build, which
# has no `neural`. tests/int_payload.rs refuses every fixture of int-payload-conformance
# with its code, every strict prefix of every payload, and runs a byte-change sweep in
# which nothing may panic; tests/int_payload_preflight.rs (its own binary, a counting
# allocator) checks that a header past the caps is refused before anything sized from it
# is allocated; tests/int_payload_cost.rs (its own binary, a live-bytes allocator) checks
# that int_payload::declared_cost bounds what each decode holds, with the store of loaded
# sets off, then on (a decode that loads its set, and one that finds it held), that the
# store counts at least the bytes it holds, and, in the release step only, decodes a
# 2^30-byte clip a 3 KB payload codes; tests/int_set_cache.rs checks that store under
# the decodes: a second decode through a set is a hit with the same bytes on every
# committed vector, sets one byte apart never share an entry, a refused set stays
# refused, refusals keep their codes, and the least recently used set goes first;
# tests/int_world_memory.rs (its own binary, the same allocator) checks that the world
# renderer, with its set loaded, holds no more than the direct renderer it replaced.
# tests/int_video_enc_memory.rs
# (its own binary, the same allocator) checks that int_video_enc::working_bytes bounds
# what the encoder holds. tests/staged_resources.rs (its
# own binary, a counting allocator) checks that the staged sink's work and memory per
# layer grow linearly in the layer's units, that a layer past the chain budget is
# refused before any stream is decoded, that what no unit holds is dropped, and that a
# WIR1 parse holds no more than its declared working bytes. tests/stage_measure.rs counts every
# committed staged envelope as exactly its length, refuses JSON, base64 and another capability's
# format, and evaluates a measured title read from a map of files to its golden, refusing a
# changed byte of a layer, the base, the source or a parameter-set file (extensions/
# staged-measurement.md). Cargo.toml declares them, and the other
# feature-gated targets named here, with required-features, so if this step ever loses a
# feature, cargo stops with an error instead of compiling an empty binary that reports ok.
# Each committed vector's decoded output is also checked against the SHA-256 in
# its sha256.json sidecar (SPEC §7 *Digests*), and
# int_kernels_vectors::every_decoded_output_states_a_sha256 requires a sidecar,
# or a named exclusion, for every corpus directory. tests/generate.rs checks the
# wai.generate.spectral vectors, which `generate` enables: the 96x96 vector, sizes.json
# and instr-v0.json, the instruction object of form v0 (SPEC §5), whose two larger
# listed sizes run only in the release step (seconds each in a debug build).
# tests/cli_generate_score.rs runs `wai generate` and `wai score build|render`, which
# the features `generate` and `score` build into the `wai` binary: every pin it prints
# against those vectors and score-conformance/ (pcm_sha256 among them), every object
# instr-v0.json lists as accepted (one at each bound) made and wrapped, every object
# it lists as refused refused for the reason it states, and each refusal writing
# nothing; tests/generate.rs holds the same lists to a second statement of form v0.
# tests/manifest_parse_memory.rs (its own binary, a counting allocator) checks that
# reading a manifest allocates within the bound SPEC §2's reader limits give, at the
# length limit and at the value limit, and tests/manifest_reader_equivalence.rs holds
# the readers to the derived reader's result on every committed envelope. Both run in
# the release step only: the first writes manifests of 2^27 bytes, which takes a debug
# build most of a minute.
# tests/int_video.rs, int_video_halfpel.rs and int_video_keyframe.rs hold the integer
# video codec to its goldens (whole clips, half-pel motion, the keyframe through the
# integer hyperprior); int_world.rs and int_world2.rs the integer world renderers;
# jpegai_bitstream_calibration.rs the JPEG AI bitstream reader against the committed
# codestream. No step named any of them until scripts/check-tests-in-ci.py asked.
# jpegai_ops.rs holds the JPEG AI scale path (integer-operators §13.6.1) to its committed
# lowered graphs and certificate here; its cases on the jpegai/v1 bundle skip here and
# run in wai-jpegai-e2e.yml, which fetches the bundle and requires them.
# jpegai_nets_ops.rs does the same for its other integer networks (§13.6.2): the
# committed synthetic networks' lowered graphs and certificate, and every kernel
# policy on them, here; its jpegai/v1 cases there.
# int_video_ops.rs and wir1_ops.rs hold WIV1 and WIR1, which decode through the
# operator set's stage operators with no graph (integer-operators §13.5), to their
# stage forms, goldens and refusals; `i32_forms` builds E9's 32-bit form, which they
# and int_ops_differential.rs hold to the exact one.
- name: Fast integer kernels ≡ reference kernels (overflow checks on)
working-directory: wai/wai-rs
run: cargo test --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int,generate,score,staged,stage_measure,legacy_int,i32_forms --lib --test int_kernels_vectors --test int_kernels_geometry --test int_synth_ops --test int_ops_differential --test int_splat_ops --test int_audio_ops --test int_hyper_ops --test int_mlicpp --test int_mlicpp_preflight --test int_mlicpp_ops --test int_world_ops --test int_world_memory --test jpegai_ops --test jpegai_nets_ops --test int_video_ops --test wir1_ops --test int_audio --test int_splat --test generate --test cli_generate_score --test int_payload --test int_payload_preflight --test int_payload_cost --test int_set_cache --test int_video_enc_memory --test cli_stage --test staged_resources --test stage_measure --test stage_measure_bounds --test int_video --test int_video_halfpel --test int_video_keyframe --test int_world --test int_world2 --test jpegai_bitstream_calibration
- name: Fast integer kernels ≡ reference kernels (release, overflow checks off)
working-directory: wai/wai-rs
run: cargo test --release --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int,generate,score,staged,stage_measure,legacy_int,i32_forms --lib --test int_kernels_vectors --test int_kernels_geometry --test int_synth_ops --test int_ops_differential --test int_splat_ops --test int_audio_ops --test int_hyper_ops --test int_mlicpp --test int_mlicpp_preflight --test int_mlicpp_ops --test int_world_ops --test int_world_memory --test jpegai_ops --test jpegai_nets_ops --test int_video_ops --test wir1_ops --test int_audio --test int_splat --test generate --test cli_generate_score --test int_payload --test int_payload_preflight --test int_payload_cost --test int_set_cache --test int_video_enc_memory --test cli_stage --test staged_resources --test stage_measure --test stage_measure_bounds --test manifest_parse_memory --test manifest_reader_equivalence --test int_video --test int_video_halfpel --test int_video_keyframe --test int_world --test int_world2 --test jpegai_bitstream_calibration
# The integer decode path builds under each of its features alone, so a sink can take
# one medium without the others, and for wasm32 (a browser sink); `int_payload` arms a
# medium only under its feature, and none needs `neural`. So does the staged-measurement
# core (`stage_measure`), which pulls no ONNX and reads no file on wasm32. The HTTP
# binding (`http`) performs no I/O, so it builds alone and for wasm32 too.
- name: Each integer feature alone, and wasm32 (unix)
if: matrix.os != 'windows'
shell: bash
working-directory: wai/wai-rs
run: |
set -euo pipefail
for f in neural_int video_int audio_int splat_int staged stage_measure telemetry http; do
cargo check --lib --no-default-features --features "$f"
done
# The decode bench prints its machine line from bench_env; no other step builds it.
cargo build --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int --bin wai_decode_bench
rustup target add --toolchain 1.98.0 wasm32-unknown-unknown
cargo check --lib --target wasm32-unknown-unknown --no-default-features --features video_int,audio_int,splat_int,staged,http
# The staged-measurement core is wasm32-clean: a browser computes the same figures.
# Built, not only checked, so codegen and linking of the library run for wasm32.
cargo build --lib --target wasm32-unknown-unknown --no-default-features --features stage_measure
# With the claim classes too: a browser sink seals its reconstruct-session claim
# (jwp-receipts §2.4.12), and wai-web's measurement binding signs with them.
cargo build --lib --target wasm32-unknown-unknown --no-default-features --features receipt_claims,stage_measure
# So is delivery telemetry: a browser sink writes the same reports.
cargo build --lib --target wasm32-unknown-unknown --no-default-features --features telemetry
# carriage: every registered capability round-trips byte-exact. cli_wrap_intent and
# cli_registry run the `wai` binary, which builds without the codecs feature: the
# intent rule of `wai wrap`, its refusal of candidate capabilities (SPEC §5), its media
# class, and `wai registry export --check` on the tree and on a drifted copy.
# tests/manifest_builders.rs: the manifest types are #[non_exhaustive], and the
# builders write the JSON a struct literal wrote; members the types keep only
# as `extra` (and `security`) survive a round trip.
# corpus_provenance: every corpus README states where its content comes from.
- name: Carriage conformance, the wai CLI (wrap, registry export) and corpus provenance
working-directory: wai/wai-rs
run: cargo test --no-default-features --test carriage --test manifest_builders --test cli_wrap_intent --test cli_registry --test corpus_provenance
# tests/cli_http.rs runs `wai http publish`, `codecs`, `origin` and `bench` as a user
# does: objects named by their content hash with their head proofs, a sequence's union
# and floor, the origin's headers, ranges and If-Range on loopback, and a fetch by
# the byte-range procedure whose record states energy as not measured; and `hls`,
# `mpd`, `seal-playlist` and `check-playlist`, whose receipts need video_manifest;
# and `receipts`, an object's receipt index checked over HTTP with its signers
# confirmed under a key log, which needs key_discovery: the log anchored over TLS
# (cli_tls; the binary's own tests run its TLS client against servers under a test
# CA, tests/fixtures/tls/), never over plaintext, and a plaintext test anchor
# labelled as one. The second run builds without cli_tls: the CLI then refuses to
# anchor and connects to nothing.
# Cargo.toml declares it with required-features = ["http"]. tests/dash_read_bounds.rs
# holds Appendix I's reader to the document's size under a counting allocator, and an
# element's attributes to linear CPU time; a binary of its own, one test.
- name: The wai http commands
working-directory: wai/wai-rs
shell: bash
run: |
cargo test --no-default-features --features http,video_manifest,key_discovery,cli_tls --bin wai --test cli_http --test dash_read_bounds
cargo test --no-default-features --features http,video_manifest,key_discovery --test cli_http -- receipts_never_anchors_over_plaintext
# tests/staged_moq.rs runs the MoQ trace of staged-conformance/moq/ (moq-streaming-format
# §4.1) with signed receipts: a chain for each track, a receipt held for its parent and
# admitted when it arrives, the relay's per-hop delivery timeout, dropped objects checked
# by inclusion and named by the relay's delivery-gap claims, and each base's stage claim,
# which seals and verifies; the subscriber of two tracks holds exactly their chains.
# Cargo.toml declares it with required-features = ["staged", "video_int", "receipt_claims"].
# The interactive-world tests, which no step named: world_replay.rs (the replay
# class, under `world`), world_model.rs (the signed action trace and per-frame
# provenance, under `world_model`) and int_world_shared.rs (two sinks converging on
# one integer world, under both). `world_model` is enabled by no other step.
- name: World replay, the world model and the shared integer world
working-directory: wai/wai-rs
run: cargo test --no-default-features --features world_model,world_int --test world_replay --test world_model --test int_world_shared
- name: Staged tracks over MoQ, with signed receipts
working-directory: wai/wai-rs
run: cargo test --no-default-features --features staged,video_int,receipt_claims --test staged_moq
# The machine-readable registry (wai/registry/, wai/vocab/v2.*, the table in
# wai/REGISTRY.md) is generated from wai-rs/src/codecs/registry.rs. Regenerate it in
# memory and fail on any difference; the message says how to regenerate. One leg: the
# export is the same text on every platform.
- name: The registry export is up to date (linux)
if: matrix.os == 'linux'
working-directory: wai/wai-rs
run: cargo run -q --no-default-features --bin wai -- registry export --check
# The C ABI's envelope surface builds with no codec library (feature `ffi`):
# unpack returns each manifest as the envelope carries it, the WAI2 table carries
# every component's identity and selectability, wai_envelope_select follows
# SPEC §7.1 and never picks a candidate, and the packers refuse a candidate
# (SPEC §5). Cargo.toml declares the target with required-features.
- name: C ABI envelope surface (no codec library)
working-directory: wai/wai-rs
run: cargo test --no-default-features --features ffi --test ffi_envelope
# The browser crate wraps the same envelope types (wai::container), so role,
# companion_of, component identity and the pin reach JS, and its pick is SPEC
# §7.1's. Its tests target the pure-Rust half (`core`), which runs natively; one
# leg suffices, the logic is architecture-independent. The JS surface itself runs
# under wasm32 in wai-web-wasm.yml.
- name: wai-web envelope surface (native tests)
if: matrix.os == 'linux'
working-directory: wai/wai-web
run: cargo test --locked
# jwp-receipts §7.1, §7.8: no `did:web`/`did:key` literal in a tracked .rs, .json or
# .js file under wai/ names a real web origin — every key the tree signs with has a
# published seed. Ungated: it reads the tree through `git ls-files` and classifies
# with `signer_id`, which builds with no feature.
- name: Every signer id in the tree is a label
working-directory: wai/wai-rs
run: cargo test --no-default-features --test signer_ids_are_labels
# jwp-receipts §7: `wai-keys` builds a key log from operator-supplied seeds, appends
# revocations and rotations, signs statuses and module grants, verifies a log as
# §7.3 anchors one, and checks a DID document against it. The test drives the binary.
- name: wai-keys — build, check and publish an origin key log
working-directory: wai/wai-rs
run: cargo test --no-default-features --features key_discovery --test wai_keys_cli
# key_log has no I/O, clock or threads, so a browser sink could run it before it
# instantiates a module (§7.9); no browser sink does yet. Nor do the HTTP binding's
# receipts and keys (http-delivery §8.1–§8.5), which a browser client checks what it
# fetched with. This step checks that both build for wasm32 on the unix legs (the
# target is added to the pinned toolchain here; the Windows host runner is not set up
# for it).
- name: key_log and the HTTP receipts build for wasm32 (unix)
if: matrix.os != 'windows'
shell: bash
working-directory: wai/wai-rs
run: |
set -euo pipefail
rustup target add --toolchain 1.98.0 wasm32-unknown-unknown
cargo check --lib --target wasm32-unknown-unknown --no-default-features --features key_discovery,http
# The corpus-verify loop is genuinely shell-specific (a helper that groups
# log output and propagates the first non-zero exit), so it ships once per
# shell family. The command it runs is identical; only the wrapper differs.
- name: Every cargo-class corpus reproduces its frozen hashes (unix)
if: matrix.os != 'windows'
shell: bash
working-directory: wai/wai-rs
run: |
set -euo pipefail
F=world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,quantum,quantum_ops,oer,receipt_claims,key_discovery,video_int,audio_int,splat_int,staged,stage_measure,telemetry,http,video_manifest
v() { echo "::group::$1"; cargo run -q --no-default-features --features "$F" --bin "$2" -- verify "$3"; echo "::endgroup::"; }
v worlds wai_world_vectors ../world-conformance
v spatial-audio wai_audio_vectors ../audio-conformance
v haptics wai_haptic_vectors ../haptic-conformance
v state-feeds wai_feed_vectors ../feed-conformance
v avatars wai_avatar_vectors ../avatar-conformance
v volumetric wai_splat4d_vectors ../volumetric-conformance
v score wai_score_vectors ../score-conformance
v int-synth wai_int_synth_vectors ../neural-conformance
v film wai_film_vectors ../film-conformance
v quantum wai_quantum_vectors ../quantum-conformance
v quantum-ops wai_quantum_ops_vectors ../quantum-ops-conformance
v oer wai_oer_vectors ../oer-conformance
v jwp wai_jwp_vectors ../jwp-conformance
v claims wai_claim_vectors ../claim-conformance
v pin wai_pin_vectors ../pin-conformance
v signers wai_signer_vectors ../signer-conformance
v int-payload wai_int_payload_vectors ../int-payload-conformance
v staged wai_staged_vectors ../staged-conformance
v http wai_http_vectors ../http-conformance
v staged-measure wai_stage_measure ../staged-measure-conformance
v telemetry wai_telemetry ../telemetry-conformance
# The pin corpus's second implementation: Python standard library only, sharing no
# code with wai-rs. One leg is enough — it checks digests and listing rules, which
# do not depend on the architecture — and the macOS host has python3.
- name: The pin corpus checks against an independent verifier (macOS)
if: matrix.os == 'macos'
shell: bash
working-directory: wai
run: python3 pin-conformance/pin_verify.py pin-conformance
# Every committed audio vector must come from a seeded generator. This check reads
# each one to PCM (each audio base's stage 0 in the staged corpus, each measured
# source over one, each spatial-audio source, every audio file under wai/) and
# fails if any correlates above 0.5, at any lag, with a recording in the reference
# set the host has: its system sound directory, or the directories named in
# WAI_AUDIO_REFERENCE_DIRS. A generated signal stays near 0.2; a lossy coding of a
# recording is near 1. A host with no reference set, or no converter to read it,
# prints why and skips: the linux legs skip, the macOS leg checks.
- name: No committed audio vector is a coding of a reference recording (unix)
if: matrix.os != 'windows'
shell: bash
working-directory: wai
run: |
if command -v python3 >/dev/null 2>&1; then
python3 tools/wai_audio_provenance_check.py
else
echo "audio provenance: SKIPPED — no python3 on this host"
fi
# OER's second implementation is portable C, not Rust. Rebuild it from source and
# require its output to match the pinned corpus byte for byte: the kernel is
# deterministic, and wai_oer_vectors above has already verified the pinned copy,
# so equality carries that verification to what the source produces today.
# `cc` with the Makefile's flags, so the step needs no `make` on the runner.
- name: OER C kernel reproduces its pinned receipts (unix)
if: matrix.os != 'windows'
shell: bash
working-directory: wai/oer-conformance/settle
run: |
set -euo pipefail
cc -O2 -std=c99 -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare \
-o "$RUNNER_TEMP/settle_host" host_main.c settle.c sha256.c tweetnacl.c -lm
"$RUNNER_TEMP/settle_host" "$RUNNER_TEMP/firmware_vectors.json" 400
cmp "$RUNNER_TEMP/firmware_vectors.json" ../firmware_vectors.json
- name: Every cargo-class corpus reproduces its frozen hashes (Windows)
if: matrix.os == 'windows'
shell: pwsh
working-directory: wai/wai-rs
run: |
$F = "world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,quantum,quantum_ops,oer,receipt_claims,key_discovery,video_int,audio_int,splat_int,staged,stage_measure,telemetry,http,video_manifest"
function v($grp, $bin, $path) {
Write-Output "::group::$grp"
cargo run -q --no-default-features --features $F --bin $bin -- verify $path
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Write-Output "::endgroup::"
}
v worlds wai_world_vectors ../world-conformance
v spatial-audio wai_audio_vectors ../audio-conformance
v haptics wai_haptic_vectors ../haptic-conformance
v state-feeds wai_feed_vectors ../feed-conformance
v avatars wai_avatar_vectors ../avatar-conformance
v volumetric wai_splat4d_vectors ../volumetric-conformance
v score wai_score_vectors ../score-conformance
v int-synth wai_int_synth_vectors ../neural-conformance
v film wai_film_vectors ../film-conformance
v quantum wai_quantum_vectors ../quantum-conformance
v quantum-ops wai_quantum_ops_vectors ../quantum-ops-conformance
v oer wai_oer_vectors ../oer-conformance
v jwp wai_jwp_vectors ../jwp-conformance
v claims wai_claim_vectors ../claim-conformance
v pin wai_pin_vectors ../pin-conformance
v signers wai_signer_vectors ../signer-conformance
v int-payload wai_int_payload_vectors ../int-payload-conformance
v staged wai_staged_vectors ../staged-conformance
v http wai_http_vectors ../http-conformance
v staged-measure wai_stage_measure ../staged-measure-conformance
v telemetry wai_telemetry ../telemetry-conformance
# wai-quantum and the quantum corpus under wasm32-wasip2, run by wasmtime. On wasm32
# usize is 32 bits, so arithmetic that cannot overflow on a 64-bit host can there: a
# section's offset plus its length, a capacity reserved from a count a file claims, a
# shift by a qubit count. The builds are debug builds, so overflow checks are on and
# such an overflow panics instead of wrapping. Three steps:
# 1. tests/bit_identity.rs, which pins one result of each f64 layer, so the wasm32
# build must give the bits every native leg gives;
# 2. the library's unit tests in the modules that hold the circuit core, its
# container, its JSON reader and its pins (quantum, ijson, receipt_pins,
# quantum_fabric, quantum_source, quantum_channel, quantum_qudit, quantum_receipt),
# each required to have run, and each test of the fabric's groundwork for
# accelerator members required by name (the WebGPU member itself has no wasm32-
# wasip2 build; wai-quantum-webgpu.yml checks that the feature is inert there);
# 3. wai_quantum_vectors verify over all four trees of quantum-conformance/ (both
# capabilities, the reject corpus and the accept corpus), the same check the matrix
# above runs natively.
# One leg: wasm32 is the same machine on every host. Linux, so it does not queue on the
# single macOS runner.
quantum-wasip2:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: quantum core and corpus under wasm32-wasip2 (wasmtime)
runs-on: linux
# The fabric's planner test runs fabric-v1 under every planner configuration in a
# debug wasm build, several minutes on its own; the timeout leaves it room rather
# than the test being skipped on wasm32.
timeout-minutes: 90
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.98.0 with the wasm32-wasip2 target
shell: bash
run: |
export PATH="$HOME/.cargo/bin:$PATH"
command -v rustup >/dev/null 2>&1 || \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
rustup target add --toolchain 1.98.0 wasm32-wasip2
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# The release binary, pinned by version and SHA-256, rather than a build from source.
- name: Install wasmtime 49.0.2
shell: bash
run: |
set -euo pipefail
[ "$(uname -m)" = x86_64 ] || { echo "::error::the pinned wasmtime archive is x86_64; this host is $(uname -m)"; exit 1; }
if ! command -v xz >/dev/null 2>&1; then
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
$SUDO apt-get update -qq
$SUDO apt-get install -y -qq xz-utils
fi
v=49.0.2
f="wasmtime-v$v-x86_64-linux.tar.xz"
curl --proto '=https' --tlsv1.2 -sSfL -o "$RUNNER_TEMP/$f" \
"https://github.com/bytecodealliance/wasmtime/releases/download/v$v/$f"
echo "a4d6e9e3a5a60f527cf7793d674c48930c80c2e8977995b8a275cad3254b9322 $RUNNER_TEMP/$f" | sha256sum -c -
tar -xJf "$RUNNER_TEMP/$f" -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/wasmtime-v$v-x86_64-linux" >> "$GITHUB_PATH"
- name: tests/bit_identity.rs under wasmtime
working-directory: wai/wai-quantum
env:
CARGO_TARGET_WASM32_WASIP2_RUNNER: wasmtime
run: cargo test --locked --target wasm32-wasip2 --features full --test bit_identity
# The filters are module paths, so a module that is renamed or loses its tests would
# leave its filter matching nothing and the run passing; the loop fails the step
# unless every module had a test that passed.
- name: The circuit core's unit tests under wasmtime
shell: bash
working-directory: wai/wai-quantum
env:
CARGO_TARGET_WASM32_WASIP2_RUNNER: wasmtime
run: |
set -euo pipefail
mods="quantum ijson receipt_pins quantum_fabric quantum_source quantum_channel quantum_qudit quantum_receipt"
filters=()
for m in $mods; do filters+=("$m::"); done
cargo test --locked --target wasm32-wasip2 --features full --lib -- "${filters[@]}" 2>&1 \
| tee "$RUNNER_TEMP/wasip2-lib.log"
for m in $mods; do
grep -q "^test $m::.* \.\.\. ok$" "$RUNNER_TEMP/wasip2-lib.log" \
|| { echo "::error::no test of $m ran"; exit 1; }
done
# The fabric's groundwork for accelerator members (certification one case at
# a time, the fabric-v1 corpus and its pins, the 32-bit-lane words and their
# range guard, run meters, metered calibration, placement for a run and the
# fabric's fallback, the program a member runs in every planner configuration,
# the WGSL kernels' host layouts, member ids and mutants), each by name: a module
# filter is satisfied by any one test of the module, so a test dropped or
# compiled out on wasm32 would otherwise go unnoticed.
for t in quantum_fabric::tests::certification_is_certify \
quantum_fabric::tests::fxmul_wide_is_the_exact_product \
quantum_fabric::tests::apply_words_is_apply \
quantum_fabric::tests::malformed_words_are_refused \
quantum_fabric::tests::z_on_the_most_negative_lane_is_flagged \
quantum_fabric::tests::simulate_checked_is_simulate \
quantum_fabric::tests::a_rounded_product_is_never_negated \
quantum_fabric::tests::the_guard_horizon_is_pinned \
quantum_fabric::tests::valid_circuits_stay_in_lanes \
quantum_fabric::tests::fabric_corpus_starts_with_random_v1 \
quantum_fabric::tests::the_fabric_v1_corpus_of_each_gateset_is_pinned \
quantum_fabric::tests::fabric_v1_covers_every_dispatch_shape \
quantum_fabric::tests::gate_words_are_the_table \
quantum_fabric::tests::a_meter_reading_is_labelled_or_dropped \
quantum_fabric::tests::a_placement_figure_is_a_measurement_or_nothing \
quantum_fabric::tests::figures_go_on_both_members_or_neither \
quantum_fabric::tests::place_for_sends_small_runs_to_the_cpu_and_large_ones_to_the_gpu \
quantum_fabric::tests::the_fabric_falls_back_and_names_the_member_that_produced_the_result \
quantum_fabric::tests::a_metered_fabric_run_seals_its_reading \
quantum_fabric::tests::a_calibration_gives_the_cpu_reference_its_figure \
quantum_fabric::plan::tests::execute_is_the_native_simulator \
quantum_fabric::plan::tests::every_configuration_is_the_native_simulator \
quantum_fabric::plan::tests::long_circuits_tile_as_they_run_gate_by_gate \
quantum_fabric::plan::tests::tiles_are_exact_on_any_words \
quantum_fabric::plan::tests::tiles_cover_every_path \
quantum_fabric::plan::tests::the_v1_tail_phases_are_not_skipped \
quantum_fabric::plan::tests::malformed_programs_are_refused \
quantum_fabric::wgsl::tests::implementation_id_is_pinned \
quantum_fabric::wgsl::tests::gate_record_layout \
quantum_fabric::wgsl::tests::grids_cover_every_item_once \
quantum_fabric::wgsl::tests::the_index_map_is_a_bijection \
quantum_fabric::wgsl::tests::member_ids_are_pinned \
quantum_fabric::wgsl::tests::the_cpu_reference_is_placed_first_when_nothing_is_metered \
quantum_fabric::wgsl::tests::mutants_apply_once \
quantum_fabric::wgsl::tests::mutant_witnesses_exist \
quantum_fabric::wgsl::tests::placement_breaks_an_implementation_tie_by_name \
quantum_fabric::wgsl::tests::tile_implementation_id_is_pinned \
quantum_fabric::wgsl::tests::tile_records_layout \
quantum_fabric::wgsl::tests::tile_grids_cover_every_tile_once \
quantum_fabric::wgsl::tests::tile_mutants_apply_once \
quantum_fabric::wgsl::tests::tile_mutant_witnesses_exist; do
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/wasip2-lib.log" \
|| { echo "::error::$t did not run"; exit 1; }
done
# The wai package is built as one codegen unit here. Its lib target is also a cdylib,
# and the wasm linker in Rust 1.98 (LLD 22) can crash with SIGSEGV linking that cdylib:
# the linker keeps the flags of the first object that names the function table, so
# when that object names it without NO_STRIP the table is no garbage-collection root.
# Nothing the cdylib keeps calls through the table, but it does keep function
# addresses, and writing their element segment then dereferences a table that was
# never created. Which object comes first follows the hashed names of the codegen
# units, so an unrelated change to the crate, or a different checkout path, can bring
# the crash on or off. As one unit, wai's object comes first and takes function
# addresses, so it names the table with NO_STRIP. LLD 23 keeps NO_STRIP from any
# object. The units change how the crate is split for code generation, not what the
# program computes.
- name: wai_quantum_vectors verify under wasmtime
shell: bash
working-directory: wai/wai-rs
run: |
set -euo pipefail
cargo build --locked --target wasm32-wasip2 --no-default-features --features quantum --bin wai_quantum_vectors \
--config 'profile.dev.package.wai.codegen-units=1'
wasmtime run --dir ../quantum-conformance::/corpus \
target/wasm32-wasip2/debug/wai_quantum_vectors.wasm verify /corpus
# The generated v2 vocabulary (wai/vocab/v2.*) is checked as a consumer uses it:
# sample manifests, typed and untyped, WAI1 and WAI2, are expanded through the
# JSON-LD context exactly as written on the wire and validated against the SHACL
# shapes, each with the result it must give (a candidate in any place is
# rejected; a media value no revision lists is accepted). One leg: RDF tooling,
# not arithmetic. The tool versions are pinned.
vocab-shapes:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: v2 vocabulary · manifests validate as stated
runs-on: linux-arm64
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install the RDF tools
shell: bash
run: python -m pip install rdflib==7.6.0 PyLD==3.3.0 pyshacl==0.40.1
- name: Sample manifests against vocab/v2.shapes.ttl
shell: bash
run: python wai/vocab/check_shapes.py
# The corpora above are generated and verified by wai-rs, one implementation. These are
# the second implementations, written from the extension text in Python and sharing no
# code with wai-rs: claim_verify.py (every claim vector, the canonical fixture, and the
# bracket arithmetic of energy-measurement §6.2 recomputed with Python's integers),
# differential.py (both verifiers' verdicts on generated inputs the corpus does not hold,
# under a fixed seed, so a run is reproducible), jwp_verify.py (every JWP vector), and
# signer_verify.py (every key-discovery vector and the canonical fixture, with its
# verdicts required to equal wai_signer_vectors' line for line), and
# int_payload_verify.py (the integer payloads and their refusal fixtures), and
# staged_verify.py (the staged-delivery corpus), and http_verify.py (the HTTP delivery
# corpus), and quantum-conformance/tools/referee.py (both quantum-sim capabilities), and
# live_events_verify.py (the live-events corpus), and live_rooms_verify.py (the
# live-rooms corpus), and capture_take_verify.py (the capture-binding corpus), and
# live_compose_verify.py (the live-compose corpus), live_record_verify.py (the
# live-recording corpus), timed_text_verify.py (the timed-text corpus),
# live_metering_verify.py (the live-metering corpus), energy_steering_verify.py (the
# energy-steering corpus), and live_moderation_verify.py (the live-moderation corpus), and
# e2ee_verify.py (the end-to-end encrypted rooms corpus), live_watermark_verify.py (the
# forensic-watermark corpus) and live_ads_verify.py (the live-ads corpus).
# Each exits non-zero on any failure or any difference, and the step fails with it.
# One platform: what they check is the reading of the text, not the architecture.
independent-verifiers:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: independent verifiers · claims, JWP, key discovery and integer payloads (Python)
runs-on: linux-arm64
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.98.0
shell: bash
run: |
export PATH="$HOME/.cargo/bin:$PATH"
command -v rustup >/dev/null 2>&1 || \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- uses: actions/setup-python@v5
with:
python-version: '3.11'
# The verifiers check Ed25519's equation with the `cryptography` package and make the
# rest of jwp-receipts §3.1 step 3 themselves.
- name: Install the Ed25519 library
shell: bash
run: python -m pip install cryptography
# differential.py drives wai_claim_vectors' `verdicts` mode; the key-discovery
# verdicts are compared with wai_signer_vectors'.
- name: Build the corpus verifiers wai-rs ships
working-directory: wai/wai-rs
shell: bash
run: cargo build --no-default-features --features key_discovery --bin wai_claim_vectors --bin wai_jwp_vectors --bin wai_signer_vectors
# The integer payload corpus's second implementation (int-payload-conformance/README):
# it parses every payload with the extension's rules and check order, converts every
# JSON source independently and requires the committed bytes, decodes the WIV1
# keyframe-0 payloads in full to their sidecars' SHA-256, and checks every refusal
# fixture. Standard library only, so it needs nothing installed.
- name: int_payload_verify.py
working-directory: wai
shell: bash
run: python3 int-payload-conformance/int_payload_verify.py int-payload-conformance
# The staged-delivery corpus's second implementation (staged-conformance/README): it
# replays every case from its stage-0 buffers through its own reading of the
# extension (refines, WIR1, the sink's steps, holds, batches, conflicts, deadlines,
# tiers, stage hashes), decodes the WIV1 keyframe-0, PNG and FLAC bases, explodes the
# WAI2 files, and replays the schedule. Standard library only.
- name: staged_verify.py
working-directory: wai
shell: bash
run: python3 staged-conformance/staged_verify.py staged-conformance
# The HTTP delivery corpus's second implementation (http-conformance/README): the head,
# the head proof (every committed proof rebuilt from the text), response checks, plans,
# selection, the byte-range procedure and its fallback, the codecs union and floor, the
# playlists (read, rendered, held adjacent, the classical master unchanged), playlist
# receipts (WAI's strict Ed25519, _ed25519.py) and the live edge, and the adaptation policies,
# checked first against published BLAKE3 vectors, with the standard library alone;
# and the receipts, key logs, grants files and parameter sets of §8.1–§8.5, through
# http_receipts.py and the corpora's own verifiers of jwp-receipts, which need the
# `cryptography` package installed above (without it those cases fail, never skip).
# Its mutations and the differential against wai-rs run in wai-http.yml's falsify
# job.
- name: http_verify.py
working-directory: wai
shell: bash
run: python3 http-conformance/http_verify.py http-conformance
# Outside the corpus: wai_http_vectors fuzz writes seeded cases (Content-Range values,
# codecs values, #WAI-LAYER lines, manifests and their member types, encryption,
# refines, layers declared against their bases, layers over WAI2 components, objects
# past the first request through a tampering origin; playlists, adjacent pairs,
# published masters, renderings, adaptation states, the integer log and changed
# receipt files; receipt files, indexes, grants files and key logs of §8.1–§8.5,
# whose cases need the `cryptography` package installed above) with wai-rs's
# outcomes, and
# http_verify.py must give every one, a refusal by the same code. It prints each
# family's count of cases and of refusals. Two fixed seeds, so a run is reproducible.
- name: The HTTP differential outside the corpus (wai-rs against http_verify.py)
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo build --no-default-features --features http,video_manifest,key_discovery --bin wai_http_vectors)
for seed in 11 12; do
wai-rs/target/debug/wai_http_vectors fuzz http-conformance --seed "$seed" --count 400 --out "$RUNNER_TEMP/http-fuzz-$seed.json"
python3 http-conformance/http_verify.py cases "$RUNNER_TEMP/http-fuzz-$seed.json" http-conformance
done
# The staged-measurement corpus's second implementation (staged-measure-conformance/README):
# it counts every object, applies every layer from its base's stage 0, computes the quality
# integers, the output tree, the prefixes, the overhead points and the dedup totals itself,
# and requires its decode to be the fixture tool's and its figures to be goldens.json's.
# Standard library only.
- name: measure_verify.py
working-directory: wai
shell: bash
run: python3 staged-measure-conformance/measure_verify.py staged-measure-conformance
# The delivery simulator's second implementation: Appendix B from the text, every case
# of staged-measure-conformance/sim/ reproduced and its claim checked, with a
# counter-case required for each part of the stall bound a schedule can lose.
- name: sim_verify.py
working-directory: wai
shell: bash
run: python3 staged-measure-conformance/sim_verify.py staged-measure-conformance
# The simulator differentially, outside the corpus: seeded random models (a refinement
# with its own delivery timeout among them) and plans, each simulated by
# wai_stage_measure sim and by sim_verify.py, the refusal or the whole result, the
# stall bound and the longest stall equal, and every stall within the bound where it
# applies. Two fixed seeds, so a run is reproducible.
- name: sim_diff.py, wai_stage_measure against sim_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo build --no-default-features --features stage_measure --bin wai_stage_measure)
for seed in 1 2; do
python3 staged-measure-conformance/sim_diff.py wai-rs/target/debug/wai_stage_measure "$seed" 1500
done
# wai.live.events (extensions/live-events.md): the reference module's unit tests and
# tests/live_events.rs (the committed corpus regenerates byte for byte from its fixed
# seeds, wai-rs gives every vector, policy case and binding case its stated outcome,
# the corpus covers every kind and reason, and §9 lists exactly the reference's
# codes); then the corpus's second implementation, live_events_verify.py, written
# from the extension's text and sharing no code with wai-rs, which verifies the same
# cases with WAI's strict Ed25519 (claim-conformance/_ed25519.py) and BLAKE3
# (claim-conformance/_blake3.py), standard library only, run isolated (-I).
- name: live events · wai-rs and live_events_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_events --lib live_events::)
(cd wai-rs && cargo test --no-default-features --features live_events --test live_events)
python3 -I live-conformance/live_events_verify.py live-conformance/events
# wai.live.room (extensions/live-rooms.md): the reference module's unit tests and
# tests/live_room.rs (the committed corpus regenerates byte for byte from its fixed
# seeds, wai-rs gives every vector its stated outcome, every reason of §11 refuses a
# vector, and §11 lists exactly the reference's codes); then the corpus's second
# implementation, live_rooms_verify.py, written from the extension's text and sharing
# no code with wai-rs, which verifies every event with live_events_verify.py and every
# signature with WAI's strict Ed25519 (claim-conformance/_ed25519.py), standard
# library only, run isolated (-I).
- name: live rooms · wai-rs and live_rooms_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_room --lib live_room::)
(cd wai-rs && cargo test --no-default-features --features live_room --test live_room)
python3 -I live-conformance/live_rooms_verify.py live-conformance/rooms
# wai.capture.take (extensions/capture-binding.md): the reference module's unit tests,
# the output tree's (whose RFC 6962 hash and RFC 9162 consistency proofs the take tree
# reuses), and tests/capture_take.rs (the committed corpus regenerates byte for byte
# from its fixed seeds, wai-rs gives every vector its stated outcome, every reason of
# §12 appears in it, and §12 lists exactly the reference's codes); then the corpus's
# second implementation, capture_take_verify.py, written from the extension's text and
# sharing no code with wai-rs, which verifies each room with live_rooms_verify.py and
# every signature with WAI's strict Ed25519 (claim-conformance/_ed25519.py), and
# requires every mutated copy of the corpus to fail; standard library only, run
# isolated (-I).
- name: capture take · wai-rs and capture_take_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features capture_take --lib -- capture_take:: output_tree::)
(cd wai-rs && cargo test --no-default-features --features capture_take --test capture_take)
python3 -I live-conformance/capture_take_verify.py live-conformance/takes
# wai.live.compose (extensions/live-compose.md): the reference module's unit tests (the
# layout over every grid of 1 to 64 tiles stays on its canvas with no tile overlapping
# another, the fill modes, the attributes, the mixer) and tests/live_compose.rs (the
# committed corpus regenerates byte for byte from its fixed seeds, wai-rs gives every
# case its stated outcome, every reason of §10 refuses a case, and §10 lists exactly
# the reference's codes); then the corpus's second implementation,
# live_compose_verify.py, written from the extension's text and sharing no code with
# wai-rs, which verifies each room with live_rooms_verify.py, steps through its
# lifecycle replay to each instant itself, gives every layout, mix, descriptor,
# composition and receipt the same outcome rectangle for rectangle and sample for
# sample, and requires every mutated copy of the corpus to fail; standard library
# only, run isolated (-I).
- name: live compose · wai-rs and live_compose_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_compose --lib live_compose::)
(cd wai-rs && cargo test --no-default-features --features live_compose --test live_compose)
python3 -I live-conformance/live_compose_verify.py live-conformance/compose
# wai.live.recording (extensions/live-recording.md): the reference module's unit tests,
# the output tree's (whose range proofs it adds, tested against RFC 9162 §2.1.3.2's
# check), and tests/live_record.rs (the committed corpus regenerates byte for byte from
# its fixed seeds, wai-rs gives every recording and clip its stated outcome, every reason
# of §9 appears in it, every take it says it reuses is capture binding's byte for byte,
# and §9 lists exactly the reference's codes); then the corpus's second implementation,
# live_record_verify.py, written from the extension's text and sharing no code with
# wai-rs, which checks range proofs by the extension's recursion and by RFC 9162
# §2.1.3.2's own algorithm, verifies each take with capture_take_verify.py and every
# signature with WAI's strict Ed25519 (claim-conformance/_ed25519.py), and requires every
# mutated copy of the corpus to fail; standard library only, run isolated (-I).
- name: live recording · wai-rs and live_record_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_record --lib -- live_record:: output_tree::)
(cd wai-rs && cargo test --no-default-features --features live_record --test live_record)
python3 -I live-conformance/live_record_verify.py live-conformance/recordings
# wai.text.timed (extensions/timed-text.md): the reference module's unit tests (cue model,
# annotation, WebVTT, IMSC1 and its render-model bound, timelines, disclosure, and the
# 608 encoder and decoder) and tests/timed_text.rs (every file of the committed corpus,
# vectors.json and each expected .vtt, .ttml and .608.hex, regenerates byte for byte
# from its fixed seeds and no other file is there, wai-rs gives every case its stated
# outcome, the corpus covers every 608 code path, and §12 lists exactly the reference's
# codes); then the corpus's second implementation, timed_text_verify.py, written from
# the extension's text and sharing no code with wai-rs, which verifies every event with
# live_events_verify.py, writes every output byte for byte from the text, parses each
# IMSC1 document with xml.etree, and requires every mutated copy of the corpus to fail;
# standard library only, run isolated (-I).
- name: timed text · wai-rs and timed_text_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features timed_text --lib timed_text::)
(cd wai-rs && cargo test --no-default-features --features timed_text --test timed_text)
python3 -I live-conformance/timed_text_verify.py live-conformance/captions
# wai.live.metering (extensions/live-metering.md): the reference module's unit tests
# (records and ledgers round-trip, the energy rules, the size bound at its limit, a
# total of two classes told from a wrong one, funds rounding, the CMCD event-timeline
# record and the application/cmcd batch, a ledger entry's audit path) and
# tests/live_metering.rs (the committed corpus regenerates byte for byte from its fixed
# seeds and the reference relay's recorded record, wai-rs gives every vector its stated
# outcome, every reason of §9 refuses a vector, the large audience's relay record is the
# lesson's size, and §9 lists exactly the reference's codes); then the corpus's second
# implementation, live_metering_verify.py, written from the extension's text and sharing
# no code with wai-rs, which verifies each room with live_rooms_verify.py, each take with
# capture_take_verify.py and each composition receipt with live_compose_verify.py,
# recomputes every unit, total and grant's consumption itself, and requires every
# mutated copy of the corpus to fail; standard library only, run isolated (-I).
- name: live metering · wai-rs and live_metering_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_metering --lib live_metering::)
(cd wai-rs && cargo test --no-default-features --features live_metering --test live_metering)
python3 -I live-conformance/live_metering_verify.py live-conformance/metering
# wai.live.steering (extensions/energy-steering.md): the reference module's unit tests
# (policies and decisions round-trip and their rules refuse, the window, the request
# reader over HLS, DASH and CMCD, the RFC 9651 parser, exact products at their limits,
# the margin at its boundary, figures compared only within a class, and a pathway with
# no figure never placed first by its rank while one with a figure is within the
# limits) and tests/energy_steering.rs (the committed corpus regenerates byte for byte
# from its fixed seeds, wai-rs gives every request and vector its stated outcome, every
# reason of §10 refuses a vector, and §10 lists exactly the reference's codes); then the
# corpus's second implementation, energy_steering_verify.py, written from the
# extension's text and sharing no code with wai-rs, which reads the room with
# live_rooms_verify.py and the per-hop records with live_metering_verify.py, parses RFC
# 9651 itself, recomputes every report, figure, decision and manifest, and requires
# every mutated copy of the corpus to fail; standard library only, run isolated (-I).
- name: energy steering · wai-rs and energy_steering_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features energy_steering --lib energy_steering::)
(cd wai-rs && cargo test --no-default-features --features energy_steering --test energy_steering)
python3 -I live-conformance/energy_steering_verify.py live-conformance/steering
# wai.live.moderation (extensions/live-moderation.md): the reference module's unit tests
# (policies, statements and notices round-trip and their rules refuse, the export's
# strings and dates, the content types, the states that show an item) and
# tests/live_moderation.rs (every file of the committed corpus, vectors.json and each
# statement-of-reasons export, regenerates byte for byte from its fixed seeds and no
# other file is there, wai-rs gives every room, export and clip its stated outcome, and
# §10 lists exactly the reference's codes, each of which the corpus gives); then the
# corpus's second implementation, live_moderation_verify.py, written from the
# extension's text and sharing no code with wai-rs, which verifies each room with
# live_rooms_verify.py and each clip with live_record_verify.py, writes every export
# byte for byte, reads the extension's category, content-type and reason tables, and
# requires every mutated copy of the corpus to fail; standard library only, run
# isolated (-I).
- name: live moderation · wai-rs and live_moderation_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_moderation --lib live_moderation::)
(cd wai-rs && cargo test --no-default-features --features live_moderation --test live_moderation)
python3 -I live-conformance/live_moderation_verify.py live-conformance/moderation
# wai.live.ads (extensions/live-ads.md): the reference module's unit tests (policies and
# annotations round-trip and their rules refuse, a break's identity, tags, events and
# asset lists written exactly), the break form of wai.video.ssai's receipt (its JSON
# carriage, each of its rules, its strict signature, the stitched form's legacy pin
# unchanged), and tests/live_ads.rs (every file of the committed corpus, vectors.json and
# each room's HLS tags, regenerates byte for byte from its fixed seeds and no other file
# is there, wai-rs gives every room its stated outcome, and §10 lists exactly the
# reference's codes, each of which the corpus gives); then the corpus's second
# implementation, live_ads_verify.py, written from the extension's text and sharing no
# code with wai-rs, which verifies each room with live_rooms_verify.py, writes every tag,
# event and asset list byte for byte, verifies every receipt with WAI's strict Ed25519
# rule and BLAKE3 from claim-conformance, reads the extension's reason table, and
# requires every mutated copy of the corpus to fail; standard library only, run isolated
# (-I).
- name: live ads · wai-rs and live_ads_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_ads --lib live_ads::)
(cd wai-rs && cargo test --no-default-features --features live_ads --lib wai_video_ssai::)
(cd wai-rs && cargo test --no-default-features --features live_ads --test live_ads)
python3 -I live-conformance/live_ads_verify.py live-conformance/ads
# wai.live.e2ee (extensions/confidentiality.md): the corpus's second implementation,
# e2ee_verify.py, written from the extension's text and the documents it reads and
# sharing no code with the reference (joule-moq's secure_objects and joule-moq-mls,
# whose own checks run in joule-code-conformance.yml). Standard library only, run
# isolated (-I): AES, AES-GCM and RFC 9605's counter mode written from their
# specifications for test vectors only, HKDF and HMAC from the standard library,
# BLAKE3 and strict Ed25519 from claim-conformance. It checks every vector RFC 9605
# and draft-ietf-moq-secure-objects-01 publish, every record, key schedule, sealed
# object and room of vectors.json (taking each epoch's application secret as given,
# §14), and requires every mutated copy of the corpus to fail.
- name: end-to-end encrypted rooms · e2ee_verify.py
working-directory: wai
shell: bash
run: python3 -I live-conformance/e2ee_verify.py live-conformance/e2ee
# wai.live.watermark (extensions/forensic-watermark.md): the reference module's unit tests
# (the CBOR reader's deterministic-encoding rules, tokens of both COSE structures and
# every mode read and their rules refuse, a record's rules, big-endian bit addressing,
# the exact match and the binding) and tests/live_watermark.rs (vectors.json regenerates
# byte for byte from its fixed seeds and no other file is there, wai-rs gives every
# token, session list, match and disclosure its stated outcome, and §11 lists exactly the
# reference's codes, each of which the corpus gives); then the corpus's second
# implementation, live_watermark_verify.py, written from the extension's text and sharing
# no code with wai-rs, which reads rooms with live_rooms_verify.py and tokens with a CBOR
# reader of its own, requires every mutated copy of the corpus to fail, and drops each of
# its own checks in turn and requires the corpus to catch the weakened verifier; standard
# library only, run isolated (-I).
- name: forensic watermark sessions · wai-rs and live_watermark_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
(cd wai-rs && cargo test --no-default-features --features live_watermark --lib live_watermark::)
(cd wai-rs && cargo test --no-default-features --features live_watermark --test live_watermark)
python3 -I live-conformance/live_watermark_verify.py live-conformance/watermark
# The quantum corpus's second implementation (quantum-sim extension), integers only:
# it derives the circuit/1 phase table by its recurrence and the circuit2 table by an
# interval-certified procedure, and requires both literal tables and their digests,
# and the extension's Appendix B to state the same;
# rebuilds every file of both vector trees byte for byte and recomputes every manifest
# entry with its own reader, simulator, sampler and BLAKE3; refuses every reject file
# with its listed class and by the rule its name states; and requires dyadic_ladder
# to see every ±1 change of every P(k) under both tables. Standard library only, run
# isolated (-I), so no module from the working directory, the environment or the
# user's site-packages is imported.
- name: quantum referee.py
shell: bash
run: python3 -I wai/quantum-conformance/tools/referee.py wai/quantum-conformance
# chain_differential.py signs receipt chains around jwp-receipts §3 step 3 and §6.1
# (two keys, two tracks, both payloads, replays, forks, gaps, the guard and the
# freshness bound), and chain_gap_differential.py genuine chains up to 90 groups
# delivered shuffled, withheld and walked back with rewritten links and forks; both
# require wai_jwp_vectors and jwp_verify.py to give every chain the same verdict. Two
# fixed seeds each, so a run is reproducible.
- name: claim_verify.py, differential.py, jwp_verify.py, chain_differential.py, chain_gap_differential.py, signer_verify.py
working-directory: wai
shell: bash
run: |
set -euo pipefail
python3 claim-conformance/claim_verify.py claim-conformance/vectors.json
python3 claim-conformance/differential.py "$GITHUB_WORKSPACE/wai/wai-rs/target/debug/wai_claim_vectors" --random 2000 --seed 1
python3 jwp-conformance/jwp_verify.py jwp-conformance/vectors.json
for seed in 1 2; do
python3 jwp-conformance/chain_differential.py "$GITHUB_WORKSPACE/wai/wai-rs/target/debug/wai_jwp_vectors" --n 3000 --seed "$seed"
python3 jwp-conformance/chain_gap_differential.py "$GITHUB_WORKSPACE/wai/wai-rs/target/debug/wai_jwp_vectors" --n 400 --seed "$seed"
done
python3 signer-conformance/signer_verify.py signer-conformance/vectors.json
python3 signer-conformance/signer_verify.py verdicts signer-conformance/vectors.json > "$RUNNER_TEMP/signer-py.tsv"
"$GITHUB_WORKSPACE/wai/wai-rs/target/debug/wai_signer_vectors" verdicts signer-conformance/vectors.json > "$RUNNER_TEMP/signer-rs.tsv"
diff "$RUNNER_TEMP/signer-py.tsv" "$RUNNER_TEMP/signer-rs.tsv"
# Delivery telemetry's second implementation is an independent open-source CMCD and CMSD
# library at locked versions (telemetry-conformance/cml/package-lock.json). The
# differential builds each observation's report from the extension's tables, encodes it
# with the library, requires the bytes of expected/cmcd.json and expected/cmsd.json, reads
# the expected strings back as dictionary, query and header shards, and validates every
# report with no error. One platform: string encoding, not arithmetic.
telemetry-differential:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: delivery telemetry · CMCD and CMSD against an independent library
runs-on: linux-arm64
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: npm ci, then the differential
working-directory: wai/telemetry-conformance/cml
shell: bash
run: |
set -euo pipefail
npm ci --no-audit --no-fund
node differential.mjs ..
byte-exact:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: cross-arch byte-equality · ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Self-hosted fleet labels. Both architectures: x86_64 by linux, arm64
# by linux-arm64 + macos — what matters for the Fx integer floor is the
# arch, not the OS. No Intel-Mac runner exists in the fleet, and it
# would add no arch coverage anyway.
# Windows x86_64 leg removed 2026-09-30: runner offline. Restore by
# re-adding `windows` here once the runner is back online.
os: [linux, linux-arm64, macos]
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.98.0 (unix)
if: matrix.os != 'windows'
shell: bash
run: |
export PATH="$HOME/.cargo/bin:$PATH"
command -v rustup >/dev/null 2>&1 || \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Install Rust 1.98.0 (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
- name: Integer rANS + int_synth + JPEG-AI mANS goldens (one machine → every machine)
working-directory: wai/byte-exact-conformance
run: cargo test --release
# The codec wrappers are behind `codecs`, which binds C and C++ libraries that no
# container image of this fleet carries, so no other job compiles them. A feature no
# workflow enables has no CI coverage at all: without this job the wrappers' tests,
# and the limits on what a text payload may decode to (SPEC §2), pass by not running.
#
# One platform, the `macos` runner, whose host has the libraries. What the job proves
# is how the wrappers treat hostile bytes and where their limits fall, which is the
# same code on every host. A missing library fails the build step by name.
codec-wrappers:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path
runs-on: macos
steps:
- uses: actions/checkout@v5
- name: Install Rust 1.98.0
shell: bash
run: |
export PATH="$HOME/.cargo/bin:$PATH"
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# Every one of these test files is `#![cfg(feature = "codecs")]`: built without
# the feature each reports "0 passed" and exits 0. So the step names the feature,
# and then requires that each of the five binaries ran at least one test.
- name: Fuzz smoke, the text and media decode limits and the C entry points
working-directory: wai/wai-rs
shell: bash
run: |
set -o pipefail
cargo test --locked --features codecs \
--test fuzz_smoke --test text_decode_bounds --test text_decode_memory \
--test media_decode_bounds --test ffi_robustness \
2>&1 | tee "$RUNNER_TEMP/codec-wrappers.log"
ran=$(grep -cE '^test result: ok\. [1-9][0-9]* passed' "$RUNNER_TEMP/codec-wrappers.log" || true)
if [ "$ran" -ne 5 ]; then
echo "::error::expected five test binaries that each ran tests; $ran did"
exit 1
fi
# wai_prov needs `codecs`, so no other job builds it. Its --carry path writes the
# provenance asset and receipt that wai-web's reach vectors commit: carried onto
# its own receipt, a run must write both again byte for byte. A receipt changed
# by one byte must be refused, which shows the comparison is not vacuous.
- name: wai_prov carries the committed provenance receipt, byte for byte
working-directory: wai/wai-rs
shell: bash
run: |
set -euo pipefail
cargo build --locked --features provenance,codecs,receipt_claims --bin wai_prov
bin="${CARGO_TARGET_DIR:-target}/debug/wai_prov"
v=../wai-web/reach/test/vectors/provenance
"$bin" "$RUNNER_TEMP/prov" --carry "$v/captured.receipt.json"
cmp "$RUNNER_TEMP/prov/captured.jpeg.wai" "$v/captured.jpeg.wai"
cmp "$RUNNER_TEMP/prov/captured.receipt.json" "$v/captured.receipt.json"
sed 's/"encode.jpeg"/"encode.jpeh"/' "$v/captured.receipt.json" > "$RUNNER_TEMP/changed.receipt.json"
if cmp -s "$RUNNER_TEMP/changed.receipt.json" "$v/captured.receipt.json"; then
echo "::error::the changed receipt is not changed"; exit 1
fi
if "$bin" "$RUNNER_TEMP/prov-changed" --carry "$RUNNER_TEMP/changed.receipt.json"; then
echo "::error::a changed receipt was carried"; exit 1
fi
# tests/semantic_path.rs needs `semantic`, which builds on `codecs` and binds the
# ONNX runtime, so this is the one job that can run it.
- name: The semantic path
working-directory: wai/wai-rs
shell: bash
run: |
set -o pipefail
cargo test --locked --features codecs,semantic --test semantic_path 2>&1 | tee "$RUNNER_TEMP/semantic-path.log"
ran=$(grep -cE '^test result: ok\. [1-9][0-9]* passed' "$RUNNER_TEMP/semantic-path.log" || true)
if [ "$ran" -ne 1 ]; then
echo "::error::the semantic path's test binary ran no test"
exit 1
fi
# The C2PA emitter is gated behind an off-by-default feature, so the four-platform
# job above — which builds a fixed feature list — never compiles it. A feature no
# workflow enables has no CI coverage at all: the suite passes, and the tests in it
# simply do not run.
#
# One platform, deliberately. Everything the matrix above exists to prove is about
# byte-identical reconstruction across architectures; a signed manifest makes no
# such claim and would not become more true for being emitted on four machines. What
# this job proves is that the manifest is still well-formed, still carries the three
# assertions, and still validates — which is architecture-independent.
c2pa-emitter:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: C2PA manifest emission · signed, read back, validated
runs-on: linux-arm64
steps:
- uses: actions/checkout@v4
- name: Install Rust 1.98.0
shell: bash
run: |
export PATH="$HOME/.cargo/bin:$PATH"
command -v rustup >/dev/null 2>&1 || \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
rustup toolchain install 1.98.0 --profile minimal
rustup default 1.98.0
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# `rust_native_crypto` rather than the SDK's default openssl backend, so this
# job needs no system libraries — the same property the matrix above depends on.
# Asserted, not assumed: an openssl-linked build would still pass the tests here
# while quietly making the crate undistributable to a bare runner.
- name: The emitter pulls in no system crypto
working-directory: wai/wai-rs
shell: bash
run: |
for dep in openssl openssl-sys; do
if cargo tree --no-default-features --features c2pa_emit -i "$dep" >/dev/null 2>&1; then
echo "::error::$dep reached the c2pa_emit dependency graph"
exit 1
fi
done
echo "no system crypto in the graph"
- name: Emit, sign, read back, validate
working-directory: wai/wai-rs
run: cargo test --lib --no-default-features --features c2pa_emit c2pa_emit
# A room-session receipt (extensions/live-metering.md §7) in a real signed manifest:
# energy_kwh only where one class covers the session whole, the companion always.
- name: Emit a room-session receipt, sign, read back, validate
working-directory: wai/wai-rs
run: cargo test --lib --no-default-features --features c2pa_emit,live_metering c2pa_emit::tests::a_session
# The feature must stay optional. If `provenance` ever pulls c2pa in, every
# consumer that wanted only the binding types inherits a large dependency tree
# they did not ask for, and the "off by default" claim in the extension is false.
- name: The feature stays optional
working-directory: wai/wai-rs
shell: bash
run: |
if cargo tree --no-default-features --features provenance -i c2pa >/dev/null 2>&1; then
echo "::error::c2pa is reachable from the provenance feature; it must stay opt-in"
exit 1
fi
cargo build --no-default-features --features provenance
echo "provenance builds without c2pa"