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