wai: refinement layers over Media over QUIC — a receipts track per media track, recovery, and late join #174

Merged
dcharlot merged 29 commits from wai/w1-6-moq-layers into main 2026-10-06 16:05:58 -04:00

2026-10-06

Transaction Science
Merge main (session claim merged as #173) into wai/w1-6-moq-layers
All checks were successful
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m11s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 9m48s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 29s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m12s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m14s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 2m54s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m12s
wai-pack / wai-pack · macos (pull_request) Successful in 2m11s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m5s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m37s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 23s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 6m4s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 12s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 11m28s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 8s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 23s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 46s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m34s
WAI HTTP delivery / HTTP corpus · falsification and differential (pull_request) Successful in 13m5s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 57s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m3s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m7s
wai-pack / wai-pack · linux (pull_request) Successful in 1m3s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 1m40s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 20s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m10s
WAI section references / cited sections exist (pull_request) Successful in 10s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m1s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 1m56s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
Co-Authored-By: Claude Opus 5.5 <[email protected]>

# Conflicts:
#	wai/CHANGELOG.md
#	wai/REGISTRY.md
#	wai/registry/capabilities.json
2026-10-06 13:52:09 -04:00
Transaction Science
wai, joule-moq: the MoQ trace fills a gap — the lossy subscriber fetches what its re-anchor skipped (round 4, item 3)
The lossy subscriber now states fetch_ms (40): when its layer 1 chain re-anchors at
group 9, it FETCHes the receipts of the groups the anchor skipped (6, 7, 8; 6 the one
its relay dropped, 7 and 8 those refused from the hold). They arrive 40 ms later in
ascending order and each links forward from the one before: history, verified at 525.
Their layers wait for them rather than being refused at the re-anchor: 6's is then
late (unit 6), 7's and 8's in time and applied (units 7, 8).

trace.json states fetch_ms on every subscriber and fetched_ms on every object. The
generator and staged_verify.py model the fetch (moq_settle: a gap per re-anchor,
filled forward or backward, anything else outside the model). Both trace tests feed
fetched receipts through admit_on, require History for each, and compare when each
was fetched; joule-moq's answers the FETCH from the receipts the relay holds.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 12:57:41 -04:00
Transaction Science
joule-moq: an admitted group offered again changes nothing; a legacy group is known by its bytes, not its link (round 4, items 1 and 2)
- Item 1: Admission::AlreadyAdmitted. A group the chain admitted before, other than
  its head, offered again with the same bytes returns it before anything is verified,
  never ChainBreak; the head again is Linked as before. Test:
  an_admitted_group_offered_again_changes_nothing (group 3 after head 6; a joiner's
  anchor delivered again, then history behind it).
- Item 2: the chain keeps each admitted link with a digest of the group's bytes as
  carried (unsigned members included), and holds a group as known only when its bytes
  equal the held one's. A legacy group's link covers neither its parent nor its
  coverage: a variant with an unsigned coverage is now verified, and refused
  (Unverified); one with its parent rewritten is the head again and changes nothing.
  Test: a_legacy_variant_is_not_the_group_admitted (the review's jmoq_probes2 case).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 12:52:20 -04:00
Transaction Science
wai: an admitted group offered again changes nothing (accept again), never chain_break (round 4, item 1)
jwp-receipts §3 step 3: a group the verifier admitted to the chain before, offered
again with the same bytes (a legacy group's unsigned parent among them), passes and
changes nothing: MOQT can deliver one object twice, by a subscription and a fill
(§3.4). ReceiptChains::admit returns Admission::AlreadyAdmitted ("accept again")
before verifying; the chain keeps each admitted link with the parent it came with,
so a legacy group whose parent differs is not that group and is checked as before.
verify_object therefore succeeds for any admitted group, not only the head, without
verifying the group again. jwp_verify.py does the same.

Two vectors on main change their expected outcome, as the decision requires:
chain_head_predecessor_replayed (b0 again after b1: accept again, was chain_break)
and chain_legacy_replay_loop (g1 replayed with its parent unchanged: accept again,
was chain_break); the rewritten g0 is still refused. New vectors from the review:
chain_duplicate_after_the_head_moved and chain_join_anchor_delivered_again. New test:
an_admitted_group_verifies_its_objects_after_the_head_moved.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 12:50:57 -04:00
Transaction Science
joule-moq: chains verify signatures, fill gaps in any order, hold within bounds in all; the trace recovers through for_moq (NEW 7, NEW 1, NEW 2, OPEN 1)
ReceiptChains, re-implemented from WAI jwp-receipts §3 step 3 as amended:

- NEW 7: admit verifies each group's key, signature and label first
  (ReceiptVerifier::verify_group, any key); a forged group is Unverified and never
  held, admitted or anchored, joined or re-anchored.
- NEW 1: each anchor leaves a gap; a group inside it linking to either end is
  history, so an ascending FETCH after a re-anchor and a joiner's ascending fill
  are admitted (the review's two sequences, as tests).
- NEW 2: held groups indexed by link and by parent; offered again only when a group
  they link to is admitted; each signature verified once; a history count per chain
  and a total across chains beside the live count; Chain.links capped at
  CHAIN_HELD_LINKS (65 536, as WAI's reference). Tests count held groups,
  verifications and re-offers, not time.
- OPEN 1: for_moq refuses a count above MAX_HELD_GROUPS; HoldBound::from_json
  refuses a statement without counts; admit_on and ObjectReceipt::check_moqt refuse
  a receipt off its track, group or object (MoqtMismatch) unheld.

tests/staged_moq_trace.rs drops its pending queue: each subscriber's chains are
for_moq under its stated bound; the joiner subscribes at its join and anchors; the
lossy subscriber's lost receipt is recovered by re-anchoring, its layers refused;
when each receipt is verified or refused, and each status's evidence, are the
trace's.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 12:08:54 -04:00
Transaction Science
wai: the MoQ trace recovers through the MoQ verifier, under a stated bound (OPEN 1, NEW 4)
tests/staged_moq.rs drops its own pending queue: each subscriber's verifier is
ReceiptChains::for_moq under the bound the subscriber states (HoldBound::from_json,
which refuses a statement without counts), joining where it joins; each receipt
goes through admit_on (its key, alias and MOQT group) and check_moqt (its object),
and what was held is settled through take_events. The time each receipt is
verified or refused is compared with the trace's.

moq/trace.json (format /3) states object 0 on each object, a hold bound on each
subscriber, and two new subscribers: one whose relay drops the receipts-track object
of layer 1's group 6 (7 and 8 held under a bound of 2, refused when 9 passes it,
the chain re-anchoring at 9, the layers of 6 to 8 offered with no evidence and
refused, 9 to 11 verified: P-W1 recovered through the MoQ path), and one that joins
after GOP 0 and anchors each chain at its first receipt. The generator and
staged_verify.py model the bounded wait (moq_settle): hold within the count, past
it refuse and re-anchor, refuse what the anchor skips; statuses carry their
evidence. The full and capped subscribers' outcomes are unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 12:02:52 -04:00
Transaction Science
wai: a rendition has its own chain; the catalog check needs its namespace; no varint cap (NEW 3, NEW 5, NEW 6, NIT, P-J5)
moq-streaming-format §4.1 and the check (wai-rs staged::moq, staged_verify.py):

- NEW 3: no two tracks of a catalog carry one wai_receipt_alias or name one
  receipts track; a rendition of a layer, a clone among them, overrides both.
  delta_clone_layer_2 is now refused (staged-receipts); delta_clone_layer_2_own_chain
  overrides both and adds its receipts track, and is accepted.
- NEW 6: the check needs the catalog track's namespace. A checker without it
  (check_catalog, check_catalog(c) in Python) refuses a set that mixes declared and
  inherited namespaces (staged-malformed). catalogs.json (format /3) states the
  namespace each case is checked under, and gains the inheritance cases of the
  review: layers inheriting under example/cam1, other/ns and none known; layer 1
  twice, declared and inherited; every track inheriting.
- NEW 5: MOQT-22 integers reach 2^64 - 1 (§8.1): MAX_MOQT_VARINT, the Python slack
  cap, the CHANGELOG line and the §8.1 citation are gone.
- NIT: two tracks of a catalog MUST NOT share a namespace|name pair.
- P-J5: a subscriber sets no delivery timeout on its subscription to a receipts
  track (MOQT §9.20.3, §9.20.4); a receipt it loses anyway it recovers.
- Text for what follows: a receipt says which MOQT object it is about (group_id,
  object_id, key and alias; moqt_mismatch), the bound a subscriber states (a count
  live, never a time alone; history; total), and gaps filled by an ascending FETCH
  or fill as history.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 11:55:28 -04:00
Transaction Science
wai: receipt chains fill gaps in any order, under bounds that hold in all (NEW 1, NEW 2)
jwp-receipts §3 step 3. Each anchor leaves a gap between the last group admitted
before it and the earliest at or after it; a group inside the gap that links to
either end is history and moves that end, so a gap fills ascending (as MOQT
delivers a FETCH or a fill), descending, or from both ends, and closes when one
group links to both. A group linking into a gap is never chain_break.

Holding states three counts: live per chain (past it the chain re-anchors),
history per chain for groups inside a gap (past it the lowest held below is
refused, alone), and a total across chains; MAX_HELD_GROUPS caps every hold.
Held groups are indexed by link and by parent; a held group is offered again
only when a group it links to is admitted, so re-offering the head changes and
verifies nothing; each signature is verified once (a group admitted or held is
known by its link hash). ReceiptChains::for_moq refuses a count above the
maximum; HoldBound::from_json refuses a statement without counts; admit_on and
ObjectReceipt::check_moqt refuse a receipt off its track, group or object
(moqt_mismatch) before verifying or holding it.

The reviewer's two sequences are corpus vectors (gap fetched ascending after a
re-anchor; a joiner's ascending fill under a live bound of 4), with the history
bound passed and the total passed across two tracks; jwp_verify.py implements
the same rules; chain_gap_differential.py states the new counts and refetches
ranges ascending.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 11:48:58 -04:00
Transaction Science
2026-10-06 10:41:21 -04:00
Transaction Science
joule-moq: receipt chains recover (P-J2, P-J3); public text by capability; the conformance gate parses its count
Review items 1 (joule-moq) and 10:
- ReceiptChains: with_hold(HoldBound {max_groups, max_age_ms}), with_join(),
  admit() -> Admission (Linked, Anchor, History), expire(), take_events(),
  anchors(), held(): a held group is admitted when its parent arrives; past the
  bound the chain's held groups are refused (ChainRefusal::ParentNotRecovered)
  and it re-anchors at its next group above its head; a joiner anchors at its
  first group; groups linking back to a labelled anchor are history. Without the
  options accept() behaves as before.
- Tests: a lost receipt stalls without holding and recovers by re-anchoring (by
  count and by time), the lost group and the refused ones regained as history,
  a fetched parent releasing what waits on it (P-J2); a late joiner admits from
  its anchor and back to the chain's start (P-J3).
- wai_dispatch.rs: the capability docs name capabilities and standards only, with
  no evaluative or comparative wording. The names and prose checks pass on every
  tracked joule-moq file, given by explicit path.
- joule-code-conformance.yml: the C1-C4 pack's summary is matched as
  '^[1-9][0-9]* passed, 0 failed, ' ("10 failed" no longer reads as "0 failed";
  an empty pack fails).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 10:39:21 -04:00
Transaction Science
wai: receipt chains recover — holding with a stated bound, re-anchoring, joining, history behind a labelled anchor
Review item 1 (wai-rs and Python), P-W1:
- jwp_delivery::ReceiptChains: with_hold(HoldBound {max_groups, max_age_ms}) holds
  a parent_not_held group and admits it when its parent arrives; holding past the
  count, or expire() past the time, refuses every group held for the chain
  (parent_not_recovered, a new §3.3 reason) and re-anchors it at its next group
  that passes steps 1-2, the freshness bound and a group_id above the head's.
  with_join() anchors a chain it holds nothing of at its first such group. Behind
  a labelled anchor, groups that link back are admitted as history. admit()
  returns the Admission (Linked, Anchor, History); take_events() reports what
  became of held groups; anchors() reports every anchor and the group before its
  gap. Without the options nothing changes, and every existing vector is
  byte-identical.
- jwp-conformance: twelve chain vectors with a recovery input (fetched parent,
  release order, lost receipt with and without holding, re-anchor and history
  regained, a re-anchor refused behind its head, join mid-stream / at the start /
  on a legacy chain / with a stale group), appended after every existing vector;
  outcomes accept anchor and accept history. jwp_verify.py implements the same from
  the text; chain_gap_differential.py lets both verifiers recover on half its
  chains (seeds 1-3, 400 chains each: 0 differ).
- Unit tests: a lost receipt stalls without recovery, re-anchors by count and by
  time, and is regained as history; a late joiner admits from its anchor.
- jwp-receipts §3 step 3 History applies behind any labelled anchor; §5.9 lists
  the recovery vectors; README documents the input and outcomes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 10:34:40 -04:00
Transaction Science
joule-moq: a receipts track per media track, RelayStats keyed by position and counted when sent, checked send times
Review items 5 (joule-moq), 6 and 9 (P-J4):
- RelayTrackConfig names the track's receipts track; subscribe_tracks takes the
  media tracks and the receipts tracks; ingest_receipts takes the receipts track
  a bundle arrives on and forwards it only to that track's subscribers. The
  trace test subscribes each subscriber to the receipts tracks of its own tracks
  and no longer filters what reaches it (it asserts nothing else does).
- RelayStats::receipts_forwarded_for_dropped is keyed by (track, group, object)
  and counted when the receipts are sent to the subscriber the object was
  dropped for (or when the object is dropped after they were): P-J1a now counts
  two identical-bytes objects as two, P-J1b counts none for receipts never
  forwarded. Both are unit tests.
- MockRelay::ingest refuses a send time past the caller's clock instead of
  saturating it (P-J4, a unit test).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 10:18:49 -04:00
Transaction Science
wai: MoQ catalog — extent from the tracks present, typed fields, namespaces, a receipts track per media track; text against MOQT-22/MSF-01/CMSF-01
Review items 2, 3, 4, 5 (catalog and text), 7, 8 and 9:
- wai_staged is {set, layer, lead_ms}: a set's extent is its tracks, layers 0..max
  each with a track, so MSF delta updates and clones change it alone; lead_ms is
  read only while the set is live (as MSF §5.2.8 treats targetLatency).
- renderGroup an integer fitting u64, depends an array of strings, a track's
  namespace|name unique, one namespace per set, every depends entry a catalog
  track in its own namespace (namespace inherited per MSF §5.2.2):
  staged-malformed / staged-depends / staged-grouping.
- One receipts track per media track (wai_receipts_track), at its priority,
  group g carrying the receipts of media group g; an alias shared only by
  renditions of one chain; every wai_receipt_alias in the catalog an integer
  compared as a number.
- §4.1 text: recovery by FETCH, a stated hold bound with re-anchoring, joining
  (MOQT-22 replaced Joining FETCH with fill fetch streams: cited so); the
  conditional form of what a receipts-track subscriber holds; subscriber priority
  first (§5.1.2); SUBGROUP_DELIVERY_TIMEOUT from FIN to acknowledgement; no
  datagrams (MSF §6); timeouts capped at 2^62−1; a longer sink latency cannot
  extend a publisher timeout; a MOQT relay carrying receipts as payload is not a
  §4 relay (jwp-receipts §4.1 amended); §6 says what §4.1 paraphrases; CMSF-01
  pinned.
- jwp-receipts §3 step 3: holding, re-anchoring, joining, history behind a
  labelled anchor, what an anchor does not prove; §3.3 parent_not_recovered;
  §6.1 anchors. (Implementation follows.)
- staged::moq rewritten to match; layer_timeout_ms capped at 2^62−1; the corpus
  generator's trace check uses checked arithmetic and refuses rather than
  panics; catalogs.json gains the reviewed type and namespace cases and the
  delta and on-demand cases; staged_verify.py type-checks before use.
  catalog_diff.py: 100,000 catalogs, 0 differences, 0 crashes.
- joule-moq StagedTrack drops layers.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 10:16:03 -04:00
Transaction Science
wai: CHANGELOG — staged tracks over MoQ
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 09:20:38 -04:00
Transaction Science
wai: the layered-PCM port vectors — rate_port.json and test 15
The rate predictor of wai.audio.int_refine, rdiv(a·num + (b − a)·ρ, num),
beside the f64 linear interpolation of the layered-PCM ladder idea, written
from its description (no earlier code copied): on integer fixtures (a sine by
Bhaskara I's approximation, a triangle, full-scale steps), mono and stereo, at
seven ratios, the SHA-256 of the integer predictions and every sample where the
two differ. They agree at every dyadic phase, where the f64 form is exact (the
generator asserts it); they differ by one, at 1/6 and 147/160 phases, where f64
rounds next to a half.

Written by wai_staged_vectors; staged::tests::rate_matches_ported_reference_where_exact
(design test 15) checks it with its own f64 form; staged_verify.py checks it with
its own integer predictor and IEEE arithmetic.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 09:18:45 -04:00
Transaction Science
joule-moq: staged tracks — staged.rs, ReceiptChains per key and track, MockRelay per-hop timeouts and RelayStats
- staged.rs: StagedTrack (wai_staged), refines_of / layer_from_envelope (the
  layer read from the envelope's refines), check_mrl_agrees (compares, never
  obeys, the prototype header), live_object_rules_ok.
- receipt.rs: ReceiptChains, WAI jwp-receipts §3 step 3 per (publisher key,
  track_alias): head, ParentNotHeld held not accepted, ChainBreak for a second
  head or fork, GroupIdNotIncreasing for a legacy group.
- mock.rs: MockRelay forwards staged tracks on a caller-driven clock —
  configure_track (track timeout, live one-object groups), subscribe_tracks
  (capping by subscription, own timeout, receipts track), ingest (arrival at
  this hop, queue time, object timeout), ingest_receipts (no timeout, sent at
  once), advance (MOQT §5.2 at this hop), relay_stats (RelayStats: forwarded,
  dropped_on_timeout, receipts_forwarded_for_dropped). Nothing sleeps.
- messages.rs and wai_dispatch.rs: max_mrl_layer, mrl_layer and
  mrl_total_layers superseded for WAI objects (staged-delivery §13); the
  LAYERED_PCM idea is wai.audio.int_refine's rate predictor; its namespace is a
  registry decision. lib.rs exports staged, ReceiptChains, ChainRefusal and
  drops a comparative sentence.
- tests/staged_moq_trace.rs: staged_tracks_drop_on_timeout_keep_receipts runs
  WAI's staged-conformance/moq/trace.json as a third implementation (own
  receipts, own chain verifier, own stage rule) and must reach the trace's
  fates, verification times, presented stages, misses, statuses and relay
  counts; the capped subscriber holds two chains.
- Unit tests for ReceiptChains and the relay's hop timeout boundary.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 09:14:42 -04:00
Transaction Science
wai-rs: tests/staged_moq.rs — the MoQ trace with signed receipts, chains per track and claims
Runs staged-conformance/moq/trace.json with real receipts: the catalog passes
§4.1 and its aliases are the receipts'; each base decodes through
staged::decode_base; the publisher signs one labelled group per object, a chain
per track; the relay applies MOQT §5.2 at its hop, drops what outlives its
timeout, forwards every receipt and signs a delivery-gap claim per dropped
object, checked against its receipt. Each subscriber keeps ReceiptChains, holds
a receipt for its parent (frame 5's) and admits it when the parent arrives,
checks delivered objects over their bytes and dropped ones by inclusion, and
takes each object once it has it and its verified receipt. Its steps, reports,
final units, presented stages, deadline misses and each layer's status must be
the trace's; each base's stage claim seals and verifies; the capped subscriber
holds exactly two chains.

CI: a step in wai-conformance.yml (features staged,video_int,receipt_claims);
joule-code-conformance.yml fires on wai/staged-conformance/** for joule-moq's
run of the same trace.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 09:07:12 -04:00
Transaction Science
wai: a track's receipts are one chain — the MoQ trace verifies a receipt after its parent
Receipts-track objects travel on streams of their own and can arrive out of
order; jwp-receipts §3 step 3 admits a group only after its parent. The trace
now verifies each receipt once it and every earlier receipt of its track have
arrived (verified_ms), and a sink applies a layer at the later of its arrival
and that time: frame 5's slow receipt holds frames 6 and 7 until it arrives.
moq-streaming-format §4.1 states the consequence. Both verifiers derive it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 09:04:14 -04:00
Transaction Science
wai: staged-conformance/moq — the set's MSF catalog, catalogs around §4.1's check, a drop-on-timeout trace
wai_staged_vectors writes and verifies moq/: catalog.json (a live set: base
track, two layer tracks, the receipts track), catalogs.json (each §4.1 rule
broken alone, two faults, an unreadable set, two sets) and trace.json: the
envelopes of video_int_motion_gop_perframe on their tracks, one object to a
group, through one relay to a subscriber of every track and one of base and
layer 1. Per-object OBJECT_DELIVERY_TIMEOUT is the slack to the last unit
covered; the relay drops the layer 2 of two GOPs on timeout and forwards their
receipts; frame 5's layer 1 passes the relay within its timeout and is late at
the sink. expect: each object's fate, the sink's steps, reports, final units,
stage presented per clock position, deadline misses, each layer object's
status, and the relay's counts. verify checks it from the committed inputs;
staged_verify.py checks it independently (catalog check, slack, priorities,
relay fates, the steps replayed through its own sink).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 09:02:24 -04:00
Transaction Science
wai-rs: staged::moq items stay out of the C header (cbindgen:ignore)
MAX_CATALOG_INT as a C #define would overflow an int.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 08:57:13 -04:00
Transaction Science
wai-rs: staged::moq — wai_staged, the §4.1 catalog check, priorities and per-hop timeouts
StagedTrack (to_json/from_json), SetTrack::to_catalog_json, check_catalog with
the six ordered reasons of moq-streaming-format §4.1, depends_for,
live_object_rules_ok, priorities_ok (MOQT numbers: lower first),
effective_timeout_ms and expired_at_hop (MOQT §5.2 at one hop),
layer_timeout_ms (slack to the last unit covered, never 0) and
base_timeout_floor_ms. Unit tests, one per rule, and a test that §4.1 lists the
reason tokens in order.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 08:56:24 -04:00
Transaction Science
wai: staged tracks over MoQ — moq-streaming-format §4.1, the receipts track, per-hop timeouts
moq-streaming-format, re-read against draft-ietf-moq-transport-22 and
draft-ietf-moq-msf-01 (named in its status note):
- §4.1 Staged tracks: one track per layer; wai_staged {set, layer, layers,
  lead_ms}; MSF isLive, renderGroup, depends, altGroup, temporalId/spatialId
  rules; a closed, ordered catalog check (staged-malformed, -set-incomplete,
  -depends, -grouping, -lead, -receipts); one object per group, its own
  subgroup, on live tracks; priority by MOQT's number order (lower is first);
  OBJECT_DELIVERY_TIMEOUT no more than the slack to the last unit covered,
  per object as an object property; timeouts run per hop and are never the
  lateness rule; capping by subscription; the receipts track (wai-receipts).
- §4 gains wai_receipt_alias: MOQT's Track Alias is chosen per session by
  each publisher on the path (MOQT §3.1.3), so it is not the track_alias a
  receipt signs past the first hop.
- §5: a relay that does not forward an object forwards its receipts; a
  delivery-gap claim is not added to the publisher's receipts track.
- Corrections from the re-read: MSF's packaging values (no 'catalog' value),
  MSF does not set priorities (MOQT does), MOQT properties and MSF §12.
staged-delivery §8, §9, §13, jwp-receipts §4.4 and http-delivery §10.2 and
Appendix C point at it. Three wire identifiers join the registry.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 08:54:25 -04:00
Transaction Science
wai-rs: regenerate include/wai.h (CHAIN_REQUESTED_LINKS left the code before this)
build.rs writes the header from the FFI surface on every build; the committed
copy still declared a constant the code no longer has.

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