joule-moq-relay: DVR on the relay, seek back by FETCH, and the seek power (L7b) #351

Merged
dcharlot merged 47 commits from joule-moq/dvr into main 2026-10-20 08:29:33 -04:00
Owner

L7b of WAI's live and interactive work: DVR on the relay. The relay keeps a configurable window of a room's tracks on disk, every object with its receipts. A viewer seeks back into it with MOQT FETCH, addressed as live-recording §8 says, and verifies recorded objects exactly as it verifies live ones.

What is in it

  • The DVR store (joule-moq-relay/src/dvr.rs):
    • Storage: per-track segment files, appended a whole group at a time and synced once a segment is sealed.
    • Window: a window per namespace prefix, by age and by bytes, evicting whole groups.
    • Restart: on start the relay reloads its index and checks every stored object against its stored receipt. An object that fails is dropped and counted, and never served.
    • Redactions (live-moderation): a redacted event record is erased from the stored object that carries it, and a redacted object is withheld from DVR reads.
  • FETCH below the live edge: served from the cache when the cache covers it, from the store when the store holds the group, and upstream otherwise (the existing rule).
    • Eviction is signalled with MOQT's End of Unknown Range through the last group no longer held.
    • Takes are addressed by live-recording §8's mapping (the window, answering from it, moderation, a restart, and the harvest window of §8.3).
  • Who may seek back: a new seek power in live-rooms (§10.6, with joining a group in progress as a fill, MOQT §3.5). The rooms corpus, live_rooms_verify.py and wai-rs live_room::seek_check cover it; the relay checks it on every FETCH below the live edge. joule-moq-room gives every role the power.
  • Metering: WMH1 version 2 adds a hop's DVR figures (bytes stored and served), with a version 2 corpus, its refusals, and live_metering_verify.py.
  • The browser client: a Seek back control in joule-moq-web/web/room, with its end-to-end scenario. joule-moq-ingest reads the seek power.
  • Docs: the relay README's DVR section and config, both CHANGELOGs, and SPEC §5 (the DVR window and the seek power).

