live room train D: co-watch rooms, the room's own service under age rules, same-origin room endpoints (#432) #451

Merged
dcharlot merged 21 commits from train/live-room-d into main 2026-10-25 00:42:25 -04:00

2026-10-24

Transaction Science
relay tests: wait on what the relay holds, not on fixed sleeps and windows
All checks were successful
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 28s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 11m8s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m52s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 2m18s
wai-pack / wai-pack · linux (pull_request) Successful in 1m44s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m55s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 6m11s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m38s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 3m48s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 15s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 12s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 26s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 1m30s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 7m19s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 10m55s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m12s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 15m12s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 18s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m10s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 3m51s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 8m51s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 13m38s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 21s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 49s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 4m51s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 41m53s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 5m9s
wai-pack / wai-pack · macos (pull_request) Successful in 1m12s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 2m23s
floor.rs `the_relay_refuses_invalid_audience_inputs` failed under load (2 of 10
runs at load ~40-70), and not for want of readiness: the window was held and
the subscriptions live. The relay forwarded the member's *second* vote and
refused the first `input_over_limit`. Each group rides a stream of its own,
which the relay reads in a task of its own, so two votes sent back to back
can be taken in either order, and the limit counts them in the order taken.

- floor.rs (inputs): the fixed 300 ms sleep becomes `Floor::holds_window`
  (new, minimal), and the second vote is sent once the watcher has the first,
  which proves its subscription live. The refusals are waited for by
  `refused_inputs()`, then a second of quiet catches anything forwarded wrongly.
- floor.rs (the floor): the 3 s collect windows wait for the object in turn and
  for `refused()`, then a second of quiet.
- age_serving, age_rising, age_room_service: each collect waits for every group
  it expects, since the groups arrive on their own streams in any order,
  rather than for the last group alone.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 20:59:10 -04:00

2026-10-22

Transaction Science
Merge remote-tracking branch 'origin/main' into train/live-room-d
Some checks failed
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m24s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 23m59s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 8s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 37s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 9s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 7s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m44s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 2m58s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 4m39s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m34s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m24s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 30s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m18s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 2m41s
wai-pack / wai-pack · linux (pull_request) Successful in 1m36s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 51m44s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m47s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 20m32s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m52s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m36s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m51s
standards workspaces build + test / macOS energy backends (pull_request) Failing after 4m55s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 12m17s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 17s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 40s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m55s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 3m50s
wai-pack / wai-pack · macos (pull_request) Successful in 58s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 1m58s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 10m4s
2026-10-22 12:59:09 -04:00
Transaction Science
joule-moq-room: the lock file follows wai-quantum 0.6.14 from main
Main's wai-quantum 0.6.14 release updated every lock that carries it but this
one (wai-rs's optional dependency reaches it), so `cargo build --locked` of the
room service refused to run after the merge. Resolved with `cargo metadata`:
the one version line changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 12:40:14 -04:00
Transaction Science
room page: take the endpoints a link names only on the page's own origin
The room client took its relay, room service, fixture, WebTransport URL,
certificate hashes and issuer directory from its query string as given, and
followed a relay's GOAWAY to any URI. A crafted link and a press of Join would
send a joiner's camera and microphone to another origin.

- web/room/endpoint.js: an endpoint is taken only on the page's own origin
  (`https://<host>`, or `wss://<host>` for a relay), never with user
  information; a page served from the loopback interface (a fixture page, the
  e2e harness) takes loopback addresses alone.
- app.js: `service`, `ws`, `wt`, `fixture` and `issuer_directory` are held to
  it; `hashes` only on a loopback page. A refused endpoint is recorded
  (`snapshot().refused`) and shown, Join stays off, and the page connects to
  nothing: `enter()` checks the relay before it asks for the camera, a grant or
  a session. A GOAWAY naming another origin is refused: the page closes its
  session and says so.
- web/room/endpoint.test.mjs (run by e2e/run.sh): own origin, another origin,
  scheme-relative, the page's host as user information, javascript:, a plain
  scheme on a secure page, an HTTP page, and loopback for the harness.
- e2e scenario `origin`: a foreign `?ws=` is refused at Join and nothing
  connects (no WebSocket, request, grant or camera); a foreign `?service=`,
  scheme-relative, behind user information or as javascript:, is refused with
  Join off; a GOAWAY to another origin is refused and the session ends. The
  `service` scenario checks that every request and WebSocket of every page
  stays on the page's origin, as the production `connect-src` requires.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 12:38:31 -04:00
Transaction Science
2026-10-22 07:56:41 -04:00
Transaction Science
joule-moq: the rating vectors test reads the room-service requests
tests/rating_vectors.rs reads every request of the age corpus's serving cases.
The new `room_service` case gives some of them a session's proof of a room key
(age-assurance §5.5): checked here as the relay checks it in SETUP, with the
room's authority and clock as the room keys, and held to the corpus's outcome
(the room's own service, served by threshold, or refused with the proof's
reason).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 07:36:25 -04:00
Transaction Science
age × co: the room's own service is not held to the serving rule
A room with both `[age]` and `[co]` broke: co-performance's clock follows and
logs every performer's objects over a relay session of its own, which holds no
grant and no token, so age-assurance §5.5 served it nothing rated.

- age-assurance §5.5: a session that proves possession of a room key (the
  authority's or the clock's) is the room's own service, served every object of
  the room. The proof is a GRANT_PROOF naming no grant (32 bytes of zero) over
  the session's challenge, checked as live-rooms §10.5.4 checks a proof; one
  that does not pass refuses the session with that section's reason; one that
  passes by a key that is no room key gives nothing. Co-performance §8 points
  to it; §11 and §12 name the reasons and the new vectors.
- joule-moq: `grant_proof::NO_GRANT`, `add_room_key_proof`, `room_key_proofs`.
- joule-moq-relay: SETUP checks room-key proofs; a session proving a key the
  relay holds as a room key (an authority's, for its rooms; `[floor]` or `[dvr]`
  room keys, for every room) has `SessionCtx::service`, and its threshold there
  is past every age. `ClientOptions::room_keys` presents such proofs.
  tests/age_room_service.rs: a room rated 18 with the floor held; the clock's
  and the authority's proofs served every group, the clock's token alone and a
  non-room key refused `below_threshold`, a forged clock proof and one over
  another challenge closed UNAUTHORIZED.
- joule-moq-room: the clock's session proves both room keys it holds.
- wai-rs `age_assurance::room_service`, the corpus case `room_service`, and
  `age_assurance_verify.py` taught the rule, with three new checks and four
  mutations, all caught.
- e2e: scenario `ageco`, a room with both `[age]` and `[co]`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 07:08:25 -04:00
Transaction Science
room page: close the co-performance section, and test the page's markup
Train B's merge of #424 (co-performance in the room) with #413 (the browser
sink, 173981739) left `<section id="co">` without its `</section>`: the page
opened five sections and closed four. The parser then nested the binding table
(`#binding-debug`) and the Log inside the hidden `#co`, so in a room without
co-performance neither ever showed.

