wai.live.coperformance in the live room: the clock signs, the relay refuses, the page performs (CO4b) #424

Closed
dcharlot wants to merge 0 commits from wai/co-performance-live into main
Owner

CO4b: co-performance in the live room

Stacked on #410 (CO4, wai.live.coperformance). Until #410 merges this PR carries its commits; once it does, origin/main is merged in (one ordinary merge) and the diff is this slice alone. CO4 specified the extension, implemented its verifier, made the relay drop out-of-turn media under refuse, and gave the room service a [co] config. This PR makes it work in the live room.

What is in it

1. The room clock signs (joule-moq-room, new src/co.rs, src/http.rs, src/epoch.rs, src/lib.rs).

  • In a room with [co], the clock records each audience member joining when its events track appears (a viewer whose grant carries audience_input, kept within max_present), follows every member's events track (FETCH where a chain has a gap) and each publisher's audio and video, and holds the room as a verifier does.
  • It logs every object it takes: arrival = the instant it received the object from the relay, due = the envelope's target.timestamp_us (which the page states on the room clock), track = the anchor digest. GET /co/objects serves the log: the objects §9.1 gives a verifier.
  • Marks (WPM1): an object out of turn under a schedule that marks, or later than its publisher's budget while that publisher's grant is in effect, is marked as the clock takes it, in order, within the clock's event rate (40 a second, under the authority policy's 50).
  • Commitments and selections (WPC1, WPS1): once a window has closed and commit_after_ms has passed, the clock commits to the eligible inputs and signs the selection under the window's rule with its credits. A draw's seed is drawn by the clock when the window opens and kept until the selection.
  • Fidelity (WPF1): every fidelity_every_s, and when a lead asks, stated through an instant 5 s behind the clock's own, after every mark it owes is signed.
  • POST /co/schedule, /co/handover, /co/window, /co/fidelity: authorised by the caller's grant with its proof of possession over HTTP (live-rooms §10.5.3: Authorization: Bearer, WAI-Room-Proof, single-use WAI-Room-Challenge on a 401 and on every accepted answer; context = method + //host + public_prefix + path). Schedule, window and fidelity need the direct power. A handover needs the turn's holder or the direct power. The clock signs each as a room key. GET /co/state is for tests and operators.
  • Roles: in a co room a publisher may send meta (its intents). A third role lead (participant + direct power) goes to the first publisher ([co] lead = "first" | "publishers" | "none"). A publisher may ask for an AI participant's grant ("ai": <model digest>, [co] ai).
  • New [co] fields: lead, ai, fidelity_every_s, commit_after_ms, lead_ms, max_objects. New top-level field: public_prefix. relay-lines prints the relay's [floor] lines commented out.

2. What the clock signs is what the verifier recomputes (wai-rs co_performance).

  • replay(&Input) -> Replay runs §9.2 steps 1–4.
  • Replay gives:
    • commitment(w, t), selection(w, seed), fidelity(through, t), marks_for(o), budget_at, windows(), policy_at;
    • an owned FloorBook (place, turn_at).
  • verify now runs on the same replay: it was split, not rewritten. The corpus regenerates byte for byte and every vector keeps its outcome.

3. The relay refuses invalid audience inputs (joule-moq-relay floor.rs, session.rs, summary.rs; joule-moq GrantHead).

  • Before an events-track object is forwarded or cached, each WPA1 on its author's own track is held to §7.3, using the grant that author's session proved. Each refusal has a reason code:
    • bad_signature (the signature fails);
    • co_statement_malformed (it does not read);
    • input_not_permitted (no grant with audience_input);
    • window_unknown (no window by a room key or a director);
    • window_committed (the window's commitment has been forwarded);
    • input_type_mismatch (a type or option the window does not take);
    • input_over_limit (past the grant's audience_input);
    • rate_exceeded (past the grant policy's rate window).
  • A refused record is withheld from every object that carries it, including a group's repeated join set, and is never replaced. Windows (WPW1) and commitments (WPC1) are read from the same tracks.
  • Session summaries count co_refused by reason and refused_out_of_turn. Both are skipped when zero, so other summaries are byte-identical to before.
  • GrantHead now reads a grant's attributes and its policy's max_events/window_us.

4. The room page performs (joule-moq-web/web/room/co.js new, app.js, index.html; wai-live-web src/co.rs; joule-moq-web grantProofHttp).

  • The page reads co.policy and co.audience, and verifies audience grants alongside publisher grants. In a co room it subscribes to every present principal's events.
  • A new section, in the page's existing tokens and layout, shows:
    • the floor: who holds it now, the turns ahead, and the marks;
    • what's next: each intent as an upcoming line, then kept, diverged or missed; an AI participant is labelled "(AI system)";
    • the audience: the open window's question, option buttons or a prompt box for a viewer whose grant allows it, and inputs left;
    • each selection with its credits;
    • the clock's fidelity statement.
  • Lead controls: Start turns (seconds, turns, marked or refused), Pass the floor (also shown to the current holder), Open a vote, Ask for prompts, State fidelity.
  • In a co room a performer:
    • states its media timestamps on the room clock. Video uses an offset from the capture clock. Audio is read from the inputs its encoder took, because an audio encoder numbers its output by the samples taken, which would lose a stretch held back.
    • sends media only while it holds the floor, from 150 ms after its turn starts to 150 ms before it ends; the first video frame back is a key frame.
  • ai=scripted makes the page a demo AI participant: an AI grant, a drawn canvas and a tone as its media, and a scripted line announced 2 s before each one it says as a machine's caption; every third line it says differently. script=off leaves the lines to a test. The demo uses a scripted source, not the spectral generator.
  • wai-live-web adds coStatement, coEventStatement, coEncode (a page's intents, inputs and handovers), coPolicy and Room.coVerify. On the host, wai_live_web co-verify <room.json> <co.json> prints the same verification in the corpus's form.

5. e2e (joule-moq-web/e2e/room.e2e.mjs, scenario co, the host's installed browser driven by the automation package, domcontentloaded): see the checks below.

6. Spec (co-performance.md). The amendments state only what the room service and relay now do:

  • §7.3: a relay also refuses an input that names a window whose commitment it has forwarded, and withholds a refused input as live-moderation §8.1 does.
  • §8:
    • a relay SHOULD count what it held back;
    • how a room clock that is a session of its own on the relay takes arrivals and signs marks;
    • when the clock commits and when it states fidelity;
    • how a room key states a statement a participant asks for.
  • §9.1: a performer states due as its object's timestamp on the room clock.
  • §12: the hop between the relay's arrival and the clock's.
  • SPEC §5 paragraph and CHANGELOG entry.
  • No new record or reason code. §10 is unchanged and so is the corpus; co_performance_verify.py passes as before.

Design decisions, and why

  • The clock observes arrivals itself. Its log is the §9.1 objects, so marking and verification use the same instants: a room that marks verifies with no turn_unmarked/late_unflagged. The relay's own arrival is a hop earlier. Under refuse, an object the relay admitted within that hop of a turn's end can appear out of turn in the clock's log. The page's turn guard prevents this in practice, and §8/§12 say so.
  • Pages ask the clock; the clock signs. The lead asked for schedules, handovers and windows to be signed by the room service. The clock signs them as a room key, authorised by the requester's grant and powers through live-rooms §10.5.3's HTTP proof, which the repo already had. The clock refreshes its floor before the instant a statement governs (lead_ms ahead).
  • window_committed is a relay label, not a §10 reason. A verifier never sees it. Without it, a member could backdate an input after the commitment and break commit_mismatch for every verifier.
  • Lateness counts only while the publisher's grant is in effect. This follows §9.1's grant-in-effect rule; the first e2e run caught a mark on an object that arrived before the publisher's join.
  • Owner rule: no consent step; §12 already points to the lawful-basis claim class (jwp-receipts §2.4.6).

Checks run (all on the build host via rb, except the light repo checks)

check command result
wai-rs co tests cargo test --locked --no-default-features --features co_performance --lib co_performance:: and --test co_performance 6 + 5 passed (new: the_clock_signs_what_the_verifier_recomputes, the_clock_keeps_to_the_commitment_and_the_seed)
wai-live-web cargo test --locked --lib 5 passed (new: statements read and signed; corpus verified through the crate)
joule-moq cargo test --locked -p joule-moq --lib 85 passed (new: grant head attributes and rate window)
joule-moq-relay cargo test --locked -p joule-moq-relay --all-targets all passed (new: audience_inputs_are_held_to_section_7_3, the_relay_refuses_invalid_audience_inputs)
joule-moq-web native cargo test --locked -p joule-moq-web 8 passed (HTTP proof binding)
joule-code workspace cargo check --locked --workspace --all-targets ok
joule-moq-room cargo test --locked --all-targets all passed (new: tests/co_performance.rs, a co room end to end against a floor-holding relay, verified accept; example config reads)
clippy --all-targets on wai-rs (co_performance), wai-live-web, joule-moq/-relay/-web, joule-moq-room no notes in code this PR adds; the remaining notes are pre-existing (epoch.rs:650 test, session.rs:311, wai-rs unpinned_read)
lockfiles cargo metadata --locked --offline in wai-rs, wai-live-web, joule-code-rs, joule-moq-room all ok; no lockfile changed
browser e2e co e2e/run.sh --only co --runs 3 3 of 3 runs, 87 of 87 checks
browser e2e service,co e2e/run.sh --only service,co --runs 4 4 of 4 runs, 280 of 280 checks
browser e2e full suite e2e/run.sh 1 of 1 run, 187 of 187 checks (compose, webtransport, websocket, goaway, dvr, service, e2ee, co). An earlier run had shown a service-scenario flake this change introduced (a page laying the room out at its own instant, a moment behind a lifecycle event once its clock took the service's); fixed (1b1d1575c), then service+co 4 of 4
repo checks check-tests-in-ci.py, check-workflow-concurrency.sh, check-spec-refs.py, check-wai-section-refs.py, check-no-vanity-metrics.sh, test-public-text-checks.sh, check-comparative-prose.sh, check-orphan-sources.py all pass
second implementation python3 -I wai/live-conformance/co_performance_verify.py wai/live-conformance/coperformance PASS, 42 rooms

What the co scenario checks:

  • everyone is in one room; the page reads the policy; only the lead sees the lead's controls; the AI participant is labelled as an AI system;
  • the schedule the lead starts from its page is signed by the clock, and every page shows who holds the floor;
  • playing out of turn for half a second under mark is marked by the clock;
  • the AI's next line shows as upcoming before it plays; one line is kept, one diverged; a late object is marked late;
  • the input box counts inputs against the member's power;
  • the relay refuses five kinds of invalid input (input_over_limit, window_unknown, input_type_mismatch, co_statement_malformed, input_not_permitted), and no page receives any of them;
  • the vote is committed (4 inputs) and the plurality selected, credited to its voters together; a drawn prompt is shown with its author's credit;
  • under the later refuse schedule, the relay holds back the out-of-turn objects (about 100 per run);
  • the lead's fidelity statement shows "kept 1 of 2";
  • the room as an audience member's page holds it, with the clock's log of objects, verifies accept, and the page's Room.coVerify output is identical to the host's wai_live_web co-verify; every out-of-turn and late object is marked; intents, fidelity and both windows' picks recompute;
  • the relay's summaries count each refused input by reason; no page reports an error.

Falsifications (committed first; each mutation made on the build host's copy, test exit status recorded, then restored)

mutation test result
the clock signs no marks joule-moq-room tests/co_performance.rs exit 101: Refuse { at: Object(1), reason: TurnUnmarked }
the clock marks nothing late same exit 101
the service takes a request without its proof same exit 101 (the pop_missing assertion)
the relay forwards every input relay tests/floor.rs exit 101
the relay ignores commitments relay floor::tests exit 101
the clock commits one input too many wai-rs the_clock_signs_what_the_verifier_recomputes exit 101
the clock draws with the wrong seed same exit 101
(e2e) audio due from encoder timestamps the co scenario, first run lateness grew to 18 s, 1,600 marks, late_unflagged: fixed by reading inputs

The live room must be redeployed as one unit

The page assets, the relay and the room service must all come from this one commit:

  • A page at this commit stamps media on the room clock and gates media to its turns.
  • A relay at this commit reads windows and commitments and refuses inputs.
  • A room service at this commit follows members, logs objects, and serves /co/* and now_us.

A room service from before this commit and a page from this commit will not interoperate in a co room. With [co] off (the default) the room behaves as before.

What turns it on. Both are off by default:

  • room service: [co] audience_input = <1..255> and/or latency_budget_ms = <ms>, plus public_prefix = "/room-api" at the top level when the front strips that prefix;
  • relay: [floor] room_keys = ["<clock key>"] (the lines joule-moq-room relay-lines prints, commented out).

Site (wai-transaction-science-web, not touched here):

  • scripts/sync-room.mjs must map the new client file: add "room/co.js": "room-co.js" to FILES, "room/co.js": {} to SPECIFIERS, and "./co.js": "./room-co.js" to SPECIFIERS["room/app.js"]. No other new relative import.
  • The WebAssembly packages rebuild from this commit: wai_live_web gains co_performance, joule_moq_web gains grantProofHttp.
  • The site's src/pages/room.astro has its own markup and needs the co section's elements for the page to show it: co, co-now, co-turns, co-marks, co-pass, co-intents, co-question, co-input, co-options, co-prompt-row, co-prompt, co-left, co-selections, co-fidelity, and the lead controls co-lead, co-turn-s, co-turns-n, co-mode, co-start, co-q, co-options-n, co-window-s, co-vote, co-prompts, co-fid. Without them co.js renders nothing (no error).

Not done / open

  • Credits onto wai.media.contribution steps. CO1 (#403) is merged, but this branch is stacked on #410 and has not merged main. The selection's credits still map onto the contribution slot only in prose (§7.8), not as written contribution records.
  • One mark per object can outrun the clock's rate. The clock signs at most 40 events a second. A performer late on every object (50 audio objects a second) gets its marks signed behind; they arrive eventually, but not in real time. A ranged mark would need a spec change.
  • The relay keeps no arrival log. Under refuse, a verifier that wants the relay's own arrivals has none; the clock's log is the one served.
  • No reactions UI. The reactions rule works in the clock and verifier, but the page has no reaction buttons on inputs.
  • No symbolic tracks. The demo AI participant does not use the spectral generator. Notes and camera intents need symbolic payload tracks, which live-rooms §6.1 does not name; the page announces text intents only.
  • Nothing deployed.

🤖 Generated with Claude Code


Closed: Landed in #428 (merge train, merged as aa61ab3b with all 65 checks green).

## CO4b: co-performance in the live room Stacked on #410 (CO4, `wai.live.coperformance`). Until #410 merges this PR carries its commits; once it does, `origin/main` is merged in (one ordinary merge) and the diff is this slice alone. CO4 specified the extension, implemented its verifier, made the relay drop out-of-turn media under `refuse`, and gave the room service a `[co]` config. This PR makes it work in the live room. ### What is in it **1. The room clock signs** (`joule-moq-room`, new `src/co.rs`, `src/http.rs`, `src/epoch.rs`, `src/lib.rs`). - In a room with `[co]`, the clock records each audience member joining when its events track appears (a viewer whose grant carries `audience_input`, kept within `max_present`), follows every member's events track (FETCH where a chain has a gap) and each publisher's audio and video, and holds the room as a verifier does. - It logs every object it takes: arrival = the instant it received the object from the relay, due = the envelope's `target.timestamp_us` (which the page states on the room clock), track = the anchor digest. `GET /co/objects` serves the log: the objects §9.1 gives a verifier. - Marks (`WPM1`): an object out of turn under a schedule that marks, or later than its publisher's budget while that publisher's grant is in effect, is marked as the clock takes it, in order, within the clock's event rate (40 a second, under the authority policy's 50). - Commitments and selections (`WPC1`, `WPS1`): once a window has closed and `commit_after_ms` has passed, the clock commits to the eligible inputs and signs the selection under the window's rule with its credits. A draw's seed is drawn by the clock when the window opens and kept until the selection. - Fidelity (`WPF1`): every `fidelity_every_s`, and when a lead asks, stated through an instant 5 s behind the clock's own, after every mark it owes is signed. - `POST /co/schedule`, `/co/handover`, `/co/window`, `/co/fidelity`: authorised by the caller's grant with its proof of possession over HTTP (live-rooms §10.5.3: `Authorization: Bearer`, `WAI-Room-Proof`, single-use `WAI-Room-Challenge` on a 401 and on every accepted answer; context = method + `//host` + `public_prefix` + path). Schedule, window and fidelity need the direct power. A handover needs the turn's holder or the direct power. The clock signs each as a room key. `GET /co/state` is for tests and operators. - Roles: in a co room a publisher may send `meta` (its intents). A third role `lead` (participant + direct power) goes to the first publisher (`[co] lead = "first" | "publishers" | "none"`). A publisher may ask for an AI participant's grant (`"ai": <model digest>`, `[co] ai`). - New `[co]` fields: `lead`, `ai`, `fidelity_every_s`, `commit_after_ms`, `lead_ms`, `max_objects`. New top-level field: `public_prefix`. `relay-lines` prints the relay's `[floor]` lines commented out. **2. What the clock signs is what the verifier recomputes** (`wai-rs` `co_performance`). - `replay(&Input) -> Replay` runs §9.2 steps 1–4. - `Replay` gives: - `commitment(w, t)`, `selection(w, seed)`, `fidelity(through, t)`, `marks_for(o)`, `budget_at`, `windows()`, `policy_at`; - an owned `FloorBook` (`place`, `turn_at`). - `verify` now runs on the same replay: it was split, not rewritten. The corpus regenerates byte for byte and every vector keeps its outcome. **3. The relay refuses invalid audience inputs** (`joule-moq-relay` `floor.rs`, `session.rs`, `summary.rs`; `joule-moq` `GrantHead`). - Before an events-track object is forwarded or cached, each `WPA1` on its author's own track is held to §7.3, using the grant that author's session proved. Each refusal has a reason code: - `bad_signature` (the signature fails); - `co_statement_malformed` (it does not read); - `input_not_permitted` (no grant with `audience_input`); - `window_unknown` (no window by a room key or a director); - `window_committed` (the window's commitment has been forwarded); - `input_type_mismatch` (a type or option the window does not take); - `input_over_limit` (past the grant's `audience_input`); - `rate_exceeded` (past the grant policy's rate window). - A refused record is withheld from every object that carries it, including a group's repeated join set, and is never replaced. Windows (`WPW1`) and commitments (`WPC1`) are read from the same tracks. - Session summaries count `co_refused` by reason and `refused_out_of_turn`. Both are skipped when zero, so other summaries are byte-identical to before. - `GrantHead` now reads a grant's attributes and its policy's `max_events`/`window_us`. **4. The room page performs** (`joule-moq-web/web/room/co.js` new, `app.js`, `index.html`; `wai-live-web` `src/co.rs`; `joule-moq-web` `grantProofHttp`). - The page reads `co.policy` and `co.audience`, and verifies audience grants alongside publisher grants. In a co room it subscribes to every present principal's events. - A new section, in the page's existing tokens and layout, shows: - the floor: who holds it now, the turns ahead, and the marks; - what's next: each intent as an upcoming line, then kept, diverged or missed; an AI participant is labelled "(AI system)"; - the audience: the open window's question, option buttons or a prompt box for a viewer whose grant allows it, and inputs left; - each selection with its credits; - the clock's fidelity statement. - Lead controls: Start turns (seconds, turns, marked or refused), Pass the floor (also shown to the current holder), Open a vote, Ask for prompts, State fidelity. - In a co room a performer: - states its media timestamps on the room clock. Video uses an offset from the capture clock. Audio is read from the inputs its encoder took, because an audio encoder numbers its output by the samples taken, which would lose a stretch held back. - sends media only while it holds the floor, from 150 ms after its turn starts to 150 ms before it ends; the first video frame back is a key frame. - `ai=scripted` makes the page a demo AI participant: an AI grant, a drawn canvas and a tone as its media, and a scripted line announced 2 s before each one it says as a machine's caption; every third line it says differently. `script=off` leaves the lines to a test. The demo uses a scripted source, not the spectral generator. - `wai-live-web` adds `coStatement`, `coEventStatement`, `coEncode` (a page's intents, inputs and handovers), `coPolicy` and `Room.coVerify`. On the host, `wai_live_web co-verify <room.json> <co.json>` prints the same verification in the corpus's form. **5. e2e** (`joule-moq-web/e2e/room.e2e.mjs`, scenario `co`, the host's installed browser driven by the automation package, `domcontentloaded`): see the checks below. **6. Spec** (`co-performance.md`). The amendments state only what the room service and relay now do: - §7.3: a relay also refuses an input that names a window whose commitment it has forwarded, and withholds a refused input as live-moderation §8.1 does. - §8: - a relay SHOULD count what it held back; - how a room clock that is a session of its own on the relay takes arrivals and signs marks; - when the clock commits and when it states fidelity; - how a room key states a statement a participant asks for. - §9.1: a performer states due as its object's timestamp on the room clock. - §12: the hop between the relay's arrival and the clock's. - SPEC §5 paragraph and CHANGELOG entry. - No new record or reason code. §10 is unchanged and so is the corpus; `co_performance_verify.py` passes as before. ### Design decisions, and why - **The clock observes arrivals itself.** Its log is the §9.1 objects, so marking and verification use the same instants: a room that marks verifies with no `turn_unmarked`/`late_unflagged`. The relay's own arrival is a hop earlier. Under `refuse`, an object the relay admitted within that hop of a turn's end can appear out of turn in the clock's log. The page's turn guard prevents this in practice, and §8/§12 say so. - **Pages ask the clock; the clock signs.** The lead asked for schedules, handovers and windows to be signed by the room service. The clock signs them as a room key, authorised by the requester's grant and powers through live-rooms §10.5.3's HTTP proof, which the repo already had. The clock refreshes its floor before the instant a statement governs (`lead_ms` ahead). - **`window_committed` is a relay label, not a §10 reason.** A verifier never sees it. Without it, a member could backdate an input after the commitment and break `commit_mismatch` for every verifier. - **Lateness counts only while the publisher's grant is in effect.** This follows §9.1's grant-in-effect rule; the first e2e run caught a mark on an object that arrived before the publisher's join. - **Owner rule:** no consent step; §12 already points to the `lawful-basis` claim class (jwp-receipts §2.4.6). ### Checks run (all on the build host via `rb`, except the light repo checks) | check | command | result | |---|---|---| | wai-rs co tests | `cargo test --locked --no-default-features --features co_performance --lib co_performance::` and `--test co_performance` | 6 + 5 passed (new: `the_clock_signs_what_the_verifier_recomputes`, `the_clock_keeps_to_the_commitment_and_the_seed`) | | wai-live-web | `cargo test --locked --lib` | 5 passed (new: statements read and signed; corpus verified through the crate) | | joule-moq | `cargo test --locked -p joule-moq --lib` | 85 passed (new: grant head attributes and rate window) | | joule-moq-relay | `cargo test --locked -p joule-moq-relay --all-targets` | all passed (new: `audience_inputs_are_held_to_section_7_3`, `the_relay_refuses_invalid_audience_inputs`) | | joule-moq-web native | `cargo test --locked -p joule-moq-web` | 8 passed (HTTP proof binding) | | joule-code workspace | `cargo check --locked --workspace --all-targets` | ok | | joule-moq-room | `cargo test --locked --all-targets` | all passed (new: `tests/co_performance.rs`, a co room end to end against a floor-holding relay, verified accept; example config reads) | | clippy | `--all-targets` on wai-rs (co_performance), wai-live-web, joule-moq/-relay/-web, joule-moq-room | no notes in code this PR adds; the remaining notes are pre-existing (`epoch.rs:650` test, `session.rs:311`, wai-rs `unpinned_read`) | | lockfiles | `cargo metadata --locked --offline` in wai-rs, wai-live-web, joule-code-rs, joule-moq-room | all ok; no lockfile changed | | browser e2e `co` | `e2e/run.sh --only co --runs 3` | 3 of 3 runs, 87 of 87 checks | | browser e2e `service,co` | `e2e/run.sh --only service,co --runs 4` | 4 of 4 runs, 280 of 280 checks | | browser e2e full suite | `e2e/run.sh` | 1 of 1 run, 187 of 187 checks (compose, webtransport, websocket, goaway, dvr, service, e2ee, co). An earlier run had shown a service-scenario flake this change introduced (a page laying the room out at its own instant, a moment behind a lifecycle event once its clock took the service's); fixed (`1b1d1575c`), then service+co 4 of 4 | | repo checks | `check-tests-in-ci.py`, `check-workflow-concurrency.sh`, `check-spec-refs.py`, `check-wai-section-refs.py`, `check-no-vanity-metrics.sh`, `test-public-text-checks.sh`, `check-comparative-prose.sh`, `check-orphan-sources.py` | all pass | | second implementation | `python3 -I wai/live-conformance/co_performance_verify.py wai/live-conformance/coperformance` | PASS, 42 rooms | What the `co` scenario checks: - everyone is in one room; the page reads the policy; only the lead sees the lead's controls; the AI participant is labelled as an AI system; - the schedule the lead starts from its page is signed by the clock, and every page shows who holds the floor; - playing out of turn for half a second under `mark` is marked by the clock; - the AI's next line shows as upcoming before it plays; one line is kept, one diverged; a late object is marked late; - the input box counts inputs against the member's power; - the relay refuses five kinds of invalid input (`input_over_limit`, `window_unknown`, `input_type_mismatch`, `co_statement_malformed`, `input_not_permitted`), and no page receives any of them; - the vote is committed (4 inputs) and the plurality selected, credited to its voters together; a drawn prompt is shown with its author's credit; - under the later `refuse` schedule, the relay holds back the out-of-turn objects (about 100 per run); - the lead's fidelity statement shows "kept 1 of 2"; - the room as an audience member's page holds it, with the clock's log of objects, verifies **accept**, and the page's `Room.coVerify` output is identical to the host's `wai_live_web co-verify`; every out-of-turn and late object is marked; intents, fidelity and both windows' picks recompute; - the relay's summaries count each refused input by reason; no page reports an error. ### Falsifications (committed first; each mutation made on the build host's copy, test exit status recorded, then restored) | mutation | test | result | |---|---|---| | the clock signs no marks | joule-moq-room `tests/co_performance.rs` | exit 101: `Refuse { at: Object(1), reason: TurnUnmarked }` | | the clock marks nothing late | same | exit 101 | | the service takes a request without its proof | same | exit 101 (the `pop_missing` assertion) | | the relay forwards every input | relay `tests/floor.rs` | exit 101 | | the relay ignores commitments | relay `floor::tests` | exit 101 | | the clock commits one input too many | wai-rs `the_clock_signs_what_the_verifier_recomputes` | exit 101 | | the clock draws with the wrong seed | same | exit 101 | | (e2e) audio due from encoder timestamps | the `co` scenario, first run | lateness grew to 18 s, 1,600 marks, `late_unflagged`: fixed by reading inputs | ### The live room must be redeployed as one unit The page assets, the relay and the room service must all come from **this one commit**: - A page at this commit stamps media on the room clock and gates media to its turns. - A relay at this commit reads windows and commitments and refuses inputs. - A room service at this commit follows members, logs objects, and serves `/co/*` and `now_us`. A room service from before this commit and a page from this commit will not interoperate in a co room. With `[co]` off (the default) the room behaves as before. **What turns it on.** Both are off by default: - room service: `[co] audience_input = <1..255>` and/or `latency_budget_ms = <ms>`, plus `public_prefix = "/room-api"` at the top level when the front strips that prefix; - relay: `[floor] room_keys = ["<clock key>"]` (the lines `joule-moq-room relay-lines` prints, commented out). **Site** (`wai-transaction-science-web`, not touched here): - `scripts/sync-room.mjs` must map the new client file: add `"room/co.js": "room-co.js"` to `FILES`, `"room/co.js": {}` to `SPECIFIERS`, and `"./co.js": "./room-co.js"` to `SPECIFIERS["room/app.js"]`. No other new relative import. - The WebAssembly packages rebuild from this commit: `wai_live_web` gains `co_performance`, `joule_moq_web` gains `grantProofHttp`. - The site's `src/pages/room.astro` has its own markup and needs the co section's elements for the page to show it: `co`, `co-now`, `co-turns`, `co-marks`, `co-pass`, `co-intents`, `co-question`, `co-input`, `co-options`, `co-prompt-row`, `co-prompt`, `co-left`, `co-selections`, `co-fidelity`, and the lead controls `co-lead`, `co-turn-s`, `co-turns-n`, `co-mode`, `co-start`, `co-q`, `co-options-n`, `co-window-s`, `co-vote`, `co-prompts`, `co-fid`. Without them `co.js` renders nothing (no error). ### Not done / open - **Credits onto `wai.media.contribution` steps.** CO1 (#403) is merged, but this branch is stacked on #410 and has not merged main. The selection's credits still map onto the contribution slot only in prose (§7.8), not as written contribution records. - **One mark per object can outrun the clock's rate.** The clock signs at most 40 events a second. A performer late on every object (50 audio objects a second) gets its marks signed behind; they arrive eventually, but not in real time. A ranged mark would need a spec change. - **The relay keeps no arrival log.** Under `refuse`, a verifier that wants the relay's own arrivals has none; the clock's log is the one served. - **No reactions UI.** The `reactions` rule works in the clock and verifier, but the page has no reaction buttons on inputs. - **No symbolic tracks.** The demo AI participant does not use the spectral generator. Notes and camera intents need symbolic payload tracks, which live-rooms §6.1 does not name; the page announces text intents only. - **Nothing deployed.** 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- **Closed:** Landed in #428 (merge train, merged as aa61ab3b with all 65 checks green).
The extension text (extensions/co-performance.md), the reference module
(wai-rs feature co_performance) and its corpus generator: the room
authority's WPP1 policy; intents compared with what played under pinned
rules and the clock's fidelity statement recomputed; turn schedules in
microseconds or bars, call-and-response pairs, handovers, the floor,
latency budgets and marks; audience inputs to selection windows, the
commitment, three selection rules and their credits.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Written from extensions/co-performance.md alone: the policy, statements,
intents and their pinned rules, the fidelity statement, schedules,
handovers, the floor, budgets and marks, windows, inputs, commitments,
the three rules and the credits. Each room through live_rooms_verify.py;
mutated copies of the corpus must each fail.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The verifier is weakened on purpose, one check at a time, and the corpus
must catch each weakened copy. Room verifications are cached by their
inputs, since they do not depend on the checks dropped. The extension
names the window's, the fidelity statement's and the credit's malformed
values explicitly.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The capability and its ten magics in the reference registry, and the
export regenerated (registry/capabilities.json, vocab/v2.ttl and
REGISTRY.md's table); SPEC §5's paragraph and record list; the corpus's
README with its provenance; the live-conformance index; the sidecar
exclusion's reason for live-conformance; and a step in the independent
verifiers job that runs the module's unit tests, tests/co_performance.rs
and co_performance_verify.py, with the extension in the workflow's paths.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Clippy's type_complexity and too_many_arguments notes, cleared without an
allow.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A [co] section of the service's configuration: with audience_input above
0, every viewer's grant carries the attribute audience_input and may send
meta events and reactions, and the viewers' grants are served with the
room (co.audience) so a page verifies their inputs; with
latency_budget_ms above 0, every publisher's grant carries it. Either
gives each room a WPP1 policy the authority signs (co.policy). A unit
test checks the grants and the policy, and that two viewers' votes in a
window the clock opens, commits and selects verify as co-performance §9
verifies a room.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
joule-moq-relay: the floor of WAI rooms (co-performance §6)
All checks were successful
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m1s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m17s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 27s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m10s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 1m50s
wai-pack / wai-pack · linux (pull_request) Successful in 1m28s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m19s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m27s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m12s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 8m36s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 4m4s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 31s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 1m7s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 47s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m19s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 19m36s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m12s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 12m40s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 9m9s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 29s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 2m14s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 37m47s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m52s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 13m30s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 19s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 46s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 5m49s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 3m28s
wai-pack / wai-pack · macos (pull_request) Successful in 1m9s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 2m19s
c6b3c09944
With [floor] in its configuration, the relay reads each room's turn
schedules (WPT1) and handovers (WPH1) from the events tracks it already
forwards, as it reads moderation decisions, and holds the floor: a media
object a performer publishes out of turn under a schedule that refuses is
not forwarded and is counted. A schedule is honoured from a room key (the
authorities' and the configured ones) or a principal whose session proved
a grant with the direct power, when it reads, verifies and changes no past;
a handover from the turn's holder, a director or a room key, to a holder
of its segment. Unit tests of the reading and the floor, and
tests/floor.rs through a relay on loopback: the object in turn reaches the
subscriber, the other does not, and a handover passes the floor.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
joule-moq-relay, joule-moq-room: clippy's notes on this change
Some checks failed
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m24s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m2s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 33s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m9s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 1m55s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m29s
wai-pack / wai-pack · linux (pull_request) Successful in 1m19s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 3m43s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m56s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 10m26s
wai-quantum studio and desktop / desktop app · macos (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Has been cancelled
3f115a3da4
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dcharlot closed this pull request 2026-10-22 12:02:29 -04:00
Some checks failed
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 5s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 4s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 5s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 2m38s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m34s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m40s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m34s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 2m14s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 7s
WAI conformance / does this change touch it (pull_request) Successful in 5s
WAI energy receipts / does this change touch it (pull_request) Successful in 5s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 1m52s
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Successful in 5s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 5s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 5s
wai-web wasm32 / does this change touch it (pull_request) Successful in 6s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m24s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m2s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 33s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m9s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 1m55s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m29s
wai-pack / wai-pack · linux (pull_request) Successful in 1m19s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 3m43s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m56s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 10m26s
wai-quantum studio and desktop / desktop app · macos (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!424
No description provided.