Defects found and fixed while finishing (the builder stopped at the account's weekly limit)

  1. A relay panic. local_plan built a run of store-evicted groups by searching the cache from the run's first group, which the cache had already declined. The run then ended at g − 1: inverted, and at group 0 a subtraction overflow that panicked the session's task. The search now starts after g and skips cache-evicted groups. There are unit tests, shown failing under the old rule (exit 101).
  2. Gaps in the stored window under load. The store evicted by arrival time across groups, and moving the evicted mark removed only the victim. Groups finish, and are sealed, out of order under load, so a lower group could stay held below the mark: for example a window of [29, 32, 34, …]. Now each track evicts its lowest group first, moving the mark evicts every group at or below it in the track and its partner, and the writer refuses a seal below the mark when it writes it, not only when it was queued.
  3. Media cached without its receipts. The cache's byte budget evicted oldest first across tracks, and a group's receipts are cached before its media. So a media group could stay cached while its receipts group was gone, and a FETCH would serve media nothing could verify. A media group and its receipts group now leave the cache together. Evicting one moves the partner track's mark as well, even when the partner's group hasn't arrived yet, so a late partner is never served alone. This applies to every relay, not only DVR.
  4. Test fixes. The by-age test now waits until the relay has taken the last group before fetching. The e2e harness clears its results between runs (a second run's room-service keygen refused the first run's key file). A session that doesn't end is reported with its diagnostics.

Found while merging main: an end-to-end encrypted room was kept

L10 (#345) merged while this PR was being finished. Its confidentiality §9 says a room with a confidentiality record is never recorded, and "a relay keeps nothing of the room's tracks beyond delivery". The DVR store kept every track its prefix rules matched, sealed rooms included. Each slice was consistent alone, and the merge was clean apart from the changelog. Fixed here:

  • How the store recognises a sealed room. The store needs no key: a sealed object carries the secure-objects Key ID (SECURE_OBJECT_KEY_ID, confidentiality §4.3) in its properties. Properties that do not read count as sealed too.
  • What it does then. The first such group is never written. The store deletes what it already held of the room, since the room's events and receipts tracks are in the clear and can be whole before its first sealed group. It drops the room's decisions from decisions.wdl and writes nothing more of the room. Moderation still honours the room's decisions for what the cache delivers.
  • Restarts. The room is recorded in sealed.wdl (room(32) check(32)), so the store keeps refusing it after a restart. Every other room keeps its window.
  • Spec. live-recording §8.2 gains A room it never keeps, confidentiality §9 points to it, and SPEC §5 says so.
  • Test. a_sealed_room_is_never_kept runs a sealed room beside a clear room, before and after a restart. Falsified twice: with detection off it fails at the sealed-room wait, and with deletion off it fails at "… is kept" (exit 101 each).
  • The relay's write paths (the seal hand-off, the cache's keep-for-the-store rule, keep_late) now use Dvr::stores (a rule matches and the room is not sealed). keeps still decides which events tracks moderation reads.

Checks on the build host (rb, at c297283ff, after merging main)

The head after it, f8b199a65, rewords one sentence of live-metering §3.1. As a link, the sentence tripped the section-reference check (its [ matched the table's [start, end) interval), and "keeps none signs" matched the public-text check. The verifier and both checks pass on it.

run result
every Cargo.lock with cargo metadata --locked --offline all current (the vendored libwebrtc skipped, as check-lockfiles.sh does)
cargo test --all-targets of joule-moq-relay and joule-moq-ingest; joule-moq-web; joule-moq-room (its own workspace) 0 each, main's sealed_objects relay tests among them
cargo clippy of the relay, ingest and web, all targets 0; no note in this PR's code (those shown are in joule-moq and at server.rs:167, session.rs:302, all on main)
wai registry export --check; --lib codecs::registry; --features live_room --test live_room; --features live_metering --test live_metering 0
header with cbindgen.toml touched include/wai.h unchanged
live_rooms_verify.py, live_metering_verify.py, live_record_verify.py, e2ee_verify.py 0
browser e2e (e2e/run.sh --runs 2, real Chrome, seek-back included) 2 of 2, 238 of 238 checks
--test dvr --test late_joiner, 4 rounds of 16 concurrent copies, load average about 73 (before the merge) 64 of 64

The first round after the merge caught that secure-objects was on only through the relay's dev-dependency: the relay's own tests passed, while the relay built as joule-moq-ingest's dependency did not. The feature is now on the normal dependency, and joule-moq-room's lock gains the crates it brings (additions only, at the versions the joule-code lock holds).

Seen earlier, not reproduced after fix 3: in 3 of 64 earlier stress runs, the viewer's WebSocket session didn't end within 40 s of the client closing. conn.closed() never resolved. That is in the WebSocket binding, not the DVR code, and none of the 64 runs after the pairing fix showed it. If it reappears, the test now prints the open session's diagnostics.

The live demo room (not changed by this PR)

To turn DVR on for wai.transaction.science/room/, add to the relay's relay.toml on prod:

[dvr]
path = "/Users/dcharlot/sites/wai-room/dvr"

[[dvr.window]]
prefix = ["*"]
max_age_s = 900
max_bytes = 900000000

At the room's limits (4 publishers at 1500 kbit/s each), a 15-minute window is about 0.7 GB of media. Each receipts object adds 359 bytes per group, which is negligible next to that.

🤖 Generated with Claude Code

L7b of WAI's live and interactive work: **DVR on the relay**. The relay keeps a configurable window of a room's tracks on disk, every object with its receipts. A viewer seeks back into it with MOQT FETCH, addressed as live-recording §8 says, and verifies recorded objects exactly as it verifies live ones. ## What is in it - **The DVR store** (`joule-moq-relay/src/dvr.rs`): - **Storage:** per-track segment files, appended a whole group at a time and synced once a segment is sealed. - **Window:** a window per namespace prefix, by age and by bytes, evicting whole groups. - **Restart:** on start the relay reloads its index and checks every stored object against its stored receipt. An object that fails is dropped and counted, and never served. - **Redactions** (live-moderation): a redacted event record is erased from the stored object that carries it, and a redacted object is withheld from DVR reads. - **FETCH below the live edge:** served from the cache when the cache covers it, from the store when the store holds the group, and upstream otherwise (the existing rule). - **Eviction is signalled with MOQT's End of Unknown Range** through the last group no longer held. - **Takes are addressed** by live-recording §8's mapping (the window, answering from it, moderation, a restart, and the harvest window of §8.3). - **Who may seek back:** a new **seek power** in live-rooms (§10.6, with joining a group in progress as a fill, MOQT §3.5). The rooms corpus, `live_rooms_verify.py` and wai-rs `live_room::seek_check` cover it; the relay checks it on every FETCH below the live edge. `joule-moq-room` gives every role the power. - **Metering:** `WMH1` **version 2** adds a hop's DVR figures (bytes stored and served), with a version 2 corpus, its refusals, and `live_metering_verify.py`. - **The browser client:** a **Seek back** control in `joule-moq-web/web/room`, with its end-to-end scenario. `joule-moq-ingest` reads the seek power. - **Docs:** the relay README's DVR section and config, both CHANGELOGs, and SPEC §5 (the DVR window and the seek power). ## Defects found and fixed while finishing (the builder stopped at the account's weekly limit) 1. **A relay panic.** `local_plan` built a run of store-evicted groups by searching the cache from the run's first group, which the cache had already declined. The run then ended at `g − 1`: inverted, and at group 0 a subtraction overflow that panicked the session's task. The search now starts after `g` and skips cache-evicted groups. There are unit tests, shown failing under the old rule (exit 101). 2. **Gaps in the stored window under load.** The store evicted by arrival time across groups, and moving the evicted mark removed only the victim. Groups finish, and are sealed, out of order under load, so a lower group could stay held below the mark: for example a window of [29, 32, 34, …]. Now each track evicts its lowest group first, moving the mark evicts every group at or below it in the track and its partner, and the writer refuses a seal below the mark when it writes it, not only when it was queued. 3. **Media cached without its receipts.** The cache's byte budget evicted oldest first across tracks, and a group's receipts are cached before its media. So a media group could stay cached while its receipts group was gone, and a FETCH would serve media nothing could verify. A media group and its receipts group now leave the cache together. Evicting one moves the partner track's mark as well, even when the partner's group hasn't arrived yet, so a late partner is never served alone. **This applies to every relay, not only DVR.** 4. **Test fixes.** The by-age test now waits until the relay has taken the last group before fetching. The e2e harness clears its results between runs (a second run's room-service keygen refused the first run's key file). A session that doesn't end is reported with its diagnostics. ## Found while merging main: an end-to-end encrypted room was kept L10 (#345) merged while this PR was being finished. Its confidentiality §9 says a room with a confidentiality record is never recorded, and "a relay keeps nothing of the room's tracks beyond delivery". The DVR store kept every track its prefix rules matched, sealed rooms included. Each slice was consistent alone, and the merge was clean apart from the changelog. Fixed here: - **How the store recognises a sealed room.** The store needs no key: a sealed object carries the secure-objects Key ID (`SECURE_OBJECT_KEY_ID`, confidentiality §4.3) in its properties. Properties that do not read count as sealed too. - **What it does then.** The first such group is never written. The store deletes what it already held of the room, since the room's events and receipts tracks are in the clear and can be whole before its first sealed group. It drops the room's decisions from `decisions.wdl` and writes nothing more of the room. Moderation still honours the room's decisions for what the cache delivers. - **Restarts.** The room is recorded in `sealed.wdl` (`room(32) check(32)`), so the store keeps refusing it after a restart. Every other room keeps its window. - **Spec.** live-recording §8.2 gains *A room it never keeps*, confidentiality §9 points to it, and SPEC §5 says so. - **Test.** `a_sealed_room_is_never_kept` runs a sealed room beside a clear room, before and after a restart. **Falsified twice**: with detection off it fails at the sealed-room wait, and with deletion off it fails at "… is kept" (exit 101 each). - The relay's write paths (the seal hand-off, the cache's keep-for-the-store rule, `keep_late`) now use `Dvr::stores` (a rule matches and the room is not sealed). `keeps` still decides which events tracks moderation reads. ## Checks on the build host (rb, at c297283ff, after merging main) The head after it, f8b199a65, rewords one sentence of live-metering §3.1. As a link, the sentence tripped the section-reference check (its `[` matched the table's `[start, end)` interval), and "keeps none signs" matched the public-text check. The verifier and both checks pass on it. | run | result | |---|---| | every `Cargo.lock` with `cargo metadata --locked --offline` | all current (the vendored `libwebrtc` skipped, as `check-lockfiles.sh` does) | | `cargo test --all-targets` of `joule-moq-relay` and `joule-moq-ingest`; `joule-moq-web`; `joule-moq-room` (its own workspace) | 0 each, main's `sealed_objects` relay tests among them | | `cargo clippy` of the relay, ingest and web, all targets | 0; no note in this PR's code (those shown are in `joule-moq` and at `server.rs:167`, `session.rs:302`, all on main) | | `wai registry export --check`; `--lib codecs::registry`; `--features live_room --test live_room`; `--features live_metering --test live_metering` | 0 | | header with `cbindgen.toml` touched | `include/wai.h` unchanged | | `live_rooms_verify.py`, `live_metering_verify.py`, `live_record_verify.py`, `e2ee_verify.py` | 0 | | browser e2e (`e2e/run.sh --runs 2`, real Chrome, seek-back included) | **2 of 2, 238 of 238 checks** | | `--test dvr --test late_joiner`, 4 rounds of 16 concurrent copies, load average about 73 (before the merge) | **64 of 64** | The first round after the merge caught that `secure-objects` was on only through the relay's dev-dependency: the relay's own tests passed, while the relay built as `joule-moq-ingest`'s dependency did not. The feature is now on the normal dependency, and `joule-moq-room`'s lock gains the crates it brings (additions only, at the versions the joule-code lock holds). **Seen earlier, not reproduced after fix 3:** in 3 of 64 earlier stress runs, the viewer's WebSocket session didn't end within 40 s of the client closing. `conn.closed()` never resolved. That is in the WebSocket binding, not the DVR code, and none of the 64 runs after the pairing fix showed it. If it reappears, the test now prints the open session's diagnostics. ## The live demo room (not changed by this PR) To turn DVR on for wai.transaction.science/room/, add to the relay's `relay.toml` on prod: ```toml [dvr] path = "/Users/dcharlot/sites/wai-room/dvr" [[dvr.window]] prefix = ["*"] max_age_s = 900 max_bytes = 900000000 ``` At the room's limits (4 publishers at 1500 kbit/s each), a 15-minute window is about 0.7 GB of media. Each receipts object adds 359 bytes per group, which is negligible next to that. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
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]>
Version 2 of the per-hop session record adds one field, dvr, after ledger
and before sig: six u64 of what a hop that keeps a DVR window served from
it, stored in it, held in it (byte-seconds, rounded down) and dropped from
it for not verifying against their receipts. A reader reads version 1 or
2 by its own layout; version 2's out and stored figures are held to the
out and in entries (record_invalid); its bound is B2(M) = 600 + 180(M+2),
chosen by the fifth byte before anything else is read. The units do not
sum the DVR figures; the outcome states each record's version and, for
version 2, its figures. The receipt stays version 1.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
HopRecord gains dvr: Option<DvrFigures>; Some is version 2, None version 1,
whose bytes are unchanged. A record reads as version 1 or 2 by its own
layout, any other version unknown_version; version 2's out figures are
held to the out entries and its stored figures to the in entries
(record_invalid). The size bound is chosen by the fifth byte before
anything else is read: B2(M) = B(M) + 48 for version 2, B(M) otherwise.
DvrFigures::byte_seconds floors the sum once. energy_steering's corpus
builds its records as version 1.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
dvr_relay (accepted): the lesson's relay keeps a ten-second DVR window of
the composite and signs a version 2 record of it, a viewer joining at
20 s filled from the window. Refused: dvr_out_exceeds and
dvr_stored_exceeds (record_invalid), record_unknown_version (version 3),
dvr_record_too_large (past B2(M) by less than an entry). Each accepted
record's facts state its version, and a version 2 record's six DVR
figures; every existing record keeps its bytes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Five vectors added (dvr_relay accepted; dvr_out_exceeds,
dvr_stored_exceeds, record_unknown_version, dvr_record_too_large
refused); every existing vector's records and receipt are unchanged and
its accepted records gain only their version, 1.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The second implementation reads WMH1 version 1 or 2 by its own layout,
holds version 2's out and stored figures to the entries, chooses the
bound by the fifth byte (B2(M) for 2, B(M) otherwise), and states each
record's version and a version 2 record's DVR figures. New mutations
cover the stated version, figures and bound, the record's DVR bytes, and
the four new refusals. The README describes the new vectors.

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]>
powers gains bit 4 seek; a role's and a grant's powers set none above
bit 4, and a grant's seek stays within its role's (§4.3 step 7). §10.6
fixes the live edge (MOQT §3.1.4) and when a FETCH or a SUBSCRIBE's fill
seeks back, which a relay serves only under a proved grant holding
seek, refusing any other with REQUEST_ERROR UNAUTHORIZED and the reason
phrase seek_not_granted (§11). §12 describes the new corpus content.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
power::SEEK is bit 4, which the descriptor's and the grant's field rules
now allow; seek_check refuses seek_not_granted a request that starts in a
group below the live edge under a grant without it. The corpus gains the
accepted dvr room, three refused vectors (a grant with seek its role
lacks; a grant and a role with powers bit 5), each accepted grant's seek,
and the seek section.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every existing record and stated outcome is unchanged; each accepted
grant's moqt entry gains its seek, false for every grant before the dvr
room.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The second implementation allows powers bit 4, states each accepted
grant's seek, and gives every request of seek its outcome by §10.6's
rule from the room's grants as §4.3 checks them; the README describes
the dvr room, the new refusals and the seek section.

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]>
One durable sync per group file could not keep up with a room's audio groups (fifty a second
per publisher), so the writer fell behind and recent groups were neither cached nor stored.
Segments take ten seconds of a track each; a record a later one replaces is marked and
zeroed; a crash loses at most the last second, and what it leaves cut short is cut off and
counted at start.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Two sessions that ended together could interleave a line and its newline, leaving two
summaries on one line of summary.out_path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Under load a group's stream can finish after the cache evicted a later group of its track;
the cache refused it, so the DVR store never got it. For a track the store keeps, the cache
now takes it and eviction drops the evicted group's state alone; coverage is unchanged. The
mux test of a stream that arrives after the close no longer fails when, on a loaded host, the
close arrives before its writes do.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
local_plan's run of groups the DVR store evicted searched the cache for the next whole
group from the run's first group itself, which the cache had already declined (it was at
or below the cache's own eviction mark), so the run ended at g - 1: an inverted range, and
at group 0 a subtraction overflow that panicked the session's task (seen in the DVR test
a_window_by_age_empties_as_its_groups_pass_it). The search now starts after g and skips
groups the cache evicted. local_plan takes the track's cache rather than the track, so the
two cases are unit tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Groups finish, and are sealed, out of order under load. The store evicted by arrival
across all groups, so a group sealed late could sit below groups already evicted, leaving
gaps in the window (seen as [29, 32, 34, ...] in the window test under concurrent runs).
Each track now evicts its lowest group first (across tracks, the one whose lowest group
arrived first), and the writer refuses a seal below the evicted mark when it writes it,
not only when it was queued.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The cache's byte budget evicted oldest first across tracks, and a group's receipts are
cached just before its media, so under pressure a media group could stay cached while its
receipts group was gone: a FETCH then served media no receipts covered (seen in the DVR
test a_window_by_age_empties_as_its_groups_pass_it under concurrent runs). The pair is now
evicted together, as the DVR store already evicts it, and kept together while either is
still arriving on a track the store keeps. Budget::take drops the partner's accounting.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A second run in the same output directory failed its service scenario: the room service's
keygen refuses the key file the first run left.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The DVR store evicts the track whose lowest group arrived first; a group's arrival time
can be later than a higher group's (the cache recreates a group's state when it takes a
late group), so the store could evict groups 31 and 32 while group 30 stayed held below
the new mark: a gap in the window (1 of 16 concurrent runs of the window test). Moving a
track's evicted mark now removes every group at or below it, in the track and its
partner, so none is ever held below the mark.

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]>
Taking group 3 can evict a media and receipts pair from the cache; the test's media and
receipts FETCHes are two requests, so an eviction between them left media without its
receipts ("the receipts of group 2 come with it", 16 of 64 runs under load with logging).
The test now waits until the relay's largest object of both tracks is group 3's.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
joule-moq-relay: an evicted group moves its partner track's mark too
Some checks failed
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
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
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
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-pack / wai-pack · linux (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
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 1m30s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Has been cancelled
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Has been cancelled
f0c5402080
A group's receipts are cached before its media, and under load the media's stream can be
taken after later groups, so the budget could evict receipts group g before media group g
had arrived: the pairing found no partner to evict, and media g was then cached and served
without receipts (the DVR by-age test, 8 of 64 runs under load). Evicting group g now moves
the partner track's evicted mark to g as well, so a partner group arriving later is never
served from the cache alone; a DVR-kept track still takes it for the store.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
# Conflicts:
#	wai/CHANGELOG.md
confidentiality §9 (merged with L10) says a relay keeps nothing of an
end-to-end encrypted room's tracks beyond delivery; the DVR store kept
every track its prefix rules matched. The store now knows such a room by
its first object carrying a secure-objects Key ID (or properties that do
not read), never writes that group, deletes what it held of the room (its
events and receipts tracks are in the clear and can be whole first),
drops the room's decisions from decisions.wdl, writes nothing more of it,
and records it in sealed.wdl so a restart keeps refusing it. Moderation
still honours the room's decisions for what the cache serves.

live-recording §8.2 states the rule; confidentiality §9 points to it.
The joule-code changelog's stale "a file per group" now describes the
segments, and the cache's media/receipts pairing is documented.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The DVR store reads an object's Key ID to know a sealed room; the feature
was on only through the dev-dependency, so the relay built as another
crate's dependency (joule-moq-ingest, the e2e's release binary) did not
compile. tests/sealed_objects.rs now gets it from the normal dependency.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
joule-moq-room: Cargo.lock with the relay's secure-objects dependencies
Some checks failed
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Has been cancelled
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · discrete GPU, Vulkan (jetson-hub) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · integrated GPU, Vulkan (framework-128gb) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Has been cancelled
wai-quantum CPU vector units / does this change touch it (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector unit, rvv 1024-bit (riscv64, emulated) (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector unit, sve 128-bit (aarch64, emulated) (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector unit, rvv 128-bit (riscv64, emulated) (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector unit, sve 2048-bit (aarch64, emulated) (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector unit, avx2 (x86_64 silicon) (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector unit, sve 512-bit (aarch64, emulated) (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector units, avx2 and avx512 (framework-128gb silicon) (pull_request) Has been cancelled
wai-quantum CPU vector units / member · vector unit absent (macos) (pull_request) Has been cancelled
wai-quantum portable tensor program / does this change touch it (pull_request) Has been cancelled
wai-quantum portable tensor program / tensor program · CPU, mutants, GPU builds (pull_request) Has been cancelled
wai-quantum portable tensor program / tensor program · GPUs (jetson-hub) (pull_request) Has been cancelled
wai-quantum portable tensor program / tensor program · integrated GPU (framework-128gb) (pull_request) Has been cancelled
wai-quantum portable tensor program / tensor program · Metal and the arm64 CPU (macos) (pull_request) Has been cancelled
wai-quantum tensor-engine member / does this change touch it (pull_request) Has been cancelled
wai-quantum tensor-engine member / member · tensor engine, the kernel toolchain's simulator (linux) (pull_request) Has been cancelled
wai-quantum tensor-engine member / member · tensor engine absent (linux-arm64) (pull_request) Has been cancelled
wai-quantum matrix-extension member / member · matrix extension, emulated (aarch64 Linux) (pull_request) Has been cancelled
wai-quantum matrix-extension member / member · matrix extension absent (macos) (pull_request) Has been cancelled
wai-quantum WebGPU member / member · DX12 and Vulkan (cbio-windows) (pull_request) Has been cancelled
wai-quantum service / service · linux (pull_request) Has been cancelled
wai-quantum service / service · macos (pull_request) Has been cancelled
wai-quantum matrix-extension member / does this change touch it (pull_request) Has been cancelled
wai-quantum service / does this change touch it (pull_request) Has been cancelled
c297283ff6
Additions only, at the versions joule-code-rs's lock already holds.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
live-metering §3.1: the version 2 sentence cites live-recording §8 in prose
All checks were successful
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 1m41s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 3m29s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 10m1s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m16s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 18m47s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 23s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m10s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 4m2s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 22m44s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 6s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 2m44s
wai-web reach builds / wai-web reach · 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 6s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m16s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m6s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 27s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 8m36s
wai-pack / wai-pack · linux (pull_request) Successful in 2m7s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 9m2s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m30s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m33s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 14m33s
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 43s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 4m38s
wai-pack / wai-pack · macos (pull_request) Successful in 1m4s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m44s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m30s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 4m50s
f8b199a657
The link after the table's [start, end) interval read, to the section
reference check, as one link text reaching back to energy-measurement
§2.7; and "keeps none signs" matched the public-text check's "none signs".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge remote-tracking branch 'origin/main' into joule-moq/dvr
Some checks failed
WAI JPEG-AI whole decode (pinned inputs, required) / does this change touch it (pull_request) Has been cancelled
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (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
energy meters on real hardware / RAPL and NVML on jetson-hub (pull_request) Has been cancelled
99dae8f0a0
# Conflicts:
#	wai/CHANGELOG.md
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!351
No description provided.