Some checks failed
WAI conformance / does this change touch it (push) Has been skipped
WAI conformance / cargo-class corpora · linux (push) Has been skipped
WAI conformance / cargo-class corpora · linux-arm64 (push) Has been skipped
WAI conformance / cargo-class corpora · macos (push) Has been skipped
WAI conformance / cargo-class corpora · windows (push) Has been skipped
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (push) Has been skipped
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (push) Has been skipped
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (push) Has been skipped
WAI conformance / v2 vocabulary · manifests validate as stated (push) Has been skipped
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (push) Has been skipped
WAI conformance / independent verifiers · every verifier step, each corpus's Rust side (push) Has been skipped
WAI conformance / each feature of the independent verifiers' steps compiles alone (push) Has been skipped
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (push) Has been skipped
WAI conformance / cross-arch byte-equality · linux (push) Has been skipped
WAI conformance / cross-arch byte-equality · linux-arm64 (push) Has been skipped
WAI conformance / cross-arch byte-equality · macos (push) Has been skipped
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (push) Has been skipped
WAI conformance / C2PA manifest emission · signed, read back, validated (push) Has been skipped
WAI conformance / independent verifiers · each needs= is what a run without packages shows (nightly) (push) Has been skipped
wai-audit collector and player integration / does this change touch it (push) Successful in 46s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 1m1s
joule-moq-http live HTTP egress / joule-moq-http · does this change touch it (push) Successful in 1m8s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 58s
wai-quantum studio and desktop / does this change touch it (push) Successful in 45s
WAI Studio / does this change touch it (push) Successful in 43s
wai-sink-swift native sink package / does this change touch it (push) Successful in 43s
wai-sink-android native sink library / does this change touch it (push) Successful in 45s
wai-fleet service / does this change touch it (push) Successful in 2m50s
wai-ledger service / does this change touch it (push) Successful in 3m10s
WAI operation catalogue / does this change touch it (push) Successful in 3m12s
wai-pack / wai-pack · does this change touch it (push) Successful in 4m6s
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (push) Successful in 52s
wai-quantum for JavaScript / does this change touch it (push) Successful in 4m47s
wai-app and Create / wai-app · does this change touch it (push) Successful in 5m33s
joule-moq-agent AI participants / joule-moq-agent · does this change touch it (push) Successful in 6m0s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 6m26s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m11s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 52s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 3m32s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 7m36s
joule-moq-http live HTTP egress / joule-moq-http, every target (push) Successful in 9m46s
wai-pack / wai-pack · the floor through a media prober (push) Successful in 2m55s
wai-fleet service / service · macos (push) Successful in 43s
wai web player plugins / the four players in Chromium, Firefox and WebKit · macos (push) Failing after 17m29s
wai-pack / wai-pack · dependency licences (push) Successful in 4m31s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 10s
WAI examples / WAI examples · does this change touch them (push) Successful in 10s
WAI conformance / a push to main · corpus provenance and sidecars, signer ids, the registry export (push) Successful in 52s
wai-ledger service / service · macos (push) Successful in 3m8s
joule-code conformance gate / joule-moq-relay, every target (push) Successful in 23m50s
wai web player plugins / the browser run's room compiles · linux (push) Successful in 1m21s
wai-pack / wai-pack · linux-arm64 (push) Successful in 11m49s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m28s
wai web player plugins / the plugins' core under Node · linux (push) Successful in 4m54s
joule-moq-agent AI participants / joule-moq-agent, every target (push) Successful in 5m46s
wai-ledger service / service · linux (push) Successful in 2m41s
wai-pack / wai-pack · macos (push) Successful in 8m52s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 22m24s
wai-fleet service / service · linux (push) Successful in 5m9s
wai-quantum studio and desktop / studio · browser (push) Successful in 6m57s
wai-audit collector and player integration / collector · linux (push) Successful in 8m0s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 40s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 19m6s
wai-pack / wai-pack · linux (push) Successful in 3m53s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 20m10s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 23m50s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 10m38s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 37m47s
joule-code conformance gate / Build + round-trip C1-C4 vectors (push) Successful in 17m0s
wai-quantum for JavaScript / javascript · linux (push) Successful in 10m32s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 17m57s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 14m49s
wai release binaries build on Windows / the seven release binaries · windows (push) Successful in 21m39s
joule-code conformance gate / joule-moq-ingest, every target (push) Failing after 47m10s
wai-pack / wai-pack · independent verifier (Python) (push) Successful in 33m37s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 25m57s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 13m29s
WAI Studio / Studio in WebKit · linux (push) Successful in 32m45s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 3m47s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 48m5s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 13m30s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Successful in 21m5s
WAI examples / WAI examples · portable · linux (push) Successful in 27m47s
WAI examples / WAI examples · android-app · linux-arm64 (push) Successful in 19m2s
A profile record (live-rooms §8.1) could not state the Opus frame length or a jitter-buffer target, so no profile could ask for the short frames performers playing together need, and the room page took its frame from the URL (20 ms by default). A descriptor of version 2 is version 1 with frame_us and jitter_us in every profile record. A frame is one of RFC 6716 §2.1.4's durations, on a profile of Opus alone; a jitter target is whole frames, at most a second, and needs a frame; video states neither. A descriptor is written at the lowest version that carries it, and a version-2 descriptor that states no frame is refused, so every room of version 1 keeps its bytes and room id; a verifier of the earlier revision refuses version 2 as unknown_version (fails closed). Decision D111. jam (§8.2): music with 5 ms frames (CELT alone, 7.5 ms of algorithmic delay) and a 10 ms jitter target, which leaves 7.5 to 12.5 ms of the 25 to 30 ms ensemble threshold to the path. D111 says why not 2.5 or 10 ms, with the receipt bytes a one-object group costs measured on the corpora (377 to 409 bytes). wai-rs live_room reads and writes version 2 and registers jam; the rooms corpus adds jam's record (its version stated), a jam room and a room with a 10 ms profile of its own, and eight descriptors refused for one defect each; descriptor_unknown_version is now version 3. live_rooms_verify.py follows the text, with mutated copies and eight weakened checks each caught; live_worlds_verify.py reads version 2; joule-moq-ingest's own reader reads version 2 and knows jam; wai-live-web's room view states frame_us and jitter_us; the room page encodes with catalog.js's opusConfig (the profile's frame over the URL's, lowdelay below 10 ms, music signal, no DTX or in-band FEC), tested on the corpus records. The three breaks are acknowledged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
143 lines
9.7 KiB
Markdown
143 lines
9.7 KiB
Markdown
# live-conformance/rooms — live rooms
|
|
|
|
The corpus of [`extensions/live-rooms.md`](../../extensions/live-rooms.md) §12: rooms, each
|
|
a signed `WRD1` descriptor, its `WRG1` grants, the head of its authority's key log, and its
|
|
principals' `WEV1` chains, with the outcome a room verifier gives them; and the records of
|
|
the registered publish profiles. A descriptor is of version 1, or of version 2 where one of its
|
|
profiles states an Opus frame length or a jitter target (§3.1, §8.1): the jam room's, for the
|
|
registered `jam` profile, and eight descriptors refused for a frame or a jitter target a
|
|
profile may not state, each one defect.
|
|
|
|
**Room equivalence.** For each vector, a conforming room verifier given its `descriptor`,
|
|
its `grants` in order, its `key_log_head` (or none) and its `chains` (each one principal's
|
|
records in stream order) reaches the outcome the vector states (§9.4):
|
|
|
|
- `refuse`: the `reason` and where, `at`: `["descriptor"]`, `["key_log"]`,
|
|
`["grant", i]`, or `["record", c, i]` for record `i` of chain `c`;
|
|
- `gap`: no record refused, and the `gaps` (principal, first and last seq not held), under
|
|
the code `delivery_gap`, with the `room` id and the merged `order`;
|
|
- `accept`: the `room` id; every grant's digest (`grant_digests`); the merged `order`
|
|
(§9.2), each entry `[chain, record, grant]` with the digest of the grant the record was
|
|
verified under, or `null` for a room key's record; the room `state` (§9.3); the `tally`
|
|
of the room's polls (live-events §7); and, per grant, the `moqt` scopes and `reval`
|
|
interval it maps onto (§10.2), and whether it holds the seek power, `seek` (§3.3).
|
|
|
|
A verifier that reaches another outcome, reason, place, gap, digest, order, state, tally,
|
|
scope or seek power does not conform.
|
|
|
|
**Seeking back.** For each request of `seek`, a conforming relay, given the grant the
|
|
request names, the track's live edge and the request's start Location, serves it or
|
|
refuses it `seek_not_granted` as the request states (§10.6): a request whose start group
|
|
is below the live edge seeks back, and is served only under a grant whose `powers` has
|
|
bit 4.
|
|
|
|
**Provenance.** Generated here: `wai_live_room_vectors gen` writes every descriptor, grant,
|
|
key-log head and record from rooms authored in code, from fixed seeds. Each key is SHA-256
|
|
of a fixed label and the principal's index, each nonce and viewer id likewise, every time
|
|
is a constant (the rooms' `t0` is 2026-10-16T00:00:00Z), and Ed25519 signing is
|
|
deterministic (RFC 8032), so the file is the same bytes on every machine. The generator
|
|
asserts that each vector reaches the outcome it was written to have before it writes it.
|
|
The key-log heads are sealed by the reference's key log (jwp-receipts §7.2) under a fixed
|
|
root. The origins are `.example` names (RFC 2606). No recorded data. The frame durations a
|
|
profile may state are RFC 6716 §2.1.4's list (September 2012, read 2026-11-14), and `jam`'s
|
|
5 ms frame and 10 ms jitter target are §8.2's, with the reasons decision D111 gives; nothing
|
|
here was measured.
|
|
|
|
## Layout
|
|
|
|
One file, `vectors.json`:
|
|
|
|
- `principals`: the keys, by name (informative).
|
|
- `registered_profiles`: each profile §8.2 registers, by `name`, with its `record` (§8.1)
|
|
in hexadecimal and the descriptor `version` whose profile form the record is in (2 for
|
|
`jam`, which states a frame; 1 for the others, which a descriptor of version 2 writes with a
|
|
frame and a jitter target of 0); a verifier compares its own table with them.
|
|
- `vectors`: each with `name`, `about`, `descriptor` and `grants` (hexadecimal),
|
|
`key_log_head` (a key-log revision's JSON text, or `null`), `chains` (lists of records
|
|
in hexadecimal), `outcome`, and as above `reason`, `at`, `room`, `gaps`,
|
|
`grant_digests`, `order`, `state`, `tally` and `moqt`.
|
|
- `proofs` (§10.5): each with `name`, `about`, `binding` (`moqt` or `http`), what is
|
|
presented — for `moqt`, the AUTHORIZATION TOKEN's value `token` (the grant's record) and
|
|
the `GRANT_PROOF` option values `proofs`, in hexadecimal; for `http`, the request's
|
|
`headers`, `authorization` (`Bearer` and the grant's record in base64url) and
|
|
`wai-room-proof` (the proof record in base64url) where it has one — then what the
|
|
verifier holds: the `challenge` it issued and holds (over HTTP the request's; over MOQT
|
|
one its SETUP gave on an earlier session, which the client's SETUP proves over, since a
|
|
relay reads the client's SETUP before it sends its own), the `consumed` challenges, and
|
|
the `verb` and `target` it received; and the `outcome`, `accept` or
|
|
`refuse` with its `reason` (§10.5.4).
|
|
- `seek` (§10.6): each with `name`, `about`, the grant the request rests on — `vector`, the
|
|
name of the accepted room, and `grant`, its index among that room's `grants` — the
|
|
track's `live_edge` (the group of its Largest Object), the request's `start` Location
|
|
`[group, object]`, the `request`, `fetch` (a FETCH) or `fill` (a SUBSCRIBE's fill), and
|
|
the `outcome`, `serve` or `refuse` with its `reason`.
|
|
|
|
`state` has `present` (each principal and its grant in effect, by principal), `published`
|
|
(each own track: principal, media kind, profile name, number of layers, by principal and
|
|
media code), `slots` (each slot in the descriptor's order: its live publisher, standby,
|
|
and the live publisher's precedence), `tracks` (the rendered Full Track Names of every
|
|
track a subscriber can reach, §6.1, sorted), and `timeline` (each change of a principal's
|
|
grant in effect, with its `t`).
|
|
|
|
Vectors:
|
|
|
|
- accepted rooms: `lesson` (a director's remote record control of a performer, an audience
|
|
under single-use grants, review and recording policies with a region pin, a key-log
|
|
head revoking a grant and a viewer the room never admits), `broadcast` (one publisher,
|
|
viewers voting, a moderator's decision, no key log, the authority its own clock),
|
|
`takeover`, `redundant_failover`, `promote_viewer`, and `dvr` (a broadcast whose relay
|
|
keeps a DVR window: one publisher, and an audience whose role holds the seek power,
|
|
viewer_a's grant holding it and viewer_b's narrowing it away; its grants are 0 the
|
|
host's, 1 viewer_a's, 2 viewer_b's);
|
|
- `room_gap`: a chain with a record not delivered;
|
|
- one negative control per refusal, each a single defect: the descriptor truncated, with
|
|
trailing bytes, of another version, with a flipped signature bit, with a tick of 0,
|
|
with a registered profile changed, with a role beyond the ceiling, with a recording
|
|
policy whose jitter exceeds its commit interval, and with a role whose powers set bit 5;
|
|
the key log missing, of another origin, re-signed wrongly, not listing the authority,
|
|
and revoking it; a grant truncated, signed by another key, of another room, permitting a lifecycle
|
|
kind, with oversized attributes, too long, beyond its role, beyond the room's ceiling,
|
|
chained to nothing, chained to another principal's, with the seek power its role does
|
|
not hold, and with powers setting bit 5; and in the records, a bad
|
|
signature, the wrong room, a kind not in the grant, a participant's lifecycle event,
|
|
events outside a grant's window, a principal not present, a revoked grant and a
|
|
revoked viewer, a reused single-use grant, an unknown grant, another principal's grant,
|
|
a second join, the participant limit, a malformed detail, every publish refusal, every
|
|
exchange refusal, a takeover without higher precedence, both failover refusals, a
|
|
command without its power, a grant's rate and payload bounds, and a stated tally the
|
|
replay does not reach;
|
|
- proofs, under the broadcast room's host's grant: over MOQT, one accepted, and refused a
|
|
grant with no proof, the accepted proof presented again in a later SETUP, a proof over a
|
|
challenge the relay does not hold, one by the moderator's key, one naming the host's key and
|
|
signed by the moderator's, one naming the moderator's grant, one for another relay, and
|
|
three records that do not read; over HTTP, a WHIP `POST` and the session's `DELETE`
|
|
accepted, and refused the Bearer token alone, the `POST`'s proof sent again, a `POST`'s
|
|
proof on a `DELETE`, and a MOQT proof presented over HTTP;
|
|
- seek requests, under the `dvr` room's grants, on a track whose live edge is group 120
|
|
unless stated: served, a FETCH from group 90 and a fill from group 100 under viewer_a's
|
|
grant, which holds the seek power; refused `seek_not_granted`, the same FETCH and fill
|
|
under viewer_b's, which does not, a FETCH from (119, 7) under it, and a FETCH from group
|
|
90 under the host's, whose role lacks the power; and served under viewer_b's, a FETCH
|
|
from (120, 0) and from (120, 3), a fill from (120, 0) joining the group in progress, and
|
|
a FETCH from (0, 0) of a track whose live edge is group 0.
|
|
|
|
## Running
|
|
|
|
```
|
|
cd ../../wai-rs
|
|
cargo run --no-default-features --features live_room --bin wai_live_room_vectors -- verify ../live-conformance/rooms
|
|
cargo run --no-default-features --features live_room --bin wai_live_room_vectors -- gen ../live-conformance/rooms # regenerate
|
|
cargo test --no-default-features --features live_room --test live_room
|
|
cd ../live-conformance
|
|
python3 live_rooms_verify.py rooms
|
|
```
|
|
|
|
`wai_live_room_vectors verify` and `tests/live_room.rs` require the file to regenerate
|
|
byte for byte and `wai-rs` to give every vector, every proof and every seek request its
|
|
outcome; the test also requires every reason of §11 to refuse a vector, a proof or a seek
|
|
request, `seek` to hold requests served and refused, and §11 to list exactly the reasons
|
|
the reference reports.
|
|
`live_rooms_verify.py` is the second implementation, written from the extension's text and
|
|
sharing no code with `wai-rs`: it verifies every event with `live_events_verify.py`, the
|
|
live-events corpus's own second implementation, gives every vector, proof and seek request
|
|
the same outcome, and requires the same coverage. Pass = an exit status of 0 from each.
|