Loading…
Reference in a new issue
No description provided.
Delete branch "wai/inspect-carousel-holdings-b"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This one pull request replaces #604 and #605. Each of them was green apart from one check that this change does not touch: #604 failed the GPU energy test (it fails when other processes on the shared runner host drop GPU clients) and #605 failed the co-watch browser scenario (a room page bug); both are fixed on a separate branch whose PR follows. They could not both merge, because each adds an entry at the head of
wai/CHANGELOG.md, so whichever landed second would conflict. Here they sit in one linear branch on current main, in order: #604's two commits, then #605's six, unchanged.How this branch was built.
git cherry-pickof #604's commits (2729806f6) and then #605's (c303cf55d) onto mainc5c418e33. The only conflicts were at the head ofwai/CHANGELOG.md, resolved by keeping every entry. Every file other thanwai/CHANGELOG.mdis byte-identical togit merge-treeof main, #604 and #605, and the CHANGELOG only gains lines (+193, none removed), each entry once.check-wai-section-refs.py,check-spec-refs.pyandcheck-tests-in-ci.pypass on the combined tree.Part 1, from #604: live-contribution: the link record's magic is WLK1, no longer the clip record's WCL1
The contribution link record and the live-recording clip record both began with the 4-byte magic
WCL1. The clip record had it first (live-recording §5.1, 2026-10-17, and the onlyWCL1row in the registry); the link record took the same bytes when live-contribution was added (2026-10-25). A reader that tells records apart by their magic could not tell one from the other.This gives the later one, the link record, its own magic,
WLK1.WCL1stays the clip record's.WLK1collides with no magic in REGISTRY.md, in the code or texts of origin/main, or in any open PR's branch.Wire change. A link record written before this change is refused as
malformedby a reader of this revision (live-contribution §6.5 step 2), and a new one by a reader of the earlier revision. The signature's domain (wai:contrib-link0x01) and every other field are unchanged.What changed:
wai/extensions/live-contribution.md: the header and §6.2 nameWLK1. §6.5 step 2 says the clip record'sWCL1is one of the other magics refused asmalformed. SPEC.md's summary namesWLK1.wai/wai-rs/src/codecs/registry.rs: a wire rowWLK1, magic, live-contribution §6.2. REGISTRY.md andwai/registry/are regenerated from it bywai registry export.joule-moq-ingest:linkrec::MAGICisWLK1, and the doc comments, README and example config say so. The generator writes.wlk1files and addsclip_record_magic, a part that bears the clip record's magic and is refusedmalformed.wai/live-conformance/links/: regenerated byte for byte byjoule-moq-ingest-link-vectors --outon the build host. The.wcl1files are replaced by.wlk1ones, and the README is updated.wai/live-conformance/live_contribution_verify.py: readsWLK1. It also mutates each accepted part to the clip record's magic and requires that copy to be refused.wai/CHANGELOG.mdhas an entry under Unreleased that calls this a wire change and acknowledges each corpus findingwai breakingreports.joule-code/CHANGELOG.mdhas a matching entry forjoule-moq-ingest.The reverse direction (second commit): a record with the link record's magic is not a clip record.
wai/wai-rs/src/live_record/corpus.rs: the live-recording corpus gains the cliplink_record_magic, chunk 4's clip record beginningWLK1and signed under it, so the magic is its one defect. It is refusedmalformedat the clip.wai/live-conformance/recordings/vectors.jsonwas regenerated byte for byte bywai_live_record_vectors genon the build host; the only change is that vector, appended.wai/extensions/live-recording.md§5.2 namesWLK1among the other magics a clip reader refuses asmalformed. The recordings README lists the new vector.wai/live-conformance/live_record_verify.py: reads the clip record's magic from a constant, and requires that a copy of each accepted clip (9 of them) givenWLK1is refusedmalformedat the clip, so a verifier that reads past the magic to the signature fails.wai/CHANGELOG.md: a bullet in theWLK1entry.A falsification run on the build host used a copy of
live_record_verify.pywhose clip reader skips the magic. It failed, exit 1: it acceptedlink_record_magicand failed the new check.Run on the macOS build host at the first commit, each exiting 0:
cargo run --locked -q -p joule-moq-ingest --bin joule-moq-ingest-link-vectors -- --check ../../wai/live-conformance/links(102 files, byte for byte)cargo test --locked -p joule-moq-ingest --lib --test link_corpuspython3 -I live-conformance/live_contribution_verify.py live-conformance/linkscargo run -q --no-default-features --bin wai -- registry export --checkcargo test -q --no-default-features --lib codecs::registrywai breaking --against origin/main --text --all: no unacknowledged breaking changeRun on the macOS build host at the second commit (
2729806f6), each exiting 0:cargo run --locked -q --no-default-features --features live_record --bin wai_live_record_vectors -- verify ../live-conformance/recordings(regenerates byte for byte; every vector gets its outcome)cargo test --locked -q --no-default-features --features live_record --lib -- live_record:: output_tree::(15 passed) and--test live_record(5 passed)python3 -I live-conformance/live_record_verify.py live-conformance/recordings(27 recordings, 35 clips)python3 -I live-conformance/live_moderation_verify.py live-conformance/moderation, which reads clips withlive_record_verify.pywai breaking --against 6c8016b61 --text --all: no unacknowledged breaking changeRun locally at both commits (text only):
scripts/check-public-names.sh,check-wai-section-refs.py,check-spec-refs.py,check-comparative-prose.shandcheck-no-vanity-metrics.sh, all clean.Part 2, from #605: wai identify, the carousel schedule and holdings
This replaces #589, #592 and #595, closed because main moved under them: wai/CHANGELOG.md's Unreleased head conflicted with main's newer entries (from #591's tariff version 6 on), and a stacked branch can neither be force-pushed nor carry a merge commit. The six commits here are theirs, cherry-picked in stack order onto main at
6c8016b61, with messages unchanged and no merge commit: #589's three, #592's carousel commit, the carousel §11 Patents commit (f64d8fb53: the IETF disclosures on RaptorQ and Raptor, and no-code as the default), which was #592's last push, about seven minutes before it closed; its CI there never finished, so this pull request's CI is its first complete run, and #595's holdings commit. Three commits on the stacked branches carried #589's second and third commits again under the same patch IDs (9680914bb,716dfd41d,f356702ad), so they were skipped.Conflicts. Only one:
wai/CHANGELOG.md, when #589's first commit was picked. This branch's entries go first under Unreleased, newest first (holdings, carousel, identify), above main's entries, which are kept as they are. Main had not changed the shared lists since the stack's base (WAI_FEATURES, the union build's--testand--binlists, the feature-alone loops,codecs/registry.rs,REGISTRY.md, the registry and vocab exports,catalogue/ops.json), so they took the branch's entries in their stacking positions with no conflict.wai-rs/Cargo.tomlmerged cleanly: main'sreceipt_ledgerline keepsexact_upscaleandexact_tonemapbeside the newidentify,carouselandholdingsfeatures. No generated file needed regenerating: both exports check as current at the head.Re-run at the head (
c303cf55d). These ran on the macOS build host, exactly as the CI steps write them unless a note says otherwise, and all passed:wai registry export --checkandwai ops export --check ../catalogue/ops.json.cli_registryandcorpus_provenance.codecs::registry::and the vocab tests).cargo check --lib --features identify, its wasm32 build, andcargo check --testswithcarouseland withholdings.lib identify::(17),tests/identify(6) andwai_identify_vectors verify, thenidentify_verify.py: 429 vectors, 0 failures, with every mutated copy failing.cli_mcp,cli_setup_agent, the binary's own tests andlib catalogue::.int_kernels_vectors(8 tests; not the CI step's full test list).lib carousel:: claim_receipt::schedule::(14) andtests/carousel(7).carousel_verify.pygave 99 cases with 0 failures, 10 of 10 mutated copies failed, and 14 of 14 weakened verifiers were caught.claim_verify.py carouselchecked 134 claims with 0 failures.lib holdings::(5) andtests/holdings(3).holdings_verify.pygave 39 cases with 0 failures, 9 of 9 mutated copies failed, and 10 of 10 weakened verifiers were caught.claim_verify.pyand bearer-receipts.md changed:tests/bearer_receipts,bearer_verify.py, andclaim_verify.py bearer(72 claims).claim_verify.pyon its own corpus (636 vectors) and inconsumptionmode (27 claims).http_verify.py, sincehttp_receipts.pychanged: 1057 of 1057 cases.scripts/check-lockfiles.sh: 60 lockfiles current.These ran locally and also passed:
ruby -ryamlandyaml.safe_loadofwai-conformance.yml.check-public-names.sh,check-wai-section-refs.py,check-tests-in-ci.py,check-workflow-concurrency.shandcheck-wai-ops-doors.py.wai identifyandmedia.inspect(was #589)wai inspectreads envelopes. Most files a toolchain meets are not envelopes, and until now the answer to "what is this file?" came from a file's extension or from a third-party prober. This addswai identify <file>(catalogue operationmedia.inspect, agent toolmedia_inspect): what a file is, from its bytes alone.What it says
signature,structureorparameters. There is no confidence figure, because the strength says what was checked.verdict:identified,ambiguous,signature_onlyorunknown. A walk that stops says why:overrun,invalid,crc,limitorunknown_size.Formats it walks: ISO media, Matroska, transport streams (with CRC-32), Ogg, FLAC, RIFF, MPEG audio, ADTS, PNG, JPEG, GIF, IVF, YUV4MPEG2, FLV, AV1 OBU, Annex B streams, and HLS and DASH text. It knows many more by signature, and the §6 and §7 tables are generated from the code into the spec.
Limits:
untrusted_content, because a file's author chooses the strings in it.How it is checked
Corpus:
wai/identify-conformance/, 429 vectors.tools/make_external.sh).prober.json).wai_identify_vectors verifyandtests/identify.rsrequire the corpus to regenerate byte for byte, with every result.Second implementation:
identify_verify.py.ext/to the prober's reading, and requires every mutated copy to fail.Hostile bytes: prefix, flip and fuzz tests run through every walk. This found the AVS3 probe panic fixed in #586, which is identical here.
Mutation testing: three rounds against the Rust walks. The last round caught 1,999 of 2,185 mutants. The survivors are mostly equivalent mutants: slice bounds that cannot be reached, caps the head or scan limit makes unreachable, and the repeat measure's initial values.
Tests:
lib identify::: 17;tests/identify: 6, covering the corpus, the §6 and §7 tables, every reason and verdict reached, the CLI equal to the library, and a directory or missing file being an error;cli_ops: 10;format_probe: 7.Clippy is clean,
check-wai-section-refsand the public-name check pass, and the ops export is current.CI:
identifyfeature alone and builds it for wasm32.identify_verify.py.media-identify.mdtriggers it.The carousel schedule (was #592)
On a bearer with no return path (broadcast, satellite, one-way multicast), a receiver can't ask for what it missed. It holds an object only if the passes it heard carried enough encoding symbols. WAI could declare such a transmission (bearer-receipts) and reconcile it afterwards, but it had no signed statement of the plan in between: when each object passes, and with what forward error correction. Without one, a one-way bearer can't promise a deadline that anyone can check, and a receiver can't plan when to listen.
This adds
wai.bearer.carousel(extensions/carousel.md) with the jwp-receipts claim classschedule(§2.4.16).The claim
group_start, content hash, and length where the bytes are held.What a verifier derives
repeatand Compact No-Code never count on a second pass.availability_after_deadline,availability_not_within_scheduleorobject_not_scheduled.How it is checked
live-conformance/carousel/):tests/carousel.rs, against an independent RFC 6330 implementation (the Apache-2.0raptorqcrate, added as a dev-dependency only):carousel_verify.py, written from the text.claim_verify.py carouselagrees with wai-rs on all 134 claims through steps 1–4. Its own corpus (636 vectors) and the bearer corpus (72 claims) still pass.http_receipts.py. The HTTP corpus has no schedule claim yet, so that branch is exercised only by compiling it.Breaking
New variants in
ClaimClass,ClaimBodyandReason; each is named in CHANGELOG.Holdings (was #595)
Neighbours (a receiver that stores what a broadcast carried, a neighbourhood cache, a peer) can serve objects over a short link, but nothing said who holds what. This adds
wai.delivery.holdings(extensions/holdings.md).The record
WHD1carries, for each group a node holds objects of:wholeor a bitmap of the objects held, encoded as a reconciliation's bitmap.The record also states an instant it holds at and one it expires at, and the holder signs it under SPEC §7 Signatures. Each holding has exactly one encoding.
It uses groups and bitmaps rather than a filter over hashes, for three reasons:
What a verifier derives
as_ofor at its expiry is refused.object_not_held,object_out_of_rangeorgroup_not_advertised.An object a neighbour serves is verified under its receipts like any other object; a record is never evidence of bytes. A node advertises only what reached it over a broadcast bearer, and may sign each record with a fresh key.
Checks
holdings_verify.py, written from the text, agrees on all 39 cases, catches 9 of 9 mutated copies, and catches 10 of 10 weakened verifiers.wai breaking: no new breaking change.🤖 Generated with Claude Code