open-standards/wai/pack-conformance/README.md
Transaction Science 26ca4d7877 wai-pack golden: a reseal that fails its CMAF check says so (#426 review S6)
#426 review S6. reseal_as swallowed cmaf_supplied's error, so the
`segment-not-the-supplied-one` vector silently lost its `hi` floor: its catalogs
listed `lo` only and its overlay removed hls/classic/floor-hi.m3u8, three faults
where its README describes one. reseal_as now propagates the error, and the mutation
reseals through reseal_renamed, which renders the catalogs naming the replacement
segment, so the one fault is the segment's binding to `floor.listing`. The corpus is
regenerated in a later commit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 21:06:25 -04:00

275 lines
19 KiB
Markdown
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.

# pack-conformance — the packaging corpus
Vectors for [`extensions/packaging.md`](../extensions/packaging.md): the policy, its
digest and what it may ask a packager to emit (§3), how a source is cut into pieces
(§4), the integer video payloads, refinement layers and stills a packager writes (§5),
packages (§6–§11), and their delivery over a simulated link (§8.9).
**Provenance.** Generated here: the `wai-pack` fixture generator (`wai-pack/src/fixture.rs`, `wai-pack/src/conformance.rs`) writes every frame from integer functions of the frame and pixel index; a package's bases, refinement layers and stills are codings of those frames, and its floor an AV1 coding of them by an encoder, as `supplied_floor.py` states. No footage.
- `policy/` — policies a packager accepts (every rung one it may emit, §3.6), and
`expected.json`: each policy's effective canonical JSON and
digest (`eq-defaults-a.toml` also with `royalty_free_only` forced on, the one way an
override changes it, §3.2), and the
pairs `eq-<name>-a.toml` and `eq-<name>-b.toml`, two spellings of one policy that
must have one digest: every default omitted or written out; standard or inline
tables, dotted keys, member order, string escapes, integer notation and comments;
and `max-piece.toml`, the longest piece a policy may allow (§4.4), at both bounds.
- `refusals/` — `policy/*.toml`, one fault each (the byte layer's among them: a
byte-order mark, bytes that are not UTF-8, an integer at 2^63, nesting to depth 33 and
80), and `source/*` (Y4M and WAV), and `expected.json`: each one's reason (§12). Every
file is read as bytes. A policy's reason is a packager's: the
policy's own (§3.2–§3.4), or its first rung's capability refusal (§3.6), read from
SPEC §5's registry. The source files are written by the generator.
- `conversions.json` and `conversions/` — milliseconds to a timebase (§4.4), a lead
start to a component's timebase (§4.5), and Y4M to RGB8 (§4.7) by the SHA-256 of each
frame, for 4:2:0 with odd dimensions and for 4:4:4. The Y4M files are written by the
generator.
- `scenecut/` — `policy.toml` and `expected.json`: for each fixture, its SHA-256, the
score of every frame, every piece (start, frames, flags, kind, and the statistics the
kind is read from) and the plan digest (§4.2–§4.6).
- `encode/` — `WIV1` payloads of the integer video encoder (§5.5; `wai-rs`
`int_video_enc`), written by the generator, and `expected.json`: one for every piece
of every fixture, coding the piece's first 12 frames, under a whole-pel and a
half-pel parameter set; for each, the encoder's parameters, the payload's BLAKE3,
the SSE of its reconstruction against the source, and the SHA-256 of every decoded
frame. Identical content gives identical bytes: `kinds-01`'s pieces 4 and 5 both
start inside one static shot, so their first frames, and their payloads, are the
same.
- `qchoice/expected.json` — the step the base encode chooses (§5.6) for every piece of
every fixture (its first 12 frames), under two bounds: each candidate's SSE and SSE
per sample in thousandths, the step chosen, and the chosen payload's BLAKE3.
- `packs/video-base-01/` — a golden package (§5–§11). Its inputs: `policy.toml`, the
supplied floor `floor/v.obu` (an AV1 stream with a key frame at each piece start of
the plan, each piece coded alone, written by an AV1 encoder from the fixture; the
policy pins its listing), and `key.hex` (a test signing seed, never a production
key). `package/` is every file the packer writes from them and the fixture
`video-base-01`: objects, the stage index, the floor's objects and CMAF files, the
catalogs, the receipt and `LISTING`. The fixture's bumper plays twice, so its pieces
are one object each time.
- `packs/video-staged-01/` — a staged golden package (§5.4, §5.7): a moving shot, the
bumper, a still shot, the bumper again and a second moving shot, under a policy of an
`int_motion` base with two `int_refine` layers, a still for a static piece (a rule's
ladder), three classes (one capped by rate, one floor only), a moment whose rule
moves the last piece's layers to an 800 ms deadline, and layer lags. Its floor was
written by `supplied_floor.py`. The bumper's base, layers and floor are one object
each; the still's piece is carried over HTTP by the floor (§8.3) and over MoQ on the
base track.
- `packs/video-ladder-01/` — a golden package of two floor rungs over one base (§7.1):
the fixture and base rung of `video-base-01`, so its bases are that package's objects,
and two supplied AV1 streams, `floor/hi.obu` at the fixture's size and `floor/lo.obu`
at half its width and height, each written by `supplied_floor.py` (`--scale lo=2`).
Each piece has its base and one floor object per floor rung; each floor has its own
CMAF files under its floor name (`floor/hi/`, `floor/lo/`), its own floor playlist and
MoQ track, and the classical master, every class's master and `dash/classic.mpd` list
both.
- `packs/video-repack-01/` — a re-pack golden (§11.5): `video-ladder-01`'s policy under
another asset id and its supplied floor, packed with every piece's base taken from the
parent its file `parent` names, `video-base-01`, rather than coded. Its objects are
`video-ladder-01`'s; its receipt names `video-base-01`'s receipt as the package it
re-packs (parent kind `re-pack`); and each piece's base entry is the parent's, field for
field. Both verifiers check it against its parent.
- `packs/video-cmaf-01/` — a golden whose supplied floor is in the CMAF form (§7.7):
`video-ladder-01`'s policy with `floor.supplied_form = "cmaf"`, and its two streams as a
media muxer wrote them, `floor/<name>/init.mp4` and `floor/<name>/seg_<k>.m4s`, one
segment per piece, by `supplied_cmaf.py` (ffmpeg's HLS muxer, `-c copy`). The package's
floor files are those files, byte for byte, under their SHA-256; `floor.listing` is the
supplied floor's listing; and each floor object holds its piece's samples, which are the
OBU form's temporal units of the same streams.
- `cmaf-mutations/` — the CMAF golden altered, in `package-mutations/`'s layout: itself
(`ok`); a segment replaced by one of the same samples, a `free` box before it, under its
own SHA-256, which the catalogs name, so its one fault is its binding to `floor.listing`;
`floor.listing` altered; and without it (each `floor-cmaf-mismatch`).
- `packs/video-floor-only-01/` and `packs/video-floor-only-02/` — floor-only goldens
(§7.8): a component of `profile = "floor-only"` with the ladder's two floor rungs and no
base or source, the floor in the CMAF form (`video-cmaf-01`'s files) and in the OBU form
(`video-ladder-01`'s streams). Their pieces are the first floor's segments or shown key
frames, the ladder golden's plan; each piece is its two floor objects, which carry no
`derived_from` and hold the ladder golden's units, of kind `none`; no class lists a WAI
object.
- `ladder-mutations/` — packages a verifier must refuse or accept (§11.3), each the
ladder golden altered (re-sealed with its key where the receipt or `LISTING` alone
would catch it), in `package-mutations/`'s layout: the golden itself (`ok`); piece 2's
two floor objects swapped (`floor-object-mismatch`); the second floor's CMAF files
under the component's name (`floor-cmaf-mismatch`); and a classical master listing one
floor of two (`catalog-mismatch`).
- `mutations/` — stage indexes, objects and version-2 receipts, and `expected.json`:
each case's reason (§6.2–§6.4, §9.1), a well-formed case of each kind among them,
and three receipts carrying a signature only a verifier that checks the equation
alone accepts (a key of small order, that key spelled with y = p + 1, an R of small
order), each `receipt-signature` (SPEC §7 *Signatures*).
- `receipts/` — version-1 package receipts as JSON (§9.3), with each one's receipt
hash: the legacy receipt whose hash `wai-rs` pins, an unmetered one, and the
unmetered one carrying each of those three signatures, marked
`"signature": "refused"`.
- `catalogs/` — stage indexes no golden package has (refinements on more than one
deadline), with the MoQ catalog each gives (§8.4).
- `live/` — the staged golden's source packed live (§9.2) with its key, in windows of
two pieces: each window's stage index and receipt (`windows/<n>/`), and
`expected.json`: each window's first piece and entry, its pieces, its index digest and
its receipt hash. Each window verifies against its receipt; the first starts the
chain, and each later one names the receipt before it as its `live-window` parent,
the index before it as its `prev_index_digest`, and continues its pieces and entries.
Its pieces, bases and refinements are the golden's, entry for entry (a live pack has
no floor).
- `stills/` — PNG files a still's reader reads or refuses (§5.7: any PNG of 8-bit RGB
without interlace), each a generated 5 × 3 picture written chunk by chunk, and
`expected.json`: each file's verdict and, read, the SHA-256 of its RGB8 samples. Read:
the module's own still, and files with a suggested palette, ancillary chunks, and the
image data split across two chunks. Refused: an interlace, bytes after `IEND`, a short
row, a palette after the image data, an unknown critical chunk, no `IEND`, a chunk
between the image data, a chunk's CRC, a sixth filter, another colour type, a zlib
window past 32 KiB, bytes after the zlib stream, and its Adler-32. And one dynamic
block of literals twice: with a lone distance code of one bit, read (the one
incomplete code set the zlib library takes), and of two bits, refused.
- `staged-mutations/` — the staged golden itself (`ok`: verified without its sources,
every layer's prefix digest held to it), and the staged golden altered and re-sealed
with its key, in the
layout of `package-mutations/`: a refinement on another deadline than its plan's, a
piece missing its top layer, a still where the policy's rule now gives the piece the
default ladder (each `index-policy-mismatch`), a top layer coded again at another step
and a still's digest of its one frame rather than its frame held for the piece (each
`prefix-digest`), and a piece and a still each longer than the policy's `max_ms`
(`index-policy-mismatch`, refused before a frame is decoded, so a still's declared
duration never sets what a verifier allocates); a policy past §4.4's longest piece
(`max_ms` 600001, `policy-piece-bounds`); and the still given the longest piece a
policy allows (`max_ms` ten minutes), its manifest naming those frames, refused by its
floor's unit count before any frame is decoded (`floor-object-mismatch`); a still
whose manifest's `target` holds a member more, and a top layer whose `target` is not
null (each `object-manifest`); and the still as a PNG §5.7 does not read, its one
dynamic block's lone distance code two bits long (`prefix-digest`).
- `delivery/` — `expected.json`: the staged golden packed live and delivered to a `tv`
subscriber over a simulated link (§8.9), under §8.5's priorities, without them, and
capped at layer 1: each piece's presented layer, base arrival and dropped layers, and
the byte counts. Labelled simulated.
- `package-mutations/` — packages a verifier must refuse (§11.3), each the golden
altered and, where the receipt or `LISTING` alone would catch the alteration,
re-sealed with the golden's key: what a dishonest packager holding the key could
publish. Each is an overlay on the golden (`<name>/`, the files that differ or are
new; `expected.json`, the files it removes, the directories it adds that hold
nothing or cannot be read, and its reason), written out as a directory and read
strictly by each verifier: a receipt over no component, an index that is not its
policy's, the policy's own refusals (a `policy.json` that turns `royalty_free_only`
off among them), a missing or corrupted object, a live window no catalog can be
written for, floor objects that do not open on a key frame or are not §7.2's, files
and directories a strict read finds, and a receipt file that is not its canonical
form; and those the verifier must accept (an extra key frame the policy allows, and a
metered package, §9.4: the golden re-sealed with a 500 mW model meter over one second
and its measurement claim, every member fixed), with a claim about another figure
(`measurement-claim-invalid`) and none (`measurement-claim-missing`).
The fixtures are not committed. `wai-pack fixture gen <name>` writes each from its
definition (`wai-pack/src/fixture.rs`), every byte an integer function of the frame
index and the pixel position, and the corpus pins its SHA-256:
- `cuts-01` — hard cuts; a flash exactly as long as the lookahead, which is not cut;
a fade, which is not cut; and two shots cut against each other, each return a cut.
- `kinds-01` — one shot of each kind, then a static shot longer than the longest
piece, cut where `max` forces it.
- `video-base-01` — 64 × 36: three shots with a one-second bumper between them, the
bumper the same frames both times (its span reads time from its own start).
- `video-staged-01` — 64 × 36: a moving shot, the bumper, a shot that does not change,
the bumper again, and a second moving shot.
Files are compared as bytes; `.gitattributes` turns off line-ending conversion.
**Generation.**
cd wai/wai-pack
cargo run --release -- conformance regen ../pack-conformance
**Verifiers.**
- `wai-pack conformance check ../pack-conformance` recomputes every expected file and
every generated input and requires them to equal the committed ones, requires the
digests of each equal pair to be equal, decodes every encode payload through
`decode_int` to the encoder's reconstruction and recomputes its SSE. It packs each
golden again and compares every file, verifies the committed package
(`wai-pack verify`), gives every mutation and every package mutation its
reason, reads every still to its verdict, and checks the live windows' chain.
`cargo test`
runs the same check, with the scene cuts of each fixture stated as tests
(`tests/scenecut.rs`).
- `pack_verify.py`, Python standard library and, to sign what it re-derives, `cryptography` (TOML through `tomllib`, so 3.11 or
later) and sharing no code with wai-pack, written from the extension: its own policy
schema, constraints, canonical JSON and digest; its own Y4M and WAV readers; the
fixtures regenerated from their definition; `wai.pack.scenecut/1` in its on-demand
form, every frame known, against the vectors of the streaming segmenter; the
capability rules from the registry's published export
(`../registry/capabilities.json`); and every encode payload decoded to its frames'
SHA-256, with its SSE recomputed from the regenerated source. BLAKE3 comes from
`../claim-conformance/_blake3.py`, and the `WIV1` parser and decoder from
`../int-payload-conformance/int_payload_verify.py`. For the packages it has its own
stage index reader and rules, object rules (each payload parsed as its pinned format,
a `WIR1` reader included), version-1 and version-2 receipts (Ed25519 by WAI's strict
rule, SPEC §7 *Signatures*, from `../claim-conformance/_ed25519.py`), an AV1 stream
and sequence header reader, the CMAF files, and every catalog: it verifies each golden
package in §11.3's order, rebuilding the floor's files and re-rendering the catalogs
byte for byte, gives every mutation its reason, checks the version-1 receipts, and
verifies every package mutation and staged mutation in the same order, refused with
its reason. Every prefix is decoded: a still by its own PNG reader, and each refinement
layer by the `WIR1` decoder of `../staged-conformance/staged_verify.py` (written from
staged-delivery); and the MoQ catalog is checked by that file's moq-streaming-format
§4.1 check. Every HTTP playlist of a golden is read by
`../http-conformance/http_verify.py`'s union, floor and adjacency checks
(http-delivery §4.2), and every file of `stills/` by its own PNG reader, to the
corpus's verdict. Each window of `live/` it reads as an index and a receipt, checks
the chain, and compares with the golden's index. From the regenerated fixture it re-derives what only the source decides:
the pieces, their rules, moments, ladders and class plan, each base's SSE and step and
the encoder's choices, each still's bytes, and each refinement layer's bytes with its
own rANS coder and table fit; and it checks the supplied floor against the policy's
listing and the plan. The delivery cases it re-derives from the fixture's cut and the
package's index by its own mapping onto the simulator of
`../staged-measure-conformance/sim_verify.py`.
python3 pack-conformance/pack_verify.py pack-conformance
- `policy_diff.py` runs the policy reader differentially: byte-level cases (a
byte-order mark, bytes that are not UTF-8, integers past 2^53 and 2^63, nesting at
and past the cap, control characters, line endings) and seeded random policies with
faults in every table, each one's verdict and digest from `wai-pack policy-verdict`
equal to `pack_verify.py`'s.
python3 pack-conformance/policy_diff.py <wai-pack binary> 1 3000
- `segment_diff.py` runs `wai.pack.scenecut/1` differentially: seeded random clips
under random parameters, every piece and score of the streaming segmenter
(`wai-pack segment-json`) equal to `pack_verify.py`'s on-demand form, and every piece
within `min` and `max`.
python3 pack-conformance/segment_diff.py <wai-pack binary> 1 2000
- `stage_diff.py` runs the staged packer differentially: refinement layers over random
frames and steps, stills of random pictures, piece plans under random policies (rules
with ladder subsets, maximum layers and deadlines, classes with rates, layer lags) and
deliveries of random publications over random links, each result of
`wai-pack stage-json` equal to `pack_verify.py`'s.
python3 pack-conformance/stage_diff.py <wai-pack binary> 1 3000
- `png_diff.py` runs a still's reader differentially: streams the zlib library writes
(every level and strategy, windows from 512 bytes to 32 KiB) and the packager's own
stills; dynamic blocks built on each of RFC 1951's and zlib's code-set rules (complete
codes, no distance code, a lone one-bit distance code used and misused, a lone longer
one, over-subscribed and incomplete codes of each kind, repeats with nothing before
them or past the code lengths, no end-of-block code, too many symbols, a distance past
the bytes written, stored blocks with a wrong complement, fixed blocks with symbols
they cannot use, several blocks of mixed kinds); and those altered. Each verdict, and
each read picture's SHA-256, from `wai-pack stage-json`'s `read-png` must be
`pack_verify.py`'s, which inflates with Python's zlib; and each construction must have
the verdict the rules give it.
python3 pack-conformance/png_diff.py <wai-pack binary> 1 4000
- `supplied_floor.py` is how a golden's supplied floor was written (an AV1 encoder over
each piece of the generated fixture, the policy's listing set to it); it is not a step
of verification, since an encoder's output is pinned by the listing, not re-derived.
- `source_diff.py` runs the source readers differentially: seeded Y4M and WAV
mutations (dimensions and channel counts at and past their range, every format
field, truncations, single-byte changes), each file's verdict from
`wai-pack source-verdict` equal to `pack_verify.py`'s, and no reader panicking.
python3 pack-conformance/source_diff.py <wai-pack binary> 1 3000