open-standards/wai/live-conformance/rooms
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Transaction Science ab23c8ab6b live rooms: AI participants are marked in their grant, and chat and reactions state their origin
live-events §4.4 and §4.5: a chat and a reaction may state an origin after their last
field (1 human, 2 machine, 3 machine-reviewed, with the model's digest for 2 and 3), as a
caption does. live-rooms §4.4: the grant attribute `ai` names the model that acts for an AI
participant; §9.2 step 6 refuses its chat, reaction or caption that does not state origin 2
or 3 with that model (`ai_unmarked`), and a relay does not forward one. Both corpora gain
vectors (additions only); both second implementations read the new fields.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 05:17:43 -04:00
..
README.md live_rooms_verify.py and the rooms README: the seek power and §10.6's seek requests 2026-10-19 11:45:51 -04:00
vectors.json live rooms: AI participants are marked in their grant, and chat and reactions state their origin 2026-10-21 05:17:43 -04:00

live-conformance/rooms — live rooms

The corpus of 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.

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.

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; 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 for this session or request, 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 on a later session, a proof over another session's challenge, 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.