- index.html: the `</section>` after the `#co-lead` controls.
- web/room/markup.test.mjs (run by e2e/run.sh): every element the page opens is
  closed in order; the Log, the binding table and the co-watch section are not
  inside `#co`; each mode's controls are inside its own section.
- e2e: in the service scenario (a room without `[co]`), `#log`, `#binding-debug`
  and `#cowatch` are not descendants of `#co`, `#co` is hidden and the Log shows;
  in the cowatch scenario, the co-watch section and the Log show outside `#co`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 06:50:13 -04:00
Transaction Science
Merge #432 (co-watch) into the live-room train
Co-watch merged by meaning onto the integrated live room (#428):

- joule-moq-room: one config reader, `Config::settings()`, now fallible, carries
  `age`, `audience_input`, `latency_budget_ms`, `lead`, `ai` and the watch room's
  `watch` (from `watch_source`/`watch_duration_ms`), `watch_control` and
  `watch_window_ms`; one `public_prefix`. A watch room is refused together with
  `e2ee`, `[age]` or `[co]`.
- One path for the clock's records: co-performance's `Item` (`Life`/`Meta`) and
  `emit_items`, with the clock's rate kept; co-watch's skew statements go out as
  `emit_meta`, its leaves through `emit_after` (a least `t`), and every record of
  the clock's chain reaches the watch log through `watch_record`. The separate
  `Lifecycle::Meta` is dropped.
- Roles and grants: `meta` for participants in a room with co-performance or a
  watch room, `WATCHER_KINDS` for a watch room's viewers, `watch_control` the last
  attribute in key order.
- Page: the co-watch mode beside co-performance and the binding; the e2e suite
  gains `cowatch` and keeps every scenario; run.sh runs all five node test files.
- Workflows: each step whole, `paths:` unioned. CHANGELOG and REGISTRY rows
  kept from both; capabilities.json and v2.ttl regenerated by `registry export`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 05:26:53 -04:00
Transaction Science
co-watch: reflow two paragraphs of §8
Some checks failed
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (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 / does this change touch it (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (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 / does this change touch it (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (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 / quantum core and corpus under wasm32-wasip2 (wasmtime) (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 (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 / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 03:54:58 -04:00
Transaction Science
joule-moq-web: the room page's co-watch mode and its end-to-end scenario; joule-moq-room: a watch room over HTTP and the relay
The page fetches a watch room's source and checks it by its content hash, enters the room's
co-watch log by a proof of its key, applies each control at its instant, keeps the source at
the controlled position by the catch-up rule, states what it presents and shows the room's
sync. e2e scenario cowatch: three viewers, a play, a pause, a seek, a late joiner, the clock's
skew statements in sync within the bound, and the room verified by co_watch_verify.py. The room
service's test drives a watch room against a relay on loopback.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 03:31:07 -04:00
Transaction Science
joule-moq-room: watch rooms (WAI co-watch); joule-moq-web: the page's co-watch module
The room service serves a watch room's source, admits a viewer by a proof of its grant's key
over the service's challenge, carries its controls and presentation statements in a log when
co-watch §5 and §7.2 accept them, signs each window's skew statements and a viewer's leave
when it falls silent. web/room/cowatch.js holds the rules the page applies (the policy, the
controlled position, the catch-up rule, statements written byte for byte) and the player;
its tests run them against live-conformance/cowatch/.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 03:26:41 -04:00
Transaction Science
co_watch_verify.py: the co-watch corpus's second implementation, written from the extension's text
It verifies each room with live_rooms_verify.py, recomputes the controlled position, samples,
percentiles and verdicts from §5 to §9, requires every mutated copy of the corpus to fail and
catches each of its own checks dropped. Standard library only, run isolated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 03:14:35 -04:00
Transaction Science
wai.live.cowatch: co-watch rooms — controls at a room-clock instant, the controlled position, signed presentation statements and recomputed skew
The extension text (wai/extensions/co-watch.md), the co_watch module of wai-rs behind its own
feature, and the corpus live-conformance/cowatch/ written by wai_co_watch_vectors from fixed
seeds: three accepted rooms, a gap, and refused vectors covering every reason of §12.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 03:07:55 -04:00