open-standards/wai/staged-conformance
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Transaction Science 55df2cdc2c wai: the Python verifiers check their manifest reader limit in memory
In staged_verify, claim_verify and pack_verify the man_len check is
outcome-neutral for any input under 128 MiB: the bounds check after it
refuses the same bytes. No corpus file is that large, so nothing exercised
it. Each verifier now builds, in memory, a WAI1 and a WAI2 (claim_verify:
the WAI2 its wai2_read reads) whose manifest is padded to 2^27 + 1 bytes
by a member no revision defines, and requires it refused, and requires the
same envelope with a 300-byte manifest read, so only the limit tells the
two apart. pack_verify builds its own envelopes, as it shares no code.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 17:03:13 -04:00
..
cases wai: stage explode gates on capability; the §4.1 sentence scoped; the caller-offers case named 2026-10-08 01:27:23 -04:00
moq wai, joule-moq: the MoQ trace fills a gap — the lossy subscriber fetches what its re-anchor skipped (round 4, item 3) 2026-10-06 12:57:41 -04:00
wai2 wai: the staged corpus covers each rule it was missing 2026-10-04 20:17:56 -04:00
.gitattributes wai: the staged-delivery corpus and its independent verifier 2026-10-02 00:27:50 -04:00
index.json wai: stage explode gates on capability; the §4.1 sentence scoped; the caller-offers case named 2026-10-08 01:27:23 -04:00
rate_port.json wai: the layered-PCM port vectors — rate_port.json and test 15 2026-10-06 09:18:45 -04:00
README.md wai: stage explode gates on capability; the §4.1 sentence scoped; the caller-offers case named 2026-10-08 01:27:23 -04:00
schedule.json wai: the staged-delivery corpus and its independent verifier 2026-10-02 00:27:50 -04:00
staged_verify.py wai: the Python verifiers check their manifest reader limit in memory 2026-10-09 17:03:13 -04:00

staged-conformance — staged delivery

The corpus of extensions/staged-delivery.md §12: stage sets of a base and refinement layers, and the steps a sink takes with them.

Stage-equivalence. For each case, a conforming sink that offers its layers, decodes its bases and expires its holds in the order and at the times case.json states reports, at every step, the reasons the case states per envelope and per unit, and ends with every unit at the stated stage, producer, frozen flag, tier, shape and stage hash (SHA-256 of the unit's canonical buffer, SPEC §7 Digests; stated only where the unit holds decode-equivalence). The reasons are §4.2's; a payload-malformed report names the WIR1 code (Appendix A.6), and a cost-over-limit report the figure past the limit (output bytes, symbols or working bytes). A step reports once per envelope it decided: what was refused for the whole envelope, or per unit what was applied, held and refused (a unit held and decided within the same step is reported by its decision); held_for_base marks an envelope held for a base the sink has not decoded. The order of a step's reports is not part of the outcome.

Offers. A case's offer step hands its envelope to §4 as a layer, as a caller of a sink's offer does. A sink routes an envelope by its capability (§3), so it never offers one whose capability is not refinement-only: the case capability_not_refinement tests that caller-offers path, which §4.1 step 1 refuses (capability-not-refinement).

Evidence. Each offer states what the sink verified of the layer's delivery receipt (§10.1), as a token: delivered-verified, a receipt verified through jwp-receipts §3 step 6 over the envelope's bytes as received; inclusion-verified, a receipt verified without those bytes (jwp-receipts §3, Verified by inclusion: steps 1, 2, 3 and 5), which never authorizes an application; none, no receipt verified. The same tokens are a stage claim's evidence (jwp-receipts §2.4.10), and jwp_delivery::Evidence converts into them. A base's attested states whether the sink verified a receipt for it, so that step 5 requires delivered-verified of its layers.

  • cases/<name>/ — one case: case.json, each base's envelope (base*.wai) and its stage-0 output (stage0*.bin: the units' canonical buffers concatenated, in unit order), and the layers (*.wai). case.json states each base's capability it was decoded through, whether through a fallback, whether the sink verified a delivery receipt for it, whether its pin resolved, its tier, its units and the live clock position of its first unit (first_unit, §8); the sink's hold bound, cost limit, chain budget (§4.5), record budget (§4.4) and live schedule; the steps (offer, decode a base, expire, drop a base's chain, attest a base); and what the sink reports and holds.
  • wai2/ — WAI2 envelopes with refinement components (SPEC §7.1) and index.json, which states for each what check_component_roles reports, whether each envelope_manifest matches its entry, the content hash of each component's exploded envelope (null for an entry that cannot be exploded, the others exploded all the same), and entry 0's refinements: a live-style chain packed with its manifests verbatim, which explodes back to its sources (*.src<i>.wai) byte for byte; an envelope written with ids and no envelope_manifest; a refinement whose payload does not match its sha256; an envelope_manifest that does not match its entry, and one that names a fallback; each refinement rule of SPEC §7.1 broken once. Its packs list gives WAI1 envelopes and whether a packer packs them: bytes before or after a manifest's JSON value, bytes after a payload, and a manifest that inside a WAI2 entry passes the JSON depth limit are refused.
  • schedule.json — arrival traces, and the unit-by-unit presentation and stage a sink gives each (§8), with the count of units presented below the stage their layers would have reached on time.
  • moq/ — the carriage of a stage set over MoQ (moq-streaming-format §4.1). catalog.json is the MSF catalog of a live set: its base track, two layer tracks and the receipts track. catalogs.json holds catalogs around §4.1's check — each rule broken alone, two faults, an entry with no readable set, two sets, MSF delta updates (a clone of a layer, refused unless it overrides its alias and receipts track), conversion to on demand, and tracks that inherit the catalog track's namespace, checked under that namespace, under another and with none known — and, given the catalog track's namespace each case states, for each set the first rule it fails. trace.json carries the envelopes of cases/video_int_motion_gop_perframe/ on those tracks, one object to a group (object 0, which each receipt names), through one relay to four subscribers: one of every track; one of the base and layer 1 tracks only; one of those two whose relay drops the receipts-track object of layer 1's group 6, and which fetches the groups a re-anchor skips; and one of every track that joins after GOP 0. Each states the bound its verifier holds receipts under. It states each object's publication, its time upstream, queued at the relay and downstream, and the OBJECT_DELIVERY_TIMEOUT its publisher sets (its slack to the last unit it covers). The relay drops an object whose queue time passes its timeout, which MOQT starts when the object reaches the relay, and its receipts still arrive on the receipts track; the layer 2 of two GOPs is dropped, and frame 5's layer 1, queued within its timeout after a slow upstream path, arrives after its deadline. Its receipt took the same slow path, and a track's receipts are one chain (jwp-receipts §3 step 3), so frames 6 and 7's layers wait for it before they are verified. Where group 6's receipt is lost, groups 7 and 8 are held until holding group 9 would pass the bound of 2: they are refused and the chain re-anchors at 9. The subscriber fetches the receipts of 6 to 8, which arrive in ascending order 40 ms later and fill the gap as history, each linking forward from the one before: 6's layer is then late, 7's and 8's are in time and applied; 9 to 11 are verified. The joiner anchors each chain at its first receipt. expect gives, for each subscriber, each object's fate and when its receipt was verified or refused, the steps its sink takes (as a case's, the base attested and each layer offered once the sink has it and its receipt is settled), the sink's reports and final units, the stage presented at each clock position of the bases it received, the deadline misses and the status and evidence a stage claim gives each layer object; and the relay's counts of objects dropped and of receipts forwarded for them, over every subscriber. joule-moq's relay runs the same trace (joule-code/joule-code-rs/crates/joule-moq/tests/staged_moq_trace.rs), and wai-rs/tests/staged_moq.rs runs it with signed receipts and claims.
  • rate_port.json — the rate predictor of wai.audio.int_refine (Appendix A.4), rdiv(a·num + (b − a)·ρ, num), beside the f64 linear interpolation of the layered-PCM ladder idea it replaces: src = (i·den)/num, lo = ⌊src⌋, frac = src − lo, hi = min(lo + 1, n − 1), a + (b − a)·frac rounded half away from zero, written from that description. On integer fixtures (a sine by Bhaskara I's rational approximation, a triangle, full-scale steps), mono and stereo, at seven ratios up and down, it states the SHA-256 of the integer predictions and every sample where the two differ. They agree wherever the phase (i·den mod num)/num is a dyadic fraction, so that the f64 form is exact; they differ only where it is not, by the f64 form's rounding near a half.
  • index.json — the cases and their final clip hashes.

Provenance. Generated here: pictures, frames and PCM computed by integer functions in the generator. The bases of the integer codecs are the committed vectors under ../wai-rs/tests/vectors/, each generated too (that directory's README states how), decoded against their parameter sets with their pins; the wai.video.int_motion bases are coded by the library's keyframe-0 reference encoder (int_payload::encode_wiv1_zero_motion, which wai stage base also runs: zero motion, one block per frame), and the PNG and FLAC bases are written by small writers in the generator (stored deflate with the five row filters; VERBATIM subframes).

What checks each base's stage 0.

base checked by
wai.video.int_motion (WIV1, keyframe 0) wai_staged_vectors verify (the reference decode) and staged_verify.py (an independent decode)
wai.image.png staged_verify.py (zlib and the row filters); a fixture to wai_staged_vectors, which builds without codecs
wai.audio.flac staged_verify.py (VERBATIM subframes, both CRCs); a fixture to wai_staged_vectors
wai.neural.int_hyper, wai.video.int_hyper (keyframe 1), wai.audio.int_codec, wai.splat.int_codec wai_staged_vectors verify (the reference decode, pinned). Each base's payload is a committed vector's bitstream under ../wai-rs/tests/vectors/, and staged_verify.py, which has no decoder for these, checks stage0.bin against the decoded output that vector's sha256.json states (int_hyper/tiny, int_video/video_nk frame by frame, int_audio/audio, int_splat/splat); int_kernels_vectors checks those sidecars against the decoders. The cross-architecture goldens of ../byte-exact-conformance/ also hold the int_hyper image's stage 0

Every layer application, in every case, is checked by both.

Verifiers.

  • wai_staged_vectors verify . (from ../wai-rs, features staged,video_int,audio_int,splat_int): regenerates every file and requires it byte for byte, replays every case through staged::StageSink, decodes the bases it can and checks their tiers, replays the schedule, and checks moq/ from its committed inputs. rate_port.json is checked by regeneration and by the library test staged::tests::rate_matches_ported_reference_where_exact. wai_staged_vectors gen . writes the corpus.
  • staged_verify.py .: pure Python with the standard library, sharing no code with wai-rs. It reimplements, from the extension and SPEC: a strict reader of envelope JSON (UTF-8 with no byte-order mark, no member named twice, no NaN or Infinity, no number past the float range, no lone surrogate, the depth limit, -0, a fraction or an exponent as no integer) with the members SPEC §3 and §7.1 require; the content hash; refines; WIR1 (its parse in order, its cost, its streams, the three predictors and rdiv); the sink as §4 states it, each envelope through §4.1's numbered steps in turn, batches as §4.4 forms them, holds and their bound, frozen units, the chain budget, live deadlines on one saturating clock across bases, and receipt evidence; tiers and stage hashes; the PNG and FLAC decodes; the schedule; exploding a WAI2 component (reading the manifest's members as the text they are) with the refinement role rules; what a packer refuses; rate_port.json, from its own integer predictor and its own f64 form; and moq/: the catalog check, each timeout as its slack, the priorities, each object's fate at the relay, and each subscriber's steps replayed through its sink. It takes BLAKE3 from ../claim-conformance/_blake3.py and the rANS decoder and the WIV1 keyframe-0 decode from ../int-payload-conformance/int_payload_verify.py, both written from their specifications.