From 946dec5257e9336d6b43bca2c6d3e75c4acf936c Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 5 Nov 2026 12:05:09 -0800 Subject: [PATCH 1/5] quest: audit m0 and m1 (2026-11-05) Co-Authored-By: Claude Opus 5.5 --- quest/m0/README.md | 18 +++-- quest/m0/backport-fill-head-race.md | 5 +- quest/m0/backport-release-hardening.md | 4 - quest/m0/backport-security-fixes.md | 24 ------ quest/m0/ci/README.md | 1 - quest/m0/ci/five-minutes.md | 21 +++-- quest/m0/ci/hakari-followups.md | 45 +++++++---- quest/m0/ci/hakari.md | 18 +++-- quest/m0/ci/mbx-r2-verify.md | 42 +++++----- quest/m0/ci/publish-release-only.md | 27 ++++--- quest/m0/ffi-shutdown-backport.md | 42 +++------- quest/m0/interop-green/README.md | 13 ++- quest/m0/nightly/README.md | 3 +- quest/m0/nightly/miri.md | 28 ++++--- quest/m0/nightly/obs-stop-drain.md | 33 ++++++++ quest/m0/nightly/resume-model.md | 33 ++++++++ quest/m0/nightly/shipping-size.md | 79 ------------------- quest/m0/test-flakes-2/README.md | 10 ++- quest/m0/test-flakes-2/open-gop-fixture.md | 20 ----- quest/m0/test-flakes-2/p2p-data-channel.md | 27 +++++++ quest/m1/README.md | 24 +++--- quest/m1/announce-takeover.md | 14 ++-- quest/m1/api-audit/README.md | 5 +- .../m1/audio-jitter-target/native-stretch.md | 16 ++-- quest/m1/audio-jitter-target/watch.md | 11 ++- quest/m1/bench-publish.md | 6 +- quest/m1/c/README.md | 16 ++-- quest/m1/ci-housekeeping.md | 20 ----- quest/m1/cluster-routing/federation.md | 34 ++++---- quest/m1/cluster-routing/routes/README.md | 7 +- quest/m1/copy-recover.md | 15 ++-- quest/m1/crates-trusted-publisher.md | 5 ++ quest/m1/group-drops.md | 13 ++- quest/m1/moq-e2ee-remove.md | 22 ++++++ quest/m1/push-to-talk/README.md | 4 - quest/m1/push-to-talk/native-comfort-noise.md | 7 +- quest/m1/read-backfill.md | 11 ++- quest/m1/release-rs-oidc.md | 1 + quest/m1/session-policy/README.md | 6 +- quest/m1/session-policy/tokio-handoff.md | 7 +- quest/m1/session-policy/uring.md | 3 +- quest/m1/stream-credit/takeover.md | 13 +-- quest/m1/subscribe-ranges/README.md | 14 ++-- quest/m1/subscribe-ranges/js-fills.md | 6 ++ quest/m1/subscribe-ranges/lite07-fetch.md | 9 +++ .../m1/subscribe-ranges/start-bookkeeping.md | 43 +++++----- quest/m1/time-addressing/consumers.md | 6 +- quest/m1/time-addressing/js.md | 12 ++- quest/m1/time-addressing/lite07.md | 15 +++- quest/m1/time-addressing/model.md | 3 +- quest/m1/unbounded-groups/README.md | 44 ++++++----- quest/m1/unbounded-groups/byte-holes.md | 19 ++++- quest/m1/unbounded-groups/js-byte-holes.md | 19 +++-- quest/m1/webrtc-rename.md | 2 +- quest/m2/README.md | 4 +- quest/m2/c/README.md | 4 +- quest/m2/c/consumers.md | 4 +- quest/m2/mbx-r2-release-cache.md | 27 +++++++ quest/m2/relay-io-uring-package.md | 5 ++ quest/{m0/ci => m2}/release-tag-publishers.md | 9 +++ 60 files changed, 565 insertions(+), 433 deletions(-) delete mode 100644 quest/m0/backport-security-fixes.md create mode 100644 quest/m0/nightly/obs-stop-drain.md create mode 100644 quest/m0/nightly/resume-model.md delete mode 100644 quest/m0/nightly/shipping-size.md delete mode 100644 quest/m0/test-flakes-2/open-gop-fixture.md create mode 100644 quest/m0/test-flakes-2/p2p-data-channel.md delete mode 100644 quest/m1/ci-housekeeping.md create mode 100644 quest/m1/moq-e2ee-remove.md create mode 100644 quest/m2/mbx-r2-release-cache.md rename quest/{m0/ci => m2}/release-tag-publishers.md (54%) diff --git a/quest/m0/README.md b/quest/m0/README.md index 9d3ffaa5673..a001d10e8ec 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -2,11 +2,14 @@ ## Goal -The work in flight now: a passing Nightly, fixes for the `release` line, the -quest merge driver, local reviews, CI cost and latency, test flakes, and -replacing the catalog's HLS records with a declared segment grid. That last -one is a breaking catalog and API change, pulled ahead of m1's other planned -format changes; it lands on `main` and ships with the next cut. +The work in flight now: passing Nightly, Interop, and Video runs, backports +and patch releases for the `release` line, CI cost and latency, test flakes, +and a few small fixes for hostile input, WebSocket throughput, agent disk use, +and CRLF checkouts. The quest merge driver +([moq-dev/moq#6728](https://github.com/moq-dev/moq/pull/6728)), local reviews +([moq-dev/moq#7175](https://github.com/moq-dev/moq/pull/7175)), and the +declared HLS segment grid +([moq-dev/moq#7652](https://github.com/moq-dev/moq/pull/7652)) landed. ## Plan @@ -26,12 +29,11 @@ edge, which embeds moq-relay; it moved there on 2026-09-28. - [Nightly passes on main](/quest/m0/nightly/README.md) - the scheduled Nightly passes end to end, so red means a new break - [Interop and Video pass on main](/quest/m0/interop-green/README.md) - the scheduled Interop and Video workflows pass, so red means a new break - [moq-video shares moq-mux's bounded H.265 SPS walk](/quest/m0/video-sps-walk.md) - a hostile publisher's H.265 SPS can't panic a subscriber's decoder -- [Publish the release line's drain() wrappers](/quest/m0/ffi-shutdown-backport.md) - Python `moq-rs` 0.5.2 and Dart `moq` 0.1.1 reach PyPI and pub.dev from `release` +- [Publish the release line's drain() wrappers](/quest/m0/ffi-shutdown-backport.md) - Dart `moq` 0.1.1 reaches pub.dev from `release` - [Backport audio groupDuration](/quest/m0/backport-audio-group-duration.md) - `@moq/publish` 0.5.4 on `release` can pack several Opus frames per group, making Cloudflare's relay drop audio less often -- [Backport the SETUP-path and iroh-key fixes](/quest/m0/backport-security-fixes.md) - `release` refuses a conflicting SETUP Path and keeps persisted iroh keys private, in one patch release - [Backport the joined-head FETCH race fix](/quest/m0/backport-fill-head-race.md) - a `release` relay stops FETCHing a group head its own SUBSCRIBE is bringing, which left live readers hanging - [CI cost and latency](/quest/m0/ci/README.md) - cloud CI runs only in GitHub's merge queue, one tested entry at a time, expensive checks run nightly and gate `release`, caches move to R2, and runners are chosen last -- [More tests under load](/quest/m0/test-flakes-2/README.md) - load-only and queue failures, one quest per flake, fixed at the cause, since each one fails a whole batch +- [More tests under load](/quest/m0/test-flakes-2/README.md) - load-only and queue failures, one quest per flake, fixed at the cause, since each one drops a queued PR - [Backport the relay and auth hardening to release](/quest/m0/backport-release-hardening.md) - `release`'s relay refuses dot-segment paths, serves its HTTP routes with main's response hardening, and withdraws advertisements a peer starves of send credit; its auth client refuses redirects - [Agent build output can't fill the desktop's disk](/quest/m0/agent-disk-budget.md) - finished agent checkouts reclaim their mbx targets automatically, so parallel agent builds stop filling the root disk - [@moq/net's WebSocket receive windows match Rust](/quest/m0/qmux-receive-windows.md) - WebSocket JS throughput stops being capped below Rust's diff --git a/quest/m0/backport-fill-head-race.md b/quest/m0/backport-fill-head-race.md index 09cd8bc0f09..3105257ede8 100644 --- a/quest/m0/backport-fill-head-race.md +++ b/quest/m0/backport-fill-head-race.md @@ -27,8 +27,9 @@ that arrives, and a remaining miss still FETCHes. Older history does not wait. Local review also exposed a pending miss no longer being polled during the PUBLISH_DONE grace. The backport adds that poll and a paused-time reproduction. -[moq-dev/moq#7903](https://github.com/moq-dev/moq/pull/7903) lands the same -correction on main first, following the main-first backport rule. Its other +[moq-dev/moq#7903](https://github.com/moq-dev/moq/pull/7903) landed the same +correction on main first (merged 2026-11-05), following the main-first +backport rule. Its other change, driving a lingering copy's fetches while a resumed SUBSCRIBE is set up, has no `release` counterpart: release creates its fetch set after SUBSCRIBE_OK and never lingers. diff --git a/quest/m0/backport-release-hardening.md b/quest/m0/backport-release-hardening.md index 4e4bf984035..d3943f0277d 100644 --- a/quest/m0/backport-release-hardening.md +++ b/quest/m0/backport-release-hardening.md @@ -20,7 +20,3 @@ Added 2026-10-31 (user, /quest-plan of the follow-ups from the 2026-10-31 /quest - **Landed:** the dot-segment and auth-redirect items above merged into `release` on 2026-11-02 in [moq-dev/moq#7599](https://github.com/moq-dev/moq/pull/7599), which also settles the redirect follow-up that [moq-dev/moq#7298](https://github.com/moq-dev/moq/pull/7298) and [moq-dev/moq#7278](https://github.com/moq-dev/moq/pull/7278) suggested. What remains is the two ports above, then the patch release. [moq-dev/moq#7596](https://github.com/moq-dev/moq/pull/7596) (open) holds this quest's main-side checkpoint. Public API: none. Wire: none; as on main, a withdrawal resets a partially written request without waiting for peer credit. - -## Related - -- [Backport the SETUP-path and iroh-key fixes](/quest/m0/backport-security-fixes.md) - the earlier backport in the same patch release diff --git a/quest/m0/backport-security-fixes.md b/quest/m0/backport-security-fixes.md deleted file mode 100644 index c1503d18701..00000000000 --- a/quest/m0/backport-security-fixes.md +++ /dev/null @@ -1,24 +0,0 @@ -# [S] Backport the SETUP-path and iroh-key fixes to release - -## Goal - -`release` refuses a moq-transport SETUP Path on WebTransport and WebSocket -bindings, as [moq-dev/moq#7206](https://github.com/moq-dev/moq/pull/7206) -fixed on main, and writes persisted iroh endpoint keys with private file -permissions, as [moq-dev/moq#7213](https://github.com/moq-dev/moq/pull/7213) -did. Both ship in one patch release with the published API unchanged. - -## Plan - -Decided 2026-10-30 (maintainer, `/quest-plan`): one quest and one PR against -`release` for both. They are small security fixes that ship in the same patch -release, so pairing them is simpler than the usual one PR per backport. - -- SETUP path: `release`'s handshake also accepts a SETUP Path that names a - different path or query than the request URI, so Tokio could authorize the - wrong path. Port #7206's refusal onto `release`'s handshake, with its test. -- iroh key: port #7213's private permissions for the persisted key file, with - its test. -- Version bumps are hand-picked, per `CONTRIBUTING.md`. - -Public API: none. Wire: a conflicting SETUP Path is refused, as on main. diff --git a/quest/m0/ci/README.md b/quest/m0/ci/README.md index 4be581e5f17..02b91e50370 100644 --- a/quest/m0/ci/README.md +++ b/quest/m0/ci/README.md @@ -181,7 +181,6 @@ The historical samples locate candidates; they are not controlled benchmarks. - [Verify the Nix cache](/quest/m0/ci/nix-cache-verify.md) - confirm releases use `nix.moq.dev`, check its bucket sizes, and retire Cachix - [Record hosted cargo-hakari evidence](/quest/m0/ci/hakari.md) - compare scheduled macOS and Windows cache hits and estimated compiler work saved before and after the workspace-hack - [Drop main from the publish Environment](/quest/m0/ci/publish-release-only.md) - the maintainer narrows `publish` to `release` and release tags once no job naming it runs as `main` -- [Binary release publishers run on their tag](/quest/m0/ci/release-tag-publishers.md) - brew, Go and Swift releases stop running through `workflow_run` on main - [Measure the Linux cache effect of native media exclusions](/quest/m0/ci/hakari-followups.md) - scheduled Linux jobs measure cache reuse after unrelated tests stop compiling PipeWire and libclang - [A release merge opens no stale release PR](/quest/m0/ci/release-pr-after-release.md) - `just rs release` publishes before it proposes, so a merged release isn't re-proposed - [Build two queue entries at once if it helps](/quest/m0/ci/queue-concurrency.md) - a measured trial of `maximumEntriesToBuild: 2` against the serial lane's burst latency diff --git a/quest/m0/ci/five-minutes.md b/quest/m0/ci/five-minutes.md index 721d52bedb1..ff4b3b9ca70 100644 --- a/quest/m0/ci/five-minutes.md +++ b/quest/m0/ci/five-minutes.md @@ -30,6 +30,16 @@ Decided 2026-10-29 (user): time queued in `quest gate` admission counts. kixelated/quest redesigns the gate so admission no longer outlasts a worker's cache; this quest owns the gated commands' own run time. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ drop the wait on +moq-dev/quest's admission work. Its admission changes landed +([moq-dev/quest#324](https://github.com/moq-dev/quest/pull/324), +[moq-dev/quest#342](https://github.com/moq-dev/quest/pull/342)), and the +5-minute-cache premise PR +([moq-dev/quest#276](https://github.com/moq-dev/quest/pull/276)) closed +unmerged. Re-measure the net route with landed admission, then finish or +narrow this quest. Not chosen: wait on moq-dev/quest's m1 worker cache and +move this to m1; delete this quest. + Baseline, 2026-10-22 to 10-29: successful agent-run gates on the desktop, from Claude Code transcripts. Times include admission wait and load from concurrent agents, so this is an observation, not a controlled benchmark. @@ -131,9 +141,9 @@ require a capable builder. What remains: -- Admission still makes the measured net route exceed 5 minutes despite its - command taking 227 s. The 2026-10-29 admission decision above remains with - moq-dev/quest. +- Re-measure the net route with landed admission: on 2026-11-02, admission + made it exceed 5 minutes despite its command taking 227 s. Then finish or + narrow this quest. - Repeat the default FFI route without the override; the Gradle fix ([moq-dev/moq#7632](https://github.com/moq-dev/moq/pull/7632)) merged 2026-11-04. @@ -146,11 +156,6 @@ What remains: Moving a check to the queue or nightly still needs evidence and an explicit coverage tradeoff. Split a large independent lever into its own quest. -## Waiting - -- moq-dev/quest: admission must keep the whole gate inside the worker's cache - window; repeat the net measurement after its admission work lands. - ## Related - [Unify dependency features](/quest/m0/ci/hakari.md) - cache hits across feature shapes diff --git a/quest/m0/ci/hakari-followups.md b/quest/m0/ci/hakari-followups.md index 8bfecc2801e..2cfaf7e58c7 100644 --- a/quest/m0/ci/hakari-followups.md +++ b/quest/m0/ci/hakari-followups.md @@ -9,13 +9,15 @@ settled. ## Plan -The implementation in [moq-dev/moq#7713](https://github.com/moq-dev/moq/pull/7713) -adds the derived trybuild-edge guard and excludes `pipewire`, `libspa`, and -`clang-sys` from the workspace-hack's final output. Other transitive features -remain unified. Linux x86_64 and ARM test graphs of `moq-json` no longer reach -PipeWire or libclang. An x86_64 nextest run with shared compiler caching -bypassed passes with native media pkg-config probes refused and an invalid -libclang path. The original manifests fail under the same restriction. +The implementation in +[moq-dev/moq#7713](https://github.com/moq-dev/moq/pull/7713) (merged +2026-11-05) adds the derived trybuild-edge guard and excludes `pipewire`, +`libspa`, and `clang-sys` from the workspace-hack's final output. Other +transitive features remain unified. Linux x86_64 and ARM test graphs of +`moq-json` no longer reach PipeWire or libclang. An x86_64 nextest run with +shared compiler caching bypassed passes with native media pkg-config probes +refused and an invalid libclang path. The original manifests fail under the +same restriction. Local Cargo 1.98.1 unit graphs for `moq-json`, `moq-video --features pipewire`, and `moq-audio --features pipewire`, each built with `--tests`, have 531 distinct @@ -43,7 +45,7 @@ the merge with the first two after it. Failed or cancelled builds and missing su are incomplete evidence, not zero cache hits. Record source/build differences that prevent attributing a change to these exclusions. -The 2026-11-02 scheduled run is a pre-merge candidate: +The 2026-11-02 scheduled run was the first pre-merge candidate: [run 41483654426](https://github.com/moq-dev/moq/actions/runs/41483654426), [Rust benchmark tests](https://github.com/moq-dev/moq/actions/runs/41483654426/job/125408205554). Its 12 mbx object-cache summaries total 986 hits, 721 misses, 323 not @@ -51,23 +53,32 @@ looked up, 8 bypassed, and 11 remote failures. The conditional hit rate is 57.76% (`986 / (986 + 721)`); this excludes not-looked-up and bypassed units. The summaries report estimated compiler time avoided, not measured CPU totals. The 5 GiB download budget was exhausted during the first build; remote -failures and mixed build phases limit attribution. Replace this -candidate if a later scheduled run precedes this PR's merge. +failures and mixed build phases limit attribution. + +Checked 2026-11-05 (/quest-audit): the last scheduled run before the merge, +[run 41852517544](https://github.com/moq-dev/moq/actions/runs/41852517544) +(2026-11-04), replaces that candidate as the baseline. Its +[Rust benchmark tests](https://github.com/moq-dev/moq/actions/runs/41852517544/job/126652296572) +job failed (test failures and a denied `moq-ffi` test warning) but printed +its mbx summaries. The first post-merge run, +[42050683248](https://github.com/moq-dev/moq/actions/runs/42050683248/job/127325640293), +cancelled that job at the 60-minute timeout, so it is incomplete evidence. Public API: none. Wire: none. ## Waiting -- moq-dev/moq: after the native-media exclusions merge, collect the last - scheduled Linux baseline and first two post-merge Nightlies' mbx hit rates - and available compiler-time fields. No post-merge evidence for these - exclusions exists yet. If the cache cost is material, present the measured tradeoff to the - maintainer; recommend keeping the narrow final exclusions unless the - measurements justify another design. +- moq-dev/moq: collect the baseline run 41852517544's and the first two + complete post-merge Nightlies' mbx hit rates and available compiler-time + fields for `Nightly (Rust benchmark tests)`. No complete post-merge evidence + exists yet: the 2026-11-05 run cancelled the job at 60 minutes. If the cache + cost is material, present the measured tradeoff to the maintainer; recommend + keeping the narrow final exclusions unless the measurements justify another + design. ## Related - [Unify dependency features with cargo-hakari](/quest/m0/ci/hakari.md) - owns the separate macOS/Windows evidence and FFI invocation alignment in [moq-dev/moq#7666](https://github.com/moq-dev/moq/pull/7666); do not duplicate - those measurements or depend on its unmerged implementation + those measurements diff --git a/quest/m0/ci/hakari.md b/quest/m0/ci/hakari.md index 9ac40761ed3..8b9841a4873 100644 --- a/quest/m0/ci/hakari.md +++ b/quest/m0/ci/hakari.md @@ -18,8 +18,9 @@ trimming CI's feature permutations. dev-dependency layout, unifying test, lint, and bench builds. Keep that layout; library-only builds do not need the hack. -The remaining FFI invocation alignment is implemented in -[moq-dev/moq#7666](https://github.com/moq-dev/moq/pull/7666): default builds use +The remaining FFI invocation alignment landed in +[moq-dev/moq#7666](https://github.com/moq-dev/moq/pull/7666) (merged +2026-11-05): default builds use `cargo build-ffi` with `openh264`, native builds omit `--target`, and only cross builds name a target. Python and Dart host tests retain `testing` for the manual clock and leak allocator, with separate target directories so they cannot @@ -40,7 +41,7 @@ completed Windows, but cancelled macOS before any step ran. Windows therefore has two complete after-runs; macOS has only one. Logs expose object-cache counts and estimated compiler work saved, but no measured user/system CPU totals. Do not call elapsed time CPU time, or attribute these earlier runs to the FFI -alignment that has not landed yet. +alignment, which landed only on 2026-11-05. The 2026-11-04 maintainer decision accepts hosted CI as the strict Nix gate; a local namespace-probe skip is expected. The pkg-config and Gradle repairs @@ -51,10 +52,13 @@ Public API and wire: none. ## Waiting - moq-dev/moq: inspect the next scheduled Nightly for a second complete macOS - after-run. As of 2026-11-04, the latest scheduled run is - [Nov 4](https://github.com/moq-dev/moq/actions/runs/41852517544); its - [macOS job](https://github.com/moq-dev/moq/actions/runs/41852517544/job/126656206251) - was cancelled with no steps. Run + after-run. The macOS job cannot give one until + [Nightly's macOS platform job passes](/quest/m0/nightly/macos.md) fixes + `moq-audio`'s macOS test build: the + [2026-11-05 macOS job](https://github.com/moq-dev/moq/actions/runs/42050683248/job/127326015410) + failed compiling it (E0277, `rs/moq-audio/src/capture.rs:859`), and the + [Nov 4](https://github.com/moq-dev/moq/actions/runs/41852517544/job/126656206251) + one was cancelled with no steps. Run `gh run list --repo moq-dev/moq --workflow nightly.yml --event schedule`, inspect the next macOS job and record its mbx summaries alongside Nov 3. This measurement wait outlives the implementation PR; never dispatch Nightly. diff --git a/quest/m0/ci/mbx-r2-verify.md b/quest/m0/ci/mbx-r2-verify.md index a1cbe7eeda2..71381a83544 100644 --- a/quest/m0/ci/mbx-r2-verify.md +++ b/quest/m0/ci/mbx-r2-verify.md @@ -2,14 +2,10 @@ ## Goal -Confirm the cache earns its keep for the hosted jobs that still use R2 -(Nightly on `main`, release pull requests, and the macOS and Windows jobs), -and record the numbers in the PR that closes this: - -- A release pull request's `Check the cache` step reports `effective - read-only`. Condition: `release` carries the Rust cache, which its - `platform.yml` still lacks on 2026-10-28; check with - `git show origin/release:.github/workflows/platform.yml | grep rust-cache`. +Confirm the cache earns its keep for the hosted Nightly jobs on `main` that +still use R2 (Linux, macOS and Windows), and record the numbers in the PR +that closes this: + - Nightly's Linux, macOS and Windows jobs hit what the previous Nightly wrote. - Restore plus build time against the 150-210s Actions restore of the ~6 GB @@ -28,6 +24,12 @@ nightly.yml --branch main --event schedule`), never a dispatch on a branch. ## Plan +Decided 2026-11-05 (maintainer, /quest-audit): ✅ the release pull request +check moved to [m2](/quest/m2/mbx-r2-release-cache.md) behind the cut, since +`release` gets the platform Rust cache only when the cut merges `main` into +it; the Nightly checks stay here. Not chosen: moving this whole quest; merging +`main` into `release` now, which reverses the 2026-11-04 decision. + Decided 2026-10-22 (maintainer): narrowed to hosted jobs. Since [#6040](https://github.com/moq-dev/moq/pull/6040) the merge queue runs on the self-hosted `moq-queue` runner with mbx's local store, so it neither reads nor @@ -70,9 +72,13 @@ compilation is "not looked up". where `main` has it. mbx v1.29.1 (2026-11-01) includes [#870](https://github.com/jdx/mr-boxington/pull/870), and `.github/actions/rust-cache/action.yml` pins 1.29.2 (2026-11-03) since - [#7653](https://github.com/moq-dev/moq/pull/7653). Verify it against the - Windows criterion in Waiting below. The fix also offers legacy CRLF - identities, so an in-window manifest from 1.28.0 remains usable. + [#7653](https://github.com/moq-dev/moq/pull/7653). The fix also offers + legacy CRLF identities, so an in-window manifest from 1.28.0 remains usable. + Verified 2026-11-05: the scheduled + [Windows job](https://github.com/moq-dev/moq/actions/runs/42050683248/job/127326015447) + of run 42050683248 set up mbx 1.29.2, and its workspace build, against a + manifest of 2,604 predictions, reported 846 hits, 224 misses, 168 not looked + up and 1,019 prefetched. Windows inheritance pays. - macOS: on 2026-10-28 the build did inherit, prefetching 732 predictions, yet hit only 13, with 1565 compilations not looked up. The install order is not the cause. Find out why the inherited predictions mostly miss, for @@ -82,7 +88,8 @@ compilation is "not looked up". The doctest job hit 0 on 2026-10-24 and 2026-10-27, 115 on 2026-10-25, and 46 on 2026-10-26. Decided 2026-10-29 (maintainer): give those jobs full history (`fetch-depth: 0` with `filter: blob:none`) only once Windows hits - after the mbx bump, which shows inheritance pays. + after the mbx bump, which shows inheritance pays. Windows hit on + 2026-11-05 (above), so that condition is met. - `Cargo.lock` changed 7, 2, 6, 10, 8 and 8 times between consecutive scheduled Nightlies from 2026-10-21 to 2026-10-27. Nightly is the only hosted writer for Windows and macOS, so after more than 8 changes the @@ -118,17 +125,6 @@ feature unification, so changed compiler inputs remain a separate cause. ## Waiting -- GitHub Actions: a scheduled Windows job on mbx 1.29.1 or later must load - a workspace manifest of more than 124 predictions and hit, as its - workspace build's mbx summary reports. Check the first run with an - available manifest from an earlier scheduled Windows workspace build at the - same lockfile state or within 8 earlier states. A setup failure or no - in-window predecessor is inconclusive; inspect the next eligible scheduled - run. Until this proves inheritance pays, keep Linux's shallow checkout as - decided above. Do not dispatch Nightly. -- moq-dev/moq: `release` still lacks the platform Rust cache as checked on - 2026-11-04 with the command in the Goal. Once it carries the cache, inspect - a release pull request's `Check the cache` step for effective read-only. - GitHub Actions: scheduled runs must supply the remaining cross-platform reuse, restore-plus-build comparison and rebuild-frequency evidence in the Goal. Current timings are not a matched-commit comparison, and macOS's diff --git a/quest/m0/ci/publish-release-only.md b/quest/m0/ci/publish-release-only.md index e7143de7624..1ce6ab25a87 100644 --- a/quest/m0/ci/publish-release-only.md +++ b/quest/m0/ci/publish-release-only.md @@ -28,15 +28,24 @@ merges `main` into it, and [nix-cache-verify](/quest/m0/ci/nix-cache-verify.md) deletes the Cachix cache and token once a release tag substitutes from `nix.moq.dev`. -What remains is the maintainer's, in order: - -1. Merge `main` into `release` (a release cut or a backport). Tags run - `release`'s copies of the workflows, so until then a tag still chains its - winget and Kotlin wrapper publishers through `main`'s `workflow_run`, which - that PR removed: those two skip, and `release`'s apt and rpm dispatches - still run on `main`. -2. Then drop `main` from `publish`'s deployment policy, and remove - `DISCORD_WEBHOOK` and `CACHIX_AUTH_TOKEN` from `publish`. +Decided 2026-11-05 (maintainer, /quest-audit): `publish` still admits +`main`, so this does not wait for the next cut. + +- ✅ Backport only #7431's workflow change to `release` now, as + [moq-dev/moq#7202](https://github.com/moq-dev/moq/pull/7202) and + [moq-dev/moq#7421](https://github.com/moq-dev/moq/pull/7421) backported + workflow changes, so a tag's run dispatches winget and calls the Kotlin + wrapper itself, and `release`'s apt and rpm dispatches name `--ref release`. +- Not chosen: moving this quest to m2 behind the cut with the other + release-gated CI quests; merging `main` into `release` now, which reverses + the 2026-11-04 decision below. + +What remains, in order: + +1. Open the backport PR against `release` (agent work). +2. Once it merges, the maintainer drops `main` from `publish`'s deployment + policy and removes `DISCORD_WEBHOOK` and `CACHIX_AUTH_TOKEN` from + `publish`. Environment settings need the maintainer's admin access. Decided 2026-11-04 (maintainer, /quest-unblock): ✅ cut the combined patch release on `release` soon, once [moq-dev/moq#7596](https://github.com/moq-dev/moq/pull/7596)'s diff --git a/quest/m0/ffi-shutdown-backport.md b/quest/m0/ffi-shutdown-backport.md index 100d5c10820..7acdbbeddb6 100644 --- a/quest/m0/ffi-shutdown-backport.md +++ b/quest/m0/ffi-shutdown-backport.md @@ -2,17 +2,14 @@ ## Goal -The `release` line's hand-written wrappers that gained `drain()` in -[moq-dev/moq#6642](https://github.com/moq-dev/moq/pull/6642) are on their -registries: +The `release` line's hand-written Dart wrapper that gained `drain()` in +[moq-dev/moq#6642](https://github.com/moq-dev/moq/pull/6642), Dart +[`moq`](https://pub.dev/packages/moq) 0.1.1, is on pub.dev. -- Python [`moq-rs`](https://pypi.org/project/moq-rs/) 0.5.2 on PyPI. -- Dart [`moq`](https://pub.dev/packages/moq) 0.1.1 on pub.dev. - -Check: each registry lists the version. Both versions are already set on -`release` (`py/moq-rs/pyproject.toml`, `dart/moq/pubspec.yaml`), so this needs -a publish, not code. Each publish is outward-facing, so the maintainer runs it; -agents do not push tags, dispatch workflows, or bump versions. +Check: pub.dev lists the version. It is already set on `release` +(`dart/moq/pubspec.yaml`), so this needs a tag push, not code. The publish +is outward-facing, so the maintainer runs it; agents do not push tags, +dispatch workflows, or bump versions. ## Plan @@ -23,28 +20,11 @@ from `gh workflow run release-kt-lib.yml --ref release` ([run](https://github.com/moq-dev/moq/actions/runs/40904381781), after [moq-dev/moq#7026](https://github.com/moq-dev/moq/pull/7026)'s fix). -Decided 2026-10-30 (maintainer): `moq-rs` 0.5.2 and Dart `moq` 0.1.1 ship in -the next combined patch cut on `release`, which the maintainer cuts. - -Python: `workflow_run` runs `main`'s `release-py.yml` against the `release` -checkout, which lacked `.github/actions/nix`. The maintainer picked the -backport of that action to `release`, which landed in -[moq-dev/moq#7421](https://github.com/moq-dev/moq/pull/7421). The -`moq-ffi-v0.4.20` tag's chained run -([failed](https://github.com/moq-dev/moq/actions/runs/41038297141)) came before -that merge, and a re-run checks out the same tag commit, so it fails again. -`release`'s `release-py.yml` has no `workflow_dispatch` until the maintainer's -cut carries the manual retry trigger from `main`. What publishes 0.5.2 now: - -- The next `moq-ffi-v*` tag at a `release` commit with the nix action, which - chains Release Py FFI into Release Py. -- A `release` push touching `py/moq-rs/**`, `.github/workflows/release-py.yml`, - or `sh/gh/release.sh`: the push gate publishes, since `release`'s moq-ffi - 0.4.20 is tagged and on PyPI. +Python [`moq-rs`](https://pypi.org/project/moq-rs/) 0.5.2 reached PyPI on +2026-10-31. -After that cut adopts the trigger, the maintainer can retry with -`gh workflow run release-py.yml --ref release`; the same published-wrapper -and published-FFI gates apply. +Decided 2026-10-30 (maintainer): Dart `moq` 0.1.1 ships in the next combined +patch cut on `release`, which the maintainer cuts. Dart: pub.dev publishes `moq` only from a `moq-dart-v*` tag, and only `moq-dart-v0.1.0` exists. Pushing `moq-dart-v0.1.1` at `release`'s head diff --git a/quest/m0/interop-green/README.md b/quest/m0/interop-green/README.md index 32a34d7b31b..f55a5bf7f22 100644 --- a/quest/m0/interop-green/README.md +++ b/quest/m0/interop-green/README.md @@ -4,7 +4,9 @@ The scheduled Interop and Video workflows pass on `main`, so a red run means a new break. Interop has failed every scheduled run since -2026-10-22, and Video fails on a stale expectation. +2026-10-22. Video has passed every scheduled run since 2026-11-02 (for +example [42063654592](https://github.com/moq-dev/moq/actions/runs/42063654592)), +so it only needs to stay green. ## Waiting @@ -58,14 +60,17 @@ showed more causes, fixed in this quest's own PR: 0.14.11 has been released. Remeasured against moq-cli 0.14.12 and moq-relay 0.17.12 with `just test wire-compat --remeasure`. -The P2P data-channel test timed out once, in 41668668824, and passes -locally; triage it if it recurs. +The P2P data-channel test timed out in 41668668824 and again in +[42062226837](https://github.com/moq-dev/moq/actions/runs/42062226837) +(2026-11-05); [its quest](/quest/m0/test-flakes-2/p2p-data-channel.md) under +test flakes owns it. Scheduled run [41863118968](https://github.com/moq-dev/moq/actions/runs/41863118968) (2026-11-04, after every fix above landed) passed the open-GOP recovery case, P2P, and wire-compat. Its only failure was the fallback audio stall above, on `moq-lite-07-wip` in Chromium, which the IETF22 fallback quest -owns. +owns. Scheduled run 42062226837 (2026-11-05) failed only P2P and the same +fallback audio stall in Chromium (`audioStalled:true`). Public API: none. Wire: none. diff --git a/quest/m0/nightly/README.md b/quest/m0/nightly/README.md index 3d0c5dea508..f0dd66c090a 100644 --- a/quest/m0/nightly/README.md +++ b/quest/m0/nightly/README.md @@ -45,6 +45,7 @@ Public API: none. Wire: none. ## Required - [moq-net's ingest fuzz target finds no stall](/quest/m0/nightly/ingest-fuzz.md) - the 13-byte stream that stalls ingest is fixed at its cause and kept as a regression test -- [Nightly's shipping-size check passes](/quest/m0/nightly/shipping-size.md) - js/net, js/watch, and moq-relay growth over 5% is traced to its commits, then shrunk or accepted - [Nightly's Miri job stays inside its time budget](/quest/m0/nightly/miri.md) - both Miri passes go green, with ARM timings inside the 60-minute job and 15-minute-per-test budgets - [Nightly's macOS platform job passes](/quest/m0/nightly/macos.md) - `moq-audio`'s tests compile on macOS again and the websocket version test's timeout is fixed if it recurs +- [The OBS stop-drain test reads no gap](/quest/m0/nightly/obs-stop-drain.md) - OBS and OBS TSan read every delivered frame and the track's end after `Stop()`, with no gap +- [The JS resume model finds no missing groups](/quest/m0/nightly/resume-model.md) - the JS resume model property test hands every reader each group it is owed diff --git a/quest/m0/nightly/miri.md b/quest/m0/nightly/miri.md index b634711efee..8c727194114 100644 --- a/quest/m0/nightly/miri.md +++ b/quest/m0/nightly/miri.md @@ -40,18 +40,22 @@ for 97 tests, with `model::group::test::a_group_has_no_frame_cap` (10,000 writes at about 30 ms each under Miri) past SLOW; #7895 ignores that test under Miri, since it still runs natively in the merge gate. -Remaining: read the next scheduled run's log and record the job duration, both -pass durations, the slowest test, and headroom against both budgets. If the job -nears 60 minutes, split the strict and epoch passes into separate matrix -entries rather than raising the timeout, and keep nextest's 15-minute per-test -cap. A test past SLOW gets a smaller Miri workload. +The first scheduled run after #7895 merged, +[run 42050683248](https://github.com/moq-dev/moq/actions/runs/42050683248) +on 2026-11-05, passed `Tests (rs miri)` with both passes: -Public API: none. Wire: none. +- Job 31 min 26 s, inside the 60-minute timeout. +- Strict pass: 228 tests in 688 s. Slowest + `model::frame::tests::a_delivery_attaching_mid_write_publishes_one_payload` + 192 s, then kio's `task::tests::concurrent_wakes_are_never_lost` 183 s. +- Epoch pass: 97 tests in 832 s, one SLOW: + `model::group::test::debt_sheds_the_front_but_not_the_newest_frame` 335.8 s, + past the 300 s SLOW mark and inside the 900 s cap. -## Waiting +Remaining: shrink `debt_sheds_the_front_but_not_the_newest_frame`'s Miri +workload so it finishes under SLOW, as #7895 did for the strict pass's +slowest tests. If the job nears 60 minutes, split the strict and epoch passes +into separate matrix entries rather than raising the timeout, and keep +nextest's 15-minute per-test cap. -- moq-dev/moq: After [moq-dev/moq#7895](https://github.com/moq-dev/moq/pull/7895) - lands, the next scheduled Nightly on `main` must pass `Tests (rs miri)` on - `ubuntu-24.04-arm` with both passes. Read its log - (`gh run view --repo moq-dev/moq --log`) and record the timings above; - local runs do not clear this wait. +Public API: none. Wire: none. diff --git a/quest/m0/nightly/obs-stop-drain.md b/quest/m0/nightly/obs-stop-drain.md new file mode 100644 index 00000000000..aa46b2af6c6 --- /dev/null +++ b/quest/m0/nightly/obs-stop-drain.md @@ -0,0 +1,33 @@ +# [S] The OBS stop-drain test reads no gap + +## Goal + +Nightly's `Nightly (OBS)` and `Nightly (OBS TSan)` jobs pass the +`stop drains the session` case of `cpp/obs/test/moq-output-test.cpp`: after +`Stop()`, a subscriber reads every frame the session delivered and then the +track's end, with no gap. Find the root cause and fix it there, not by +loosening the assertion. + +## Plan + +Added 2026-11-05 (maintainer, /quest-audit), from scheduled Nightly +[run 42050683248](https://github.com/moq-dev/moq/actions/runs/42050683248). +Both [OBS](https://github.com/moq-dev/moq/actions/runs/42050683248/job/127325639496) +and [OBS TSan](https://github.com/moq-dev/moq/actions/runs/42050683248/job/127325639711) +failed the same check: + +```text +FAIL test/moq-output-test.cpp:909: !std::holds_alternative((*result)->get_variant()) +``` + +The 2026-11-04 scheduled run +([41852517544](https://github.com/moq-dev/moq/actions/runs/41852517544/job/126652295686)) +failed the same line; the 2026-11-03 run +([41656613559](https://github.com/moq-dev/moq/actions/runs/41656613559)) +passed both jobs, so start with what landed on `main` between them. The test +writes a 2 MiB keyframe just before `Stop()` and reads after the relay sees +the session close, so a gap means the relay or the container consumer reports +a group the session did not finish delivering, or the drain cut the large +frame off. + +Public API: none expected. Wire: none expected. diff --git a/quest/m0/nightly/resume-model.md b/quest/m0/nightly/resume-model.md new file mode 100644 index 00000000000..ec1febe1986 --- /dev/null +++ b/quest/m0/nightly/resume-model.md @@ -0,0 +1,33 @@ +# [S] The JS resume model finds no missing groups + +## Goal + +Nightly's `Tests (test resume-model)` passes: the JS resume model property +test (`js/net/src/resume.model.test.ts`) hands every reader each group its +spec owes on every generated case. Find the root cause and fix it in +`@moq/net`, or in the model if the model is wrong. + +## Plan + +Added 2026-11-05 (maintainer, /quest-audit), from scheduled Nightly +[run 42050683248](https://github.com/moq-dev/moq/actions/runs/42050683248/job/127325640208). +The Rust half (`model::resume_model::readers_match_the_logical_track`) +passed; the JS half failed: + +```text +error: Property failed after 2700 tests +error: reader 0: missing groups 2,3,4,5,6,7,8,9,10; handed out 1,11,0, dropped , floor undefined, spec {"ordered":false,"budget":"hour","drops":false} +``` + +Replay it with `MOQ_RESUME_SEED=764723972 just test resume-model`. The shrunk +counterexample: instance 1 brings up slots 1 and 2, reader 0 joins unordered +with an hour budget, slot 1 writes group 11 and slot 2 group 1, slot 2 goes +down, slot 1 ends, and reader 0 joins again. + +The two earlier scheduled runs failed this job with a different symptom, +`the track ended cleanly though no route declared an end` +([41852517544](https://github.com/moq-dev/moq/actions/runs/41852517544/job/126652296304), +[41656613559](https://github.com/moq-dev/moq/actions/runs/41656613559/job/125988510774)). +Check whether one cause explains both before closing this. + +Public API: none expected. Wire: none. diff --git a/quest/m0/nightly/shipping-size.md b/quest/m0/nightly/shipping-size.md deleted file mode 100644 index f828ce9d01c..00000000000 --- a/quest/m0/nightly/shipping-size.md +++ /dev/null @@ -1,79 +0,0 @@ -# [S] Nightly's shipping-size check passes - -## Goal - -Nightly's shipping-size check passes on `main`. Every growth over its 5% -threshold is traced to the commits that caused it. Each is then shrunk back, -or accepted as a new baseline with the reason recorded. - -## Plan - -Decided 2026-11-03 (maintainer, /quest-plan of the follow-ups from -[moq-dev/moq#7667](https://github.com/moq-dev/moq/pull/7667)): milestone m0, -a child of the Nightly epic. - -The [2026-11-03 shipping-size job](https://github.com/moq-dev/moq/actions/runs/41656613559/job/126039954216) -failed nine daily comparisons between -[dde50c699f](https://github.com/moq-dev/moq/commit/dde50c699f69507ced243754c2f700a6184d1576) -and [801fd9a2f2](https://github.com/moq-dev/moq/commit/801fd9a2f2f5c88371fa833d805620d97d372465). -[Investigation PR](https://github.com/moq-dev/moq/pull/7813) records every failing -measurement and its attribution evidence: - -- Rebuilt both JS endpoints and all 18 intervening JS/lockfile commits. All 21 - retained endpoint measurements reproduce exactly. Net raw grows 22,656 bytes; - watch raw grows 30,479. Subscription ranges contribute 17,090 and 17,111 - respectively, and stats/feedback adds 6,787 watch bytes. The remaining deltas, - including every failing compression format, are attributed in the PR. -- Bigint group IDs are excluded as a cause: their merge happened after the - failed Nightly commit. -- All four downloaded relay archives and executable code sections grew. Native - x86_64 Linux symbol attribution identifies new rind and rind-rustls alongside - transport's retained AWS-LC. The PR separates local diagnostic builds from - the actual shipping archive sizes. Native per-commit attribution on macOS, - aarch64 Linux, and Windows MSVC remains unfinished; do not label the Linux - measurements as those targets' results. -- The daily baseline already advances after a threshold failure. The failed - run retained its current point, and there was no thirty-day anchor yet. - `sh/size/README.md` documents acceptance using retained history, and tests - cover both daily advancement and the surviving thirty-day guard. A step over - 10% can still fail until a post-jump point becomes the thirty-day anchor; - recording acceptance alone does not waive that check. Summaries now identify - the current and failing baseline commits. - -Decided 2026-11-04 (maintainer, on the investigation PR): - -- ✅ Accept the exactly attributed JS growth (`js/net` and `js/watch`, - +5.02–5.28%) as the cost of the retained features and correctness fixes. - The PR's per-commit table is the acceptance record; the retained November 3 - point is the new daily baseline. -- Require further JS reduction while retaining those behaviors. - -- ✅ Keep the 5% daily and 10% thirty-day guards unchanged. -- Raise or exempt the guards for this step. - -Relay archive acceptance stays open until native per-commit attribution for -macOS, aarch64 Linux, and Windows MSVC is supplied, or the maintainer -explicitly accepts the evidence limit. Keep the retained history intact. -[Size audit](/quest/m2/audit-size.md) owns the release-time view. - -Public API: none. Wire: none. - -## Waiting - -- moq-dev/moq: native per-commit relay archive attribution for macOS, aarch64 - Linux, and Windows MSVC. Windows needs a matching build host; none of the - listed SSH hosts runs Windows. macOS needs the pinned Nix toolchain rather - than kixtop's ambient Rust. Supply before/after archive measurements for the - responsible commits rather than substituting Linux `cargo bloat` estimates, - then put relay acceptance to the maintainer. -- moq-dev/moq: inspect the next scheduled Nightly shipping-size job on main, - its measured revision and retained baseline, for passing JS daily - comparisons and, when an anchor exists, thirty-day comparisons. If a - thirty-day comparison still fails, reduction or further acceptance work - remains, potentially until the post-jump point is thirty days old. No manual - Nightly dispatch; retain this quest until that evidence and the relay - attribution are settled. - -## Related - -- [Size audit](/quest/m2/audit-size.md) - pre-cut size investigation and the post-release refresh diff --git a/quest/m0/test-flakes-2/README.md b/quest/m0/test-flakes-2/README.md index 60278571419..18adb23b633 100644 --- a/quest/m0/test-flakes-2/README.md +++ b/quest/m0/test-flakes-2/README.md @@ -37,8 +37,9 @@ Added 2026-10-21 and 2026-10-22 (maintainer): failures from the m0/m1 merge runs, one child each. Decided 2026-10-26 (maintainer): the epic moved from m1 to m0, since every -flake now fails a whole batch of the [batched merge gate](https://github.com/moq-dev/moq/blob/17a81d6c64/quest/m0/ci/land.md) -rather than one PR. The queue's recurring flakes from 2026-10-23 to 10-26 +flake drops a queued PR from the merge queue (it then failed a whole batch of +the [batched merge gate](https://github.com/moq-dev/moq/blob/17a81d6c64/quest/m0/ci/land.md), +dropped 2026-11-01). The queue's recurring flakes from 2026-10-23 to 10-26 were already fixed (the moq-rtsp stall tests, the moq-gst pinned-instance and sibling-restart tests, the moq-mux missing-sequence test, `js/common/worklet.test.ts`, and the IETF datagram range test in @@ -91,6 +92,9 @@ from 2026-11-03 and early 2026-11-04 UTC, one child each. Added 2026-11-04 (maintainer, `/quest-plan`): moq-gst's interleaved restart test, which failed two merge-queue batches and two loaded local runs. +Added 2026-11-05 (maintainer, `/quest-audit`): Interop's P2P data-channel +timeout, one child. + Public API: none. Wire: none. ## Required @@ -102,4 +106,4 @@ Public API: none. Wire: none. - [release.test.ts never reaches the network](/quest/m0/test-flakes-2/release-test-offline.md) - the JSR release test fakes its registry lookup and passes offline - [Diagnose and re-enable the FFI datagram connection test](/quest/m0/test-flakes-2/ffi-datagram-roundtrip.md) - diagnose the default-connection timeout and re-enable the quarantined test - [Test PulseAudio servers stay off the desktop's D-Bus](/quest/m0/test-flakes-2/pulse-dbus.md) - concurrent media runs on one desktop never collide on `org.PulseAudio1` -- [The open-GOP browser fixture fails loudly](/quest/m0/test-flakes-2/open-gop-fixture.md) - its broadcast stub matches current stats dependencies and an effect exception fails the test +- [The P2P data-channel test transfers its frame](/quest/m0/test-flakes-2/p2p-data-channel.md) - Interop's two-peer data-channel test stops stalling after a failed send diff --git a/quest/m0/test-flakes-2/open-gop-fixture.md b/quest/m0/test-flakes-2/open-gop-fixture.md deleted file mode 100644 index 216b79ee669..00000000000 --- a/quest/m0/test-flakes-2/open-gop-fixture.md +++ /dev/null @@ -1,20 +0,0 @@ -# [XS] The open-GOP browser fixture fails loudly - -## Goal - -The open-GOP browser test (`test/interop/clients/js/open-gop.browser.ts`) -exercises current `@moq/watch` code: its broadcast stub satisfies the stats -dependencies the player now reads, and an exception inside the fixture's -effect fails the test directly instead of being swallowed. - -## Plan - -Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the -2026-11-05 /quest-complete run), from -[moq-dev/moq#7716](https://github.com/moq-dev/moq/pull/7716). Milestone: ✅ m0. - -The stub lives in `test/interop/clients/js/open-gop/main.ts`. Prefer building -the stub from the real types so the next dependency change fails to compile -rather than at runtime. - -Public API: none. Wire: none. diff --git a/quest/m0/test-flakes-2/p2p-data-channel.md b/quest/m0/test-flakes-2/p2p-data-channel.md new file mode 100644 index 00000000000..7993d1d4c1d --- /dev/null +++ b/quest/m0/test-flakes-2/p2p-data-channel.md @@ -0,0 +1,27 @@ +# [S] The P2P data-channel test transfers its frame + +## Goal + +Interop's P2P test (`test/p2p/transport.browser.ts`, two browser peer +connections completing MoQ SETUP and transferring a frame without a relay) +passes in scheduled Interop runs. Find the root cause and fix it, never by +raising the test's timeout or adding a retry. + +## Plan + +Added 2026-11-05 (maintainer, /quest-audit), from scheduled Interop +[run 42062226837](https://github.com/moq-dev/moq/actions/runs/42062226837/job/127366882573). +`window.checkTransport()` never returned, so the test timed out after +60000 ms at `test/p2p/transport.browser.ts:46`. Chromium logged one data +channel error just before: + +```text +ERROR:third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc:867] Send failedINVALID_STATE +``` + +A send on a data channel that was not open (or already closing) failed, and +the transfer then stalled instead of failing. It timed out once before, in +[41668668824](https://github.com/moq-dev/moq/actions/runs/41668668824), and +passed locally then. + +Public API: none expected. Wire: none. diff --git a/quest/m1/README.md b/quest/m1/README.md index a9508e32f65..4e98d4242ec 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -101,8 +101,9 @@ crashes and amplification in media and RTMP parsing, lite announce bounds, JS track terminal causes, browser element teardown, and smaller Rust/JS divergences, under one epic; its redesign proposals went to m2. -Changed 2026-10-26 (maintainer): pure-Rust crypto moved to m3 until upstream -graviola and ACME releases make it cheap, so the cut ships on aws-lc-rs. +Decided 2026-10-26 (maintainer): every MoQ crate takes its crypto from +[rind](/quest/m1/rind/README.md), a pure-Rust graviola fork, so the cut ships +no C crypto. This supersedes the same day's move of pure-Rust crypto to m3. Dropping the `rsa` crate from moq-auth's production graph stays in m1. Added 2026-10-25 (maintainer): the studio's @@ -137,18 +138,26 @@ Added 2026-11-04 (maintainer): the relay reports the native sessions its drain deadline force-closes while still open, apart from those only finishing their end report, so an embedder's drain alert pages on real cuts. +Decided 2026-11-05 (maintainer, /quest-audit): blockers rank above the +quests that require them. + +- ✅ Move the blockers up: Drop set and Subscribe ranges rank just above + Address groups by timestamp, and the API audit just above Cluster routing. +- Not chosen: moving the dependents down; leaving the order as it was. + ## Required +- [Drop set](/quest/m1/drop-set.md) - each cursor judges missing groups against its own budget, so a narrow reader drops promptly and a widening re-offers groups already reported dropped on lite-07 +- [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - a lite-07 SUBSCRIBE asks for past and live ranges with absolute or relative ends, in either order, and replaces FETCH for multi-group reads (single-group FETCH stays); merged ranges never starve a subscriber; relays fill misses by range, including over moq-transport - [Address groups by timestamp](/quest/m1/time-addressing/README.md) - group start timestamps replace sequence numbers in the moq-net API and lite-07 wire, while old subscribers, old publishers, and published JS clients keep working - [Pre-cut audit findings](/quest/m1/cut-audit/README.md) - fix the crashes, hostile-input costs, and correctness bugs the 2026-10-24 audit of main found - [Vendored code has every upstream fix it needs](/quest/m1/vendor-sync/README.md) - quinn, libv4l-rs, nvidia-video-codec-sdk, rust-media-libs, cros-codecs, and UniFFI generator fixes are ported or planned, once per release cycle - [Media fuzz findings](/quest/m1/fuzz-findings/README.md) - the nightly media fuzz targets run clean: mp4-atom, MKV block, TS step, SPS overflow, and catalog encoder bugs they found are fixed +- [A smaller, safer API than release](/quest/m1/api-audit/README.md) - every surface added since release has a consumer or is gone, overlapping operations are collapsed, names mirror across Rust, JS, and the bindings, and every break says how to migrate - [Cluster routing](/quest/m1/cluster-routing/README.md) - prove shared routing contracts, implement per-origin routes, and connect outbound local clusters - [Routing guide](/quest/m1/routing-guide.md) - concepts and practical outbound federation setup - [moq-c at parity](/quest/m1/c/README.md) - the hand-written `moq-c` ships at the cut with every m1 binding feature moq-ffi gains - [A job's exact route continues its claim's readers](/quest/m1/announce-takeover.md) - a job's route inherits its claim's instance, replacing the ANNOUNCE_TAKEOVER predecessor design -- [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - a lite-07 SUBSCRIBE asks for past and live ranges with absolute or relative ends, in either order, and replaces FETCH; merged ranges never starve a subscriber; relays fill misses by range, including over moq-transport -- [Drop set](/quest/m1/drop-set.md) - each cursor judges missing groups against its own budget, so a narrow reader drops promptly and a widening re-offers groups already reported dropped on lite-07 - [A reader on a failed copy continues on the held re-offer](/quest/m1/copy-recover.md) - a live reader keeps a group whose copy fails by continuing on the same track's re-offer at the same frame - [Group errors are cached by kind](/quest/m1/group-error-cache.md) - permanent group errors bind every reader, retryable ones are kept only for a bounded time, and a live SUBSCRIBE_DROP or FETCH answered `Old` no longer caches it for good - [A group a subscriber gives up on is always reported](/quest/m1/group-drops.md) - the wire names every abandoned group and the drop signal is public, so readers count losses instead of stalling @@ -158,7 +167,6 @@ their end report, so an embedder's drain alert pages on real cuts. - [Stream credit by priority](/quest/m1/stream-credit/README.md) - every stream opens through one priority entry point, and a higher-priority group takes over or resets a lower one when credit runs out - [Finalize moq-lite-07](/quest/m1/lite07-finalize.md) - when the maintainer cuts it, lite-07 negotiates as `moq-lite-07` and the next release ships it - [Sockets](/quest/m1/socket/README.md) - a generic dial/accept `Socket` in moq-net, Rust, JS, and Python, with tracks as streams; moq-boy and CARLA move onto it -- [A smaller, safer API than release](/quest/m1/api-audit/README.md) - every surface added since release has a consumer or is gone, overlapping operations are collapsed, names mirror across Rust, JS, and the bindings, and every break says how to migrate - [Audio jitter target](/quest/m1/audio-jitter-target/README.md) - the playout target is default in both languages; time-stretched browser playback without steady-state underruns and a native trace replay remain - [A/V clock](/quest/m1/av-clock.md) - the audio playhead drives Sync.reference while audio plays, through per-track sync handles - [Container reads drop backfill](/quest/m1/read-backfill.md) - the JS container consumer drops groups below its read cursor like Rust @@ -167,7 +175,7 @@ their end report, so an embedder's drain alert pages on real cuts. - [Push-to-talk's press-to-audible latency fits a budget on the defaults](/quest/m1/push-to-talk-latency.md) - press to audible on the browser defaults, excluding device output, stays under a kixtop-measured budget that `just test push-to-talk` enforces - [TS fidelity and recovery](/quest/m1/ts-reliability/README.md) - both modes have explicit profiles, automated validation, loss tests, and a dedicated guide - [WebGPU on Safari](/quest/m1/webgpu-safari.md) - the WebGPU renderer is verified on Safari 26 for macOS and iOS -- [CI housekeeping](/quest/m1/ci-housekeeping.md) - remove the actionlint queue ignore once a release after 1.7.12 reaches the dev shell +- [Remove the moq-e2ee stub](/quest/m1/moq-e2ee-remove.md) - `rs/moq-e2ee` leaves the workspace and release config now that its final release points to moq-crypto - [crates.io trusts the workflow](/quest/m1/crates-trusted-publisher.md) - maintainer action: every published crate gets a trusted publisher for `release-rs.yml` - [Rust releases publish through OIDC](/quest/m1/release-rs-oidc.md) - release-plz publishes with trusted publishing and `CARGO_REGISTRY_TOKEN` is revoked - [Main is no slower than release](/quest/m1/release-perf/README.md) - every benchmark where main is slower than release is fixed or accepted with a reason, checked by a final paired run before the cut @@ -182,7 +190,3 @@ their end report, so an embedder's drain alert pages on real cuts. - [Rename moq-rtc to moq-webrtc](/quest/m1/webrtc-rename.md) - one published `moq-webrtc` crate holds the gateway, the ICE driver, and the data-channel transport - [Vendor and trim the WebRTC stack](/quest/m1/webrtc-vendor.md) - str0m, dimpl, `is`, and sctp-proto live in moq-webrtc with unused code removed, so moq-rtc can take rind - [MoQ on rind](/quest/m1/rind/README.md) - every MoQ crate takes its crypto from rind, a pure-Rust graviola fork, so no build compiles C crypto - -## Related - -- [A busy js/net serve yields](https://github.com/moq-dev/moq/pull/5289) - js/net's serve loop leaves the browser its event loop under a fast publisher, if it does not already diff --git a/quest/m1/announce-takeover.md b/quest/m1/announce-takeover.md index 2de4418c268..a3ce22adc95 100644 --- a/quest/m1/announce-takeover.md +++ b/quest/m1/announce-takeover.md @@ -121,26 +121,30 @@ Remove the cold-start warm-up reads (`claimed` in assert that the first subscription succeeds. Keep them for moq-transport. Run `just check`, `just test interop --all` and `just drafts check`. -### Once identity replaces ANNOUNCE_TAKEOVER +### Once the instance replaces ANNOUNCE_TAKEOVER Decided 2026-10-31 (maintainer, the /quest-complete requeue session). Kept separate from the identity rewrite of this Plan, which landed with [moq-dev/moq#7420](https://github.com/moq-dev/moq/pull/7420). -"We're replacing EPOCH with IDENTITY soon" (maintainer, 2026-10-31). +"We're replacing EPOCH with IDENTITY soon" (maintainer, 2026-10-31). The +broadcast "identity" was renamed `instance` on 2026-11-01 (maintainer, in +[the route API audit](/quest/m1/api-audit/route/README.md), landed in +[moq-dev/moq#7489](https://github.com/moq-dev/moq/pull/7489)), so that +IDENTITY is now the instance. -- Reword "takeover" as an event or operation, in terms of identity +- Reword "takeover" as an event or operation, in terms of instance continuity, in [moq-bench pins the instances it measures](/quest/m2/bench-epoch-pin.md) (Goal and Plan), [the HLS server follows each path once](/quest/m2/hls-follow-once.md) (Goal and Tests), and [lite-07 route wire](/quest/m1/cluster-routing/routes/wire.md) (the wire sketch, "the separately proven Takeover operation"). - Rewrite the EPOCH references in `drafts/draft-lcurley-moq-cluster.md` and - `drafts/draft-lcurley-moq-epoch.md` in terms of IDENTITY. + `drafts/draft-lcurley-moq-epoch.md` in terms of the instance. - Add a regression test where a publisher restart's new announcement arrives before the old one's reset, on `solicit = false` moq-transport sessions. [moq-dev/moq#7239](https://github.com/moq-dev/moq/pull/7239) found that the subscriber (`rs/moq-net/src/ietf/subscriber.rs`, `attach`) folds such a PUBLISH_NAMESPACE into the same epochless route as an update - instead of End then Start; per-announcement identities resolve it, and + instead of End then Start; per-announcement instances resolve it, and the test proves they do. Public API: breaking; removes `Takeover` and the predecessor fields in every diff --git a/quest/m1/api-audit/README.md b/quest/m1/api-audit/README.md index c02205b885e..ed1b3f2929e 100644 --- a/quest/m1/api-audit/README.md +++ b/quest/m1/api-audit/README.md @@ -53,9 +53,10 @@ audit skips them: InvalidRange, Remote, UnsupportedExtension}`, the `DecodeError` auth-token variants) and the session error codes the lite draft registers with moq-transport's meaning. Errors are fine; only dead ones go. -- `setup::Extensions::{auth, solicit, epoch}` and the relay's +- `setup::Extensions::{auth, solicit}` and the relay's `[listen|connect.extensions]` TOML, as interop knobs documented as - affecting moq-transport only. + affecting moq-transport only. `epoch` went with moq-transport's epochs in + [moq-dev/moq#7239](https://github.com/moq-dev/moq/pull/7239). Rejected in planning: diff --git a/quest/m1/audio-jitter-target/native-stretch.md b/quest/m1/audio-jitter-target/native-stretch.md index f14c509dc67..fc024d27efa 100644 --- a/quest/m1/audio-jitter-target/native-stretch.md +++ b/quest/m1/audio-jitter-target/native-stretch.md @@ -16,10 +16,12 @@ specifies it. ## Plan Decided 2026-11-03 (maintainer, on -[moq-dev/moq#7679](https://github.com/moq-dev/moq/pull/7679)): copy NetEq in m1. -The implementation now ports its received-audio accelerate and preemptive -expand into the native playback callback. The estimator is unchanged. -`doc/concept/audio-jitter.md` specifies the shared floating-point algorithm; +[moq-dev/moq#7679](https://github.com/moq-dev/moq/pull/7679)): copy NetEq in +m1. The implementation, merged 2026-11-04 in +[moq-dev/moq#7856](https://github.com/moq-dev/moq/pull/7856), ports its +received-audio accelerate and preemptive expand into the native playback +callback. The estimator is unchanged. `doc/concept/audio-jitter.md` specifies +the shared floating-point algorithm; `doc/concept/audio-jitter/stretch/corpus.json` supplies literal PCM vectors for both languages. The browser half remains [Watch](/quest/m1/audio-jitter-target/watch.md); neither implementation waits @@ -92,9 +94,9 @@ until the seven-nightly calibration below. audible. Recommend this check before claiming the perceptual goal; automated amplitude tests cannot decide it. Run it in `~/work/moq` on `kixtop`, with its speakers or headphones as - the default output, at - [moq-dev/moq#7856](https://github.com/moq-dev/moq/pull/7856)'s head - (`gh pr checkout 7856 --detach`), or `main` once it lands. The source is + the default output, on `main`, where + [moq-dev/moq#7856](https://github.com/moq-dev/moq/pull/7856) landed. The + source is macOS's `say` voice reading `LICENSE-APACHE`, about ten minutes of continuous speech, so nothing is downloaded (an archive's speech file returned 403): diff --git a/quest/m1/audio-jitter-target/watch.md b/quest/m1/audio-jitter-target/watch.md index 74f5dc24c53..45df4373602 100644 --- a/quest/m1/audio-jitter-target/watch.md +++ b/quest/m1/audio-jitter-target/watch.md @@ -121,11 +121,16 @@ are expanding sooner or more often as the ring nears empty, or accepting the remaining re-stalls. Each departure from NetEq's constants is recorded with the replay numbers that justify it. +- Port the shared specification rather than NetEq independently: + [moq-dev/moq#7856](https://github.com/moq-dev/moq/pull/7856) landed the + native stretch with `doc/concept/audio-jitter.md` specifying the shared + floating-point adaptation and `doc/concept/audio-jitter/stretch/corpus.json` + holding literal PCM vectors for both languages. Implement that spec and + pass those vectors, so both players stretch alike; record any departure + from it in the spec, not only here. - Put the stretch where `js/watch/src/audio/replay.ts` exercises it, such as `AudioRingBuffer`'s read path or a module the render worklet and the replay - share, so the replay rows measure the stretch and not a model of it. Port - the search with unit tests against NetEq's behaviour on synthetic periodic - and noise signals. + share, so the replay rows measure the stretch and not a model of it. - Accelerate replaces the skip-ahead when the ring sits above the high limit. A re-stall remains for a ring that empties despite the stretch, and a skip-ahead remains only above what fast accelerate can close. diff --git a/quest/m1/bench-publish.md b/quest/m1/bench-publish.md index abe57c3f32e..97026b1709d 100644 --- a/quest/m1/bench-publish.md +++ b/quest/m1/bench-publish.md @@ -32,8 +32,10 @@ Decided 2026-11-05 (maintainer, /quest-plan): Today the crate has three `[[bin]]`s (`rs/moq-bench/Cargo.toml`): `moq-bench` (`src/main.rs`), `moq-bench-host` (`src/host.rs`, Linux-only), and `moq-bench-uring-check` (`src/uring.rs`, 15 lines, behind the `uring` -feature). Only `bench/run.sh` runs the probe, and nothing else uses the -`uring` feature, so the feature goes with it. Put the probe wherever +feature). `bench/run.sh` runs the probe, `bench/profile.test.py` stubs its +binary, and `bench/metadata.py` names the `moq-bench/uring` feature in its +runtime and profile descriptions; nothing else uses the feature, so it goes +with the probe and those three callers follow. Put the probe wherever `bench/run.sh` can still build it with the least new surface; a `moq-uring` example is the likely fit. On a non-Linux host, `moq-bench host` errors the way the bin does today. diff --git a/quest/m1/c/README.md b/quest/m1/c/README.md index 7e1845fc16c..46134f1af4e 100644 --- a/quest/m1/c/README.md +++ b/quest/m1/c/README.md @@ -2,11 +2,11 @@ ## Goal -The hand-written `moq-c` crate (`rs/moq-c`, `moq.h`) ships at this cut as -`moq-c` 0.7 with every binding feature moq-ffi gains in m1, so a C user can do -whatever a Python, Swift, Kotlin, Go, Dart, or C++ user can. The C interop -client and every `doc/lib/c` sample build and run against the built release -archive before the cut. +The hand-written `moq-c` crate (`rs/moq-c`, `moq.h`) ships at this cut at the +shared 0.22 minor with every binding feature moq-ffi gains in m1, so a C user +can do whatever a Python, Swift, Kotlin, Go, Dart, or C++ user can. The C +interop client and every `doc/lib/c` sample build and run against the built +release archive before the cut. ## Plan @@ -14,7 +14,11 @@ Decided 2026-10-25 (maintainer): the hand-written crate ships at this cut and the [generated C line](/quest/m2/c/README.md) moves after it, waiting on the switch to rust2's UniFFI fork. The generated package (`c/moq`) builds in CI, but it publishes only after the cut. C users break -twice (0.6 to 0.7, then to the generated 0.8); that is the accepted cost. +twice (to 0.22 at this cut, then to the generated package at a later cut); +that is the accepted cost. moq-c follows the shared minor like every +published package (CONTRIBUTING.md's [Versions](/CONTRIBUTING.md#versions), +[moq-dev/moq#7610](https://github.com/moq-dev/moq/pull/7610)), not a 0.7 +then 0.8 line of its own. - moq-c is not frozen: it takes the same breaks as moq-ffi and the other bindings. Every m1 quest or PR that changes the binding API changes diff --git a/quest/m1/ci-housekeeping.md b/quest/m1/ci-housekeeping.md deleted file mode 100644 index 28edcf9ab71..00000000000 --- a/quest/m1/ci-housekeeping.md +++ /dev/null @@ -1,20 +0,0 @@ -# [XS] Remove the actionlint queue-key workaround - -## Goal - -`.github/actionlint.yaml` drops its ignore for the `queue` key once an -actionlint release after 1.7.12 is in the dev shell. - -## Plan - -[rhysd/actionlint#661](https://github.com/rhysd/actionlint/pull/661) is merged -but unreleased. The dev shell still has actionlint 1.7.12. -[moq-dev/moq#6180](https://github.com/moq-dev/moq/pull/6180) added the ignore -for the three Pages publishing workflows; remove it when the release reaches -nixpkgs and `just gh check` accepts `queue: max`. - -Public API: none. Wire: none. - -## Related - -- [CI workflow audit](/quest/m2/audit-ci.md) - the broader per-job review diff --git a/quest/m1/cluster-routing/federation.md b/quest/m1/cluster-routing/federation.md index 00742dcfb68..03ff65e0b22 100644 --- a/quest/m1/cluster-routing/federation.md +++ b/quest/m1/cluster-routing/federation.md @@ -17,22 +17,23 @@ connection protocol. Do not require an inbound connection to the local relay. Use authenticated, namespace-scoped admission: the CDN scopes the local relay's connection to a path prefix, and identities it sends, its own and its local publishers', are qualified, so a forger or a misconfigured uplink only -affects its own scope (decided 2026-10-14; see -[Routes and announces](/quest/m1/cluster-routing/routes/README.md)). Open: how -those identities are keyed, owned by -[Route session integration](/quest/m1/cluster-routing/routes/session.md). Without a key, a scoped forger -declaring a victim's id captures claims outside its scope -(`forged_identity_hijacks_claims_outside_the_forgers_scope`). The scope -itself (`hash(scope, id)`) was rejected 2026-10-15, and the grant's -issuer-qualified subject (`hash(subject, id)`) was dropped 2026-11-02 -(maintainer). The key must survive token refresh and be shared by the local -relay's two uplinks. A scoped -connection cannot forward an already qualified identity, so nested scoped -federation is out: a relay behind the local relay connects unscoped. The local relay -marks its CDN links `upstream`, so CDN relays never shortcut through the -local network, and keeps its local `proxy` preference on toward the CDN. One -route selection per identity; a cheaper exportable alternative hidden behind -a preferred down-only route is accepted (decided 2026-10-14). +affects its own scope (decided 2026-10-14; see [Routes and +announces](/quest/m1/cluster-routing/routes/README.md)). Decided 2026-11-04 +(maintainer): those identities are keyed by the route key the peer proves, +read from a key file the local relay's uplinks share ([Route session +integration](/quest/m1/cluster-routing/routes/session.md), [Scoped peers prove +a route key](/quest/m1/cluster-routing/routes/proof.md)). Without a key, a +scoped forger declaring a victim's id captures claims outside its scope +(`forged_identity_hijacks_claims_outside_the_forgers_scope`). The scope itself +(`hash(scope, id)`) was rejected 2026-10-15, and the grant's issuer-qualified +subject (`hash(subject, id)`) was dropped 2026-11-02 (maintainer). The key +must survive token refresh and be shared by the local relay's two uplinks. A +scoped connection cannot forward an already qualified identity, so nested +scoped federation is out: a relay behind the local relay connects unscoped. +The local relay marks its CDN links `upstream`, so CDN relays never shortcut +through the local network, and keeps its local `proxy` preference on toward +the CDN. One route selection per identity; a cheaper exportable alternative +hidden behind a preferred down-only route is accepted (decided 2026-10-14). CDN content still flows into the local network and local content out: a local relay whose own uplink died reaches the CDN, in both directions, through a @@ -67,5 +68,6 @@ Rust/JS parity. Run `just check`, `just test interop --all`, and `just drafts ch ## Related +- [Scoped peers prove a route key](/quest/m1/cluster-routing/routes/proof.md) - the key this connection's identities are qualified under - [Route health](/quest/m2/route-health/README.md) - epoch-only detection of stalled delivery on still-open links - [Routing guide](/quest/m1/routing-guide.md) - runnable operator setup after integration diff --git a/quest/m1/cluster-routing/routes/README.md b/quest/m1/cluster-routing/routes/README.md index 7793203f1fe..f3960691cf1 100644 --- a/quest/m1/cluster-routing/routes/README.md +++ b/quest/m1/cluster-routing/routes/README.md @@ -133,8 +133,11 @@ The wire sketch is in [wire](/quest/m1/cluster-routing/routes/wire.md); the bull claim no longer decides transit trust. Legitimate scoped delivery survives losing one of two uplinks under one key (`scoped_delivery_through_two_uplinks_reaches_one_key`). -- Open: how a scoped peer's routing identities are keyed, owned by - [session integration](/quest/m1/cluster-routing/routes/session.md). The router takes the key from the caller (`Scope::qualify`). +- Decided 2026-11-04 (maintainer): a scoped peer's routing identities are + keyed by the route key the peer proves, from a shared key file + ([session integration](/quest/m1/cluster-routing/routes/session.md), + [Scoped peers prove a route key](/quest/m1/cluster-routing/routes/proof.md)). + The router takes the key from the caller (`Scope::qualify`). - Decided 2026-10-14: qualified keys carry a marker every relay recognizes, and a scoped connection forwarding an already qualified identity has that route refused, with no wire change. Otherwise a key sent down through a diff --git a/quest/m1/copy-recover.md b/quest/m1/copy-recover.md index 8d37bc202d8..a67c5c1079e 100644 --- a/quest/m1/copy-recover.md +++ b/quest/m1/copy-recover.md @@ -7,12 +7,6 @@ group: its `group::Consumer` continues on the successor copy the held re-offer carries in the same track, at the same frame, instead of surfacing the failure. Rust and `js/net` behave the same. -## Waiting - -- moq-dev/moq: [moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670) - merges. It adds the held re-offer (its decision 24) this builds on. Check - that it is merged into `main`. - ## Plan Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the @@ -24,8 +18,13 @@ path. A successor that diverges from what the reader already consumed fails the reader, as a route switch does. Test on mock time: a reader mid-group on a copy that fails continues on the re-offer with no duplicate or missing frame. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ the wait on +[moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670), Drop set's own +PR, becomes a `Required` link to [Drop set](/quest/m1/drop-set.md), since +#7670 adds the held re-offer (its decision 24) this builds on. + Public API: none expected. Wire: none. -## Related +## Required -- [Drop set](/quest/m1/drop-set.md) - reworks the re-offer path this reads from +- [Drop set](/quest/m1/drop-set.md) - adds the held re-offer this builds on diff --git a/quest/m1/crates-trusted-publisher.md b/quest/m1/crates-trusted-publisher.md index daea9e07345..7c5828c6168 100644 --- a/quest/m1/crates-trusted-publisher.md +++ b/quest/m1/crates-trusted-publisher.md @@ -43,3 +43,8 @@ publishing through OIDC. Done 2026-11-04 (maintainer, /quest-unblock): all 31 published crates have the trusted publisher. Only the 7 unpublished crates remain. + +Decided 2026-11-05 (maintainer, /quest-audit): moq-e2ee, published but +retired in favor of moq-crypto, gets no trusted publisher; +[Remove the moq-e2ee stub](/quest/m1/moq-e2ee-remove.md) takes it out of the +workspace instead. diff --git a/quest/m1/group-drops.md b/quest/m1/group-drops.md index 3ae504de173..17e6c1fa04f 100644 --- a/quest/m1/group-drops.md +++ b/quest/m1/group-drops.md @@ -57,19 +57,24 @@ every run; the 256-stream cell sometimes does. surface needs one; name it in the PR or leave the mirror out. - **Order with the [drop set](/quest/m1/drop-set.md).** The drop set replaces `poll_drop`'s `Delivered` argument and the skipped record, and - edits the lite-07 SUBSCRIBE_DROP wording. Land the wire half whenever it's - ready, but publish the API after the drop set, against its final - disposition record, so the public shape doesn't change twice. + edits the lite-07 SUBSCRIBE_DROP wording. Publish the API against its + final disposition record, so the public shape doesn't change twice. - The drop set owns the per-cursor drop runs and their reasons. This quest reports what a cursor gives up; it doesn't change how a cursor judges a missing group. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ this waits for +[Drop set](/quest/m1/drop-set.md), since both rewrite the lite-07 +SUBSCRIBE_DROP draft wording and the drop signal's `Delivered` argument. + Public API: additive for a separate read; breaking if folded into `recv_group` (its `Result>` return changes for every caller), with MIGRATE notes. `@moq/net` and the bindings mirror it only with a named consumer. Wire: possibly lite-07 (SUBSCRIBE_DROP for a stopped group), decided here. -## Related +## Required - [Drop set](/quest/m1/drop-set.md) - owns the per-cursor drop runs this reports + +## Related - [The receive-windows benchmark](/quest/m1/receive-windows-evicted.md) - its overcommitted cells wait on this (skipped by [moq-dev/moq#7838](https://github.com/moq-dev/moq/pull/7838) until it lands) diff --git a/quest/m1/moq-e2ee-remove.md b/quest/m1/moq-e2ee-remove.md new file mode 100644 index 00000000000..e56d075fdff --- /dev/null +++ b/quest/m1/moq-e2ee-remove.md @@ -0,0 +1,22 @@ +# [XS] Remove the moq-e2ee stub + +## Goal + +`rs/moq-e2ee` leaves the workspace, along with any release or version config +that names it, so release-plz stops tracking a crate whose final release is +out. moq-e2ee 0.0.21, the final no-code release pointing users to moq-crypto, +is on crates.io (published 2026-11-03). + +## Plan + +Decided 2026-11-05 (maintainer, /quest-audit): ✅ retire the stub before +[Rust releases publish through OIDC](/quest/m1/release-rs-oidc.md), so the +crate never needs a trusted publisher. + +- Delete `rs/moq-e2ee` (the workspace's `rs/*` glob picks it up) and its + `Cargo.lock` entry. +- Search release-plz, `version.json`, workflows, and docs for `moq-e2ee` and + drop what names the crate. The `moq-e2ee-*` draft profiles and the + `draft-lcurley-moq-e2ee` drafts are the protocol, not the crate, and stay. + +Public API: none; the crate has no code. Wire: none. diff --git a/quest/m1/push-to-talk/README.md b/quest/m1/push-to-talk/README.md index e92815b1bd2..9af09f4390c 100644 --- a/quest/m1/push-to-talk/README.md +++ b/quest/m1/push-to-talk/README.md @@ -97,10 +97,6 @@ catches this. A complete set of runs finishes this epic. - [Push-to-talk suppresses silence instead of toggling the catalog](/quest/m1/push-to-talk/dtx.md) - replaces hold with DTX - [Native playback fills declared silence with comfort noise](/quest/m1/push-to-talk/native-comfort-noise.md) - `moq play` plays comfort noise over declared silence and counts no underrun, matching the browser -## Closes - -- [#7101](https://github.com/moq-dev/moq/issues/7101) - a disabled audio rendition is deselected, so the start of the next utterance is lost - ## Related - [Container reads drop backfill](/quest/m1/read-backfill.md) - changes how the ordered read treats a group below its cursor, where this head was lost diff --git a/quest/m1/push-to-talk/native-comfort-noise.md b/quest/m1/push-to-talk/native-comfort-noise.md index 31d72a23a36..282d0c880bc 100644 --- a/quest/m1/push-to-talk/native-comfort-noise.md +++ b/quest/m1/push-to-talk/native-comfort-noise.md @@ -30,8 +30,9 @@ browser through `doc/concept/audio-jitter.md` and a corpus case rather than two descriptions. Cover it in `test/audio-quality`'s native rows or `just test push-to-talk` if that can drive `moq play`. -Coordinate with [moq play reaches zero steady-state underruns by -time-stretching](/quest/m1/audio-jitter-target/native-stretch.md), which edits -the same playback ring: whichever lands second rebases onto the other. +Build on [moq play reaches zero steady-state underruns by +time-stretching](/quest/m1/audio-jitter-target/native-stretch.md), whose +stretch in the same playback ring is on `main` since +[moq-dev/moq#7856](https://github.com/moq-dev/moq/pull/7856). Public API: none expected. Wire: none. diff --git a/quest/m1/read-backfill.md b/quest/m1/read-backfill.md index 34489990830..7a090cd1472 100644 --- a/quest/m1/read-backfill.md +++ b/quest/m1/read-backfill.md @@ -43,7 +43,7 @@ delivers a group that arrives below the cursor as a late backfill; Rust - The cursor is range-aware, not just floored: with disjoint ranges it skips straight across an unrequested gap (group 1, then 10 onward) instead of waiting for the latency budget, since no SUBSCRIBE_DROP is owed there. -- Once both land: set the ordered read's floor from those bounds in Rust and +- With both landed: set the ordered read's floor from those bounds in Rust and JS, then make JS discard groups below the cursor. Add a test mirroring Rust's: a reordered group below the floor is never yielded and no extra `Gap` appears, and the out-of-order head case keeps passing. Add a @@ -54,8 +54,13 @@ delivers a group that arrives below the cursor as a late backfill; Rust API instead. Decided 2026-10-27 (maintainer): this waits only on the resolved start in -SUBSCRIBE_OK, now landed, and JS ranges, not the whole -[Subscribe ranges](/quest/m1/subscribe-ranges/README.md) epic. +SUBSCRIBE_OK and JS ranges, not the whole +[Subscribe ranges](/quest/m1/subscribe-ranges/README.md) epic. Both have +landed: the resolved start, and JS ranges in +[moq-dev/moq#7696](https://github.com/moq-dev/moq/pull/7696). A range that a +SUBSCRIBE_UPDATE adds gets its start from SUBSCRIBE_STARTED +([moq-dev/moq#7872](https://github.com/moq-dev/moq/pull/7872)), not +SUBSCRIBE_OK, so carry those starts to the reader too. Public API: no type change; the ordered read changes in Rust and JS (the floor comes from reported bounds, and JS drops backfill). Wire: none. diff --git a/quest/m1/release-rs-oidc.md b/quest/m1/release-rs-oidc.md index 6bd7c82a94a..8992e5456a2 100644 --- a/quest/m1/release-rs-oidc.md +++ b/quest/m1/release-rs-oidc.md @@ -29,4 +29,5 @@ authentication Action is needed. ## Required +- [Remove the moq-e2ee stub](/quest/m1/moq-e2ee-remove.md) - release-plz stops tracking a retired crate that has no trusted publisher - [crates.io trusts the workflow](/quest/m1/crates-trusted-publisher.md) - every published crate has the trusted publisher configured diff --git a/quest/m1/session-policy/README.md b/quest/m1/session-policy/README.md index 62ba3e31c82..3a8b93ac898 100644 --- a/quest/m1/session-policy/README.md +++ b/quest/m1/session-policy/README.md @@ -19,8 +19,10 @@ where moq-webrtc should plug its externally established transport in. The maintainer asked what that means for io_uring and how much of moq-tokio belongs in moq-net, and decided: -- ✅ **Move the policy first**, then give moq-tokio thin handoffs; #7804 waits - on [moq-tokio becomes a thin shell](/quest/m1/session-policy/tokio-handoff.md). +- ✅ **Move the policy first**, then give moq-tokio thin handoffs; the + [WebRTC rename](/quest/m1/webrtc-rename.md) waits on + [moq-tokio becomes a thin shell](/quest/m1/session-policy/tokio-handoff.md) + (#7804 closed unmerged). Not chosen: a moq-tokio handoff now with the move later; moq-webrtc calling moq-net directly with its own policy. - ✅ **Reconnect is in scope**: the reconnect, backoff and GOAWAY candidate diff --git a/quest/m1/session-policy/tokio-handoff.md b/quest/m1/session-policy/tokio-handoff.md index efcdec89f3d..493082e47c8 100644 --- a/quest/m1/session-policy/tokio-handoff.md +++ b/quest/m1/session-policy/tokio-handoff.md @@ -14,9 +14,10 @@ moq-webrtc without reaching into moq-tokio's internals. ## Plan Part of [Session policy lives in moq-net](/quest/m1/session-policy/README.md); -see it for the decisions and research. This is what -[moq-dev/moq#7804](https://github.com/moq-dev/moq/pull/7804) and the -[WebRTC rename](/quest/m1/webrtc-rename.md) wait on: the maintainer decided on +see it for the decisions and research. This is what the +[WebRTC rename](/quest/m1/webrtc-rename.md) waits on +([moq-dev/moq#7804](https://github.com/moq-dev/moq/pull/7804), which first +asked, closed unmerged): the maintainer decided on 2026-11-04 to move the policy first, so the handoff is a few lines over moq-net rather than a copy of the policy. diff --git a/quest/m1/session-policy/uring.md b/quest/m1/session-policy/uring.md index 352223d1e00..2963e8b48cc 100644 --- a/quest/m1/session-policy/uring.md +++ b/quest/m1/session-policy/uring.md @@ -25,7 +25,8 @@ see it for the decisions and research. runs on the worker handle, with admission hopping to the shared runtime through `Lifecycle::shared`, so one `Connection::run` serves every runtime. Use one listen-config mapping at all three sites. -- Do this before the io_uring packaging work publishes the duplicated path. +- Do this before [the io_uring packaging work](/quest/m2/relay-io-uring-package.md) + publishes the duplicated path. - The relay's existing drain, admission and handshake-deadline tests must pass on both runtimes. diff --git a/quest/m1/stream-credit/takeover.md b/quest/m1/stream-credit/takeover.md index df2d6be2e45..73a7014f20b 100644 --- a/quest/m1/stream-credit/takeover.md +++ b/quest/m1/stream-credit/takeover.md @@ -11,12 +11,6 @@ stopped when it is next served, under the duplicate rule of [moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670). moq-transport and older lite versions keep reset only. -## Waiting - -- moq-dev/moq: [moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670) - merges. Resuming a reset group sends a second stream for the same group, - which #7670's hold-the-duplicate rule rewrites. Check that it is merged. - ## Plan Decided 2026-11-05 (maintainer, /quest-plan): split from "A higher-priority group makes room". Takeover first, @@ -30,9 +24,16 @@ Tests: a browser over WebTransport and a Rust relay, more live groups than the cap, the higher-priority group starting without waiting a round trip; a group that lost its stream resumes without loss. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ the wait on +[moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670), Drop set's own +PR, becomes a `Required` link to [Drop set](/quest/m1/drop-set.md), since +resuming a reset group sends a second stream for the same group, which #7670's +hold-the-duplicate rule rewrites. + Public API: none. Wire: lite-07 group stream takeover. ## Required +- [Drop set](/quest/m1/drop-set.md) - its hold-the-duplicate rule governs a resumed group's second stream - [Open streams](/quest/m1/stream-credit/open-streams.md) - which open streams are fully acknowledged - [Reset fallback](/quest/m1/stream-credit/reset-fallback.md) - the fallback a takeover is tried before diff --git a/quest/m1/subscribe-ranges/README.md b/quest/m1/subscribe-ranges/README.md index b287c92ceeb..d2229b41ee0 100644 --- a/quest/m1/subscribe-ranges/README.md +++ b/quest/m1/subscribe-ranges/README.md @@ -36,8 +36,9 @@ relay bounds a sparse FETCH only if the model can request ranges: publisher delivers what it has and fills the rest as upstream answers. - **Model.** `Subscription` gains `ranges` beside its `order`, mirroring the wire; `request_groups` as a separate API was rejected. A publisher's - `track::Requests` receives a `track::Fill` per run of misses (landed), and - `fetch_group` becomes a one-range subscription or is removed. This breaks published moq-net APIs. + `track::Requests` receives a `track::Fill` per run of misses (landed). + Single-group FETCH stays (2026-11-03), so `fetch_group` stays too. This + breaks published moq-net APIs. - **moq-transport.** Some deployments use non-contiguous group numbers, so a relay never probes upstream one group at a time. Upstream, each run of locally missing groups becomes one standalone range FETCH, capped below the @@ -48,9 +49,12 @@ relay bounds a sparse FETCH only if the model can request ranges: (maintainer, 2026-10-28, [moq-dev/moq#7204](https://github.com/moq-dev/moq/pull/7204)), until [hole markers](/quest/m2/ietf-hole-marker.md) let a cache that knows every - group answer a range. A FETCH of the open largest group reads it whole - (maintainer, 2026-10-25): the cache cannot know an open group's real - Largest Object. + group answer a range. A FETCH of the track's newest live group is refused + unless its range ends below that group's live edge + ([moq-dev/moq#7944](https://github.com/moq-dev/moq/pull/7944), + `poll_settle` in `rs/moq-net/src/ietf/publisher.rs`), replacing the + 2026-10-25 rule that it reads the open group whole; an older group still + arriving is waited on until it finishes or its edge passes the range. - **Relative ends** (maintainer, 2026-10-11, superseding the 10-07 `Live` flag and closing #5085). Each range end is `Absolute(group)` or `Relative(n)`, naming the group n before the latest; either end may be diff --git a/quest/m1/subscribe-ranges/js-fills.md b/quest/m1/subscribe-ranges/js-fills.md index 13df15ec38d..130693fe2a4 100644 --- a/quest/m1/subscribe-ranges/js-fills.md +++ b/quest/m1/subscribe-ranges/js-fills.md @@ -67,6 +67,12 @@ half rewrites the same JS fill and miss code as which also redefine the stale-drop judgment it relies on. Not chosen: splitting the `Fill.time` lookup off to start now. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ this also waits for +[Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md), +which moves JS multi-group fills in the same `#runFills` onto the +subscription. + ## Required - [Drop set](/quest/m1/drop-set.md) - redefines the JS stale-drop judgment and fill code this rewrites +- [Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md) - moves JS multi-group fills onto the subscription in the same `#runFills` diff --git a/quest/m1/subscribe-ranges/lite07-fetch.md b/quest/m1/subscribe-ranges/lite07-fetch.md index 75738354eb1..dda0805168b 100644 --- a/quest/m1/subscribe-ranges/lite07-fetch.md +++ b/quest/m1/subscribe-ranges/lite07-fetch.md @@ -50,5 +50,14 @@ on lite-07 (`track.Consumer.fetchGroup` in JS). Subscribe sections. Run `just drafts check`. - Run `just test interop --all`. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ this waits for +[Drop set](/quest/m1/drop-set.md), since both rewrite the JS fill code +(`js/net/src/lite/subscriber.ts` `#runFills`) and the same lite-07 draft +sections. + Public API: none expected. Wire: lite-07 (unpublished) SUBSCRIBE anchors lose their frame. + +## Required + +- [Drop set](/quest/m1/drop-set.md) - rewrites the JS fill code and lite-07 draft sections this changes diff --git a/quest/m1/subscribe-ranges/start-bookkeeping.md b/quest/m1/subscribe-ranges/start-bookkeeping.md index 6d154e6d3d8..65a8275c00e 100644 --- a/quest/m1/subscribe-ranges/start-bookkeeping.md +++ b/quest/m1/subscribe-ranges/start-bookkeeping.md @@ -3,19 +3,13 @@ ## Goal Where a lite subscription starts lives in one place per version: lite -`TrackRun`'s `start`, `first`, `start_frame`, the pre-06 re-pin branch, and +`TrackRun`'s `start` and `first`, the pre-06 re-pin branch, and the per-version start branches collapse into one start state that only translates into SUBSCRIBE_START per version, and on lite-07 the `requested == start` gate is gone, since a fresh START per update makes it unnecessary. What a cursor is owed or was served is out of scope: it stays with [Drop set](/quest/m1/drop-set.md). -## Waiting - -- moq-dev/moq: [moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670) - merges. It rewrites the same lite publisher state (about 1,250 lines of - `lite/publisher.rs`). Check that it is merged into `main`. - ## Plan Decided 2026-11-05 (maintainer, /quest-plan): narrow this quest to the start state and wait for #7670, as the @@ -24,8 +18,13 @@ publisher state, Drop set already promises to delete the served-groups record (`skipped`, `served`, `Delivered`), and [moq-dev/moq#7872](https://github.com/moq-dev/moq/pull/7872)'s SUBSCRIBE_STARTED makes the lite-07 start gate removable. Not chosen: -folding it into Drop set, or doing it now on main. The bullets below -predate the narrowing; the owed-range ones are Drop set's. +folding it into Drop set, or doing it now on main. + +Decided 2026-11-05 (maintainer, /quest-audit): ✅ the wait on +[moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670), Drop set's own +PR, becomes a `Required` link to [Drop set](/quest/m1/drop-set.md), since +#7670 rewrites the same lite publisher state (about 1,250 lines of +`lite/publisher.rs`). Moved out of the [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) @@ -38,21 +37,19 @@ every child. Lite `TrackRun`'s fixes cluster on where a subscription starts and what it is owed or dropped (e713c30991, 36f82ac450, 35fa44f6bf, e1b5d2741f, f235fcfcbd, df0bd5c36f, 342445f251, 06765f4c1a, 4927167904, f52848d634, -0513c07369, 5ad3652871). That state spans about eight fields (`floor`, -`cap`, `start`, `first`, `skipped`, `served`, `start_frame`, `end_frame`), -plus `cursor_floor` and a pre-06 re-pin branch, encoding three wire -generations of "start". - -- On lite-07 every owed range is covered by delivered stream groups or a - DROP, since - [Datagram tracks](/quest/m1/datagram-tracks/README.md) takes datagrams out - of stream tracks (maintainer, 2026-11-01). The subscriber's end is "owed - range covered and no stream active", with no datagram grace. A stream - track's lite-05/06 subscription drops group datagrams, so a group an old - publisher sent only as one is a hole there. Keep `Settle`'s full grace for - lite-05/06 and moq-transport behind one version predicate. +0513c07369, 5ad3652871). That state spans `TrackRun`'s `floor`, `cap`, +`start`, `first`, `skipped`, and `served` (frame bounds moved to `Frames`; +`start_frame` remains only on lite FETCH, `lite/fetch.rs`), plus +`cursor_floor` and the pre-06 re-pin branch in `TrackRun::update`, encoding +three wire generations of "start". + - Lite-07 is unpublished, so sending a fresh START per update can remove the - `requested == start` gate (`lite/subscriber.rs`, about line 4898). + `active.start == active.requested` gate (`lite/subscriber.rs`, + `apply_response`). Public API: none expected. Wire: lite-07 (unpublished) may send a START per update; published versions are unchanged. + +## Required + +- [Drop set](/quest/m1/drop-set.md) - rewrites the same lite publisher state diff --git a/quest/m1/time-addressing/consumers.md b/quest/m1/time-addressing/consumers.md index 50ff812b750..71de05c780e 100644 --- a/quest/m1/time-addressing/consumers.md +++ b/quest/m1/time-addressing/consumers.md @@ -13,9 +13,9 @@ frame's pts. Decided 2026-10-25 (maintainer), from the spike: - GROUP_END replaces hang's empty-frame duration marker - (`rs/moq-mux/src/container/producer.rs:523`), so moq-mux stops writing - empty frames. -- Discontinuity marker groups go away (`producer.rs:650`): a gap is a + (`rs/moq-mux/src/container/producer.rs`, `cut` and `close`), so moq-mux + stops writing empty frames. +- Discontinuity marker groups go away (`producer.rs`, `discontinuity`): a gap is a previous end below the next start, and a missing group is a previous-start link that doesn't match. - Legacy egress synthesizes neither: old players lose end durations and diff --git a/quest/m1/time-addressing/js.md b/quest/m1/time-addressing/js.md index 645cf6f6b14..acc66b04a4e 100644 --- a/quest/m1/time-addressing/js.md +++ b/quest/m1/time-addressing/js.md @@ -17,12 +17,18 @@ so they are carried past 2^53 (decided 2026-11-03, maintainer). The spike found no sparse-ID breakage in direct `@moq/net` sessions over lite-06 and lite-07; its relay fills follow Rust's once JavaScript received -copies fill, which JS ranges ([moq-dev/moq#7696](https://github.com/moq-dev/moq/pull/7696)) -left as a follow-up. Decided 2026-10-27 -(maintainer): this requires JS ranges, so the ranges it rekeys exist first. +copies fill. JS ranges +([moq-dev/moq#7696](https://github.com/moq-dev/moq/pull/7696)), which the +2026-10-27 decision required first, merged. + +Decided 2026-11-05 (maintainer, /quest-audit): ✅ this waits for +[Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md), +which moves JS multi-group fills (`js/net/src/lite/subscriber.ts` +`#runFills`) onto the subscription this rekeys. Public API: breaking, mirroring Rust's. Wire: as the lite-07 quest. ## Required - [Lite-07 by start](/quest/m1/time-addressing/lite07.md) - the wire this speaks +- [Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md) - moves the JS fills this rekeys onto the subscription diff --git a/quest/m1/time-addressing/lite07.md b/quest/m1/time-addressing/lite07.md index f09800e6a4c..2451a045541 100644 --- a/quest/m1/time-addressing/lite07.md +++ b/quest/m1/time-addressing/lite07.md @@ -19,9 +19,10 @@ Decided 2026-10-25 (maintainer), from the spike: arrived, and a reset aborts. A relay closes an expired or partial group instead of resetting it, which changes the draft's reset rule for those groups (around line 760). -- SUBSCRIBE and SUBSCRIBE_UPDATE bounds, SUBSCRIBE_OK and its largest, - SUBSCRIBE_END, and SUBSCRIBE_DROP address by start. Datagrams keep their own sequence (maintainer, 2026-11-01). Drops name - time spans with no group to deliver, not sequence ranges. `Relative(n)` +- SUBSCRIBE and SUBSCRIBE_UPDATE bounds, SUBSCRIBE_OK's largest and its Range + Starts, SUBSCRIBE_STARTED, SUBSCRIBE_FINISH, and SUBSCRIBE_DROP address by + start. Datagrams keep their own sequence (maintainer, 2026-11-01). Drops + name time spans with no group to deliver, not sequence ranges. `Relative(n)` stays a group count. - Positions stay (start, frame index), preserving transport frame offsets. - SUBSCRIBE_UPDATE's `Wanted Group` (a sequence plus one) and SUBSCRIBE_OK's @@ -47,10 +48,16 @@ Update `drafts/draft-lcurley-moq-lite.md` (fields, the group-end rules, and the lite-07 changelog) and `doc/concept/moq-lite.md`, and run `just drafts check` and `just test interop --all`. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ this waits for +[Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md), +which rewrites the same lite-07 draft sections (`Range`, Positions, +SUBSCRIBE anchors). + Public API: none beyond [the model](/quest/m1/time-addressing/model.md). Wire: lite-07-wip GROUP, GROUP_END, SUBSCRIBE, SUBSCRIBE_UPDATE, -SUBSCRIBE_OK, SUBSCRIBE_END, and SUBSCRIBE_DROP change. +SUBSCRIBE_OK, SUBSCRIBE_STARTED, SUBSCRIBE_FINISH, and SUBSCRIBE_DROP change. ## Required - [Rust groups by start](/quest/m1/time-addressing/model.md) - the model this wire carries +- [Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md) - rewrites the same lite-07 draft sections first diff --git a/quest/m1/time-addressing/model.md b/quest/m1/time-addressing/model.md index 0987f1e420c..8db9afdfccc 100644 --- a/quest/m1/time-addressing/model.md +++ b/quest/m1/time-addressing/model.md @@ -54,7 +54,8 @@ a producer would need per-track memory of its last number. - **What it waits on** (decided 2026-10-27, maintainer; Fetch as a range finished in [moq-dev/moq#7625](https://github.com/moq-dev/moq/pull/7625)): only the subscribe-ranges children that put sequence ranges into the model and the - wire, Lite-07 ranges ([moq-dev/moq#7872](https://github.com/moq-dev/moq/pull/7872)) and + wire, Lite-07 ranges ([moq-dev/moq#7872](https://github.com/moq-dev/moq/pull/7872), + merged 2026-11-05) and [Delete the old start bookkeeping](/quest/m1/subscribe-ranges/start-bookkeeping.md), not the whole epic. [Drop set](/quest/m1/drop-set.md) lands first too: its runs keyed by group sequence convert mechanically to starts. diff --git a/quest/m1/unbounded-groups/README.md b/quest/m1/unbounded-groups/README.md index f8bef59a954..20cc1c0d66f 100644 --- a/quest/m1/unbounded-groups/README.md +++ b/quest/m1/unbounded-groups/README.md @@ -2,18 +2,19 @@ ## Goal -Groups and frames have no fixed size cap. `MAX_GROUP_FRAMES` (8192) goes -away, and `MAX_CACHE_BYTES` (32 MB) stops capping groups and frames and -instead bounds how much of a group's live tail is held. A group sheds whole -frames from its front once its tail passes 32 MB, or sooner when the shared -cache pool is over budget, so one long group never grows without bound even -on a relay with no cache capacity set. A reader or FETCH that reaches a shed -front is served by a flight, a separate paced copy filled from upstream or -the publisher's own refill handler; failing that, it asks for a new group -(refresh), and otherwise it gets `Evicted`. Readers never fail just because a group got big. The motivating -workloads are long-lived single groups (data/log tracks, audio, window -timelines), video with very long GOPs, and file transfers where a frame is a -whole file. +Groups and frames have no fixed size cap. `MAX_GROUP_FRAMES` is already gone +([moq-dev/moq#6993](https://github.com/moq-dev/moq/pull/6993)), and +`MAX_CACHE_BYTES` (32 MB) stops capping groups and frames and instead bounds +how much of a group's live tail is held. A group sheds whole frames from its +front once its tail passes 32 MB, or sooner when the shared cache pool is over +budget, so one long group never grows without bound even on a relay with no +cache capacity set. A reader or FETCH that reaches a shed front is served by a +flight, a separate paced copy filled from upstream or the publisher's own +refill handler; failing that, it asks for a new group (refresh), and otherwise +it gets `Evicted`. Readers never fail just because a group got big. The +motivating workloads are long-lived single groups (data/log tracks, audio, +window timelines), video with very long GOPs, and file transfers where a frame +is a whole file. The hot write and read path for ordinary groups does not regress. @@ -164,15 +165,16 @@ A flight's fill is the `track::Requests` fill (`track::Fill`). A handler serves group producer bounded to that range, the same API as a live write, so an origin can regenerate data from disk or an archive. -This epic owns the end-to-end test: a relay chain carries one live group well -past the old caps. A late joiner gets its head through a flight and hands -over to the live copy, and a live reader keeps the tail, over lite, with -memory held near 32 MB per copy; over moq-transport, the live group's replay -is refused and a finished group's replays -([moq-dev/moq#7944](https://github.com/moq-dev/moq/pull/7944)). It also carries a long -compressed group through a small cache pool with a plain reader on a legacy -wire, which [moq-dev/moq#6993](https://github.com/moq-dev/moq/pull/6993) -covered only at the model layer (maintainer, 2026-10-30). +Most of the end-to-end test landed in +[moq-dev/moq#7944](https://github.com/moq-dev/moq/pull/7944) +(`rs/moq-net/tests/integration/flights.rs`): a relay chain carries one live +group past its 32 MiB tail, a late joiner replays it through a flight and +hands over to the live copy over lite, and over moq-transport the live +group's replay is refused and a finished group's replays. This epic still +owns the rest: a long compressed group through a small cache pool with a +plain reader on a legacy wire, which +[moq-dev/moq#6993](https://github.com/moq-dev/moq/pull/6993) covered only at +the model layer (maintainer, 2026-10-30). ## Required diff --git a/quest/m1/unbounded-groups/byte-holes.md b/quest/m1/unbounded-groups/byte-holes.md index 9a1c2e888e2..a428aaff5ba 100644 --- a/quest/m1/unbounded-groups/byte-holes.md +++ b/quest/m1/unbounded-groups/byte-holes.md @@ -20,6 +20,14 @@ and lite-07 peers start flights only at frame boundaries, like older lite versions. Decided 2026-10-28 (maintainer): shed frames are served again only by flights, so this waits on Flights and stays in m1. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ the byte offset rides +FETCH's frame start plus the group header, not a SUBSCRIBE range end. +SUBSCRIBE ranges are whole groups since 2026-11-03 +([Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md), +[moq-dev/moq#7675](https://github.com/moq-dev/moq/pull/7675)), and flights +ride lite FETCH since [moq-dev/moq#7944](https://github.com/moq-dev/moq/pull/7944). +This waits for that quest. + - Segments are `frame::SEGMENT` (1 MiB) long, so segment `i` always holds bytes from `i * SEGMENT`, and a completed chain is `frame::Payload::Chain`. Only a frame past one segment written in pieces chains. One written whole @@ -28,8 +36,8 @@ by flights, so this waits on Flights and stays in m1. segment slices, whose memory frees only once every slice drops, or copied into segments. -- `Position` gains a byte offset within the frame. A lite range end can - carry it, and so can a group stream header, beside `frame_start`. A +- `Position` gains a byte offset within the frame. A lite FETCH carries it + beside its `frame_start`, and so does a group stream header. A stream that starts mid-frame still states the frame's full size. Older lite versions and moq-transport start flights only at frame or object boundaries. A reader inside a shed object refreshes or is `Evicted` there. @@ -58,4 +66,9 @@ by flights, so this waits on Flights and stays in m1. Public API: `Position` gains a byte field, frames gain a chunked read, and `MAX_CACHE_BYTES` stops capping a frame. -Wire: a byte offset on the current lite wip's range ends and group header. +Wire: a byte offset on the current lite wip's FETCH frame start and group +header. + +## Required + +- [Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md) - SUBSCRIBE ranges become whole groups, so the offset goes on FETCH diff --git a/quest/m1/unbounded-groups/js-byte-holes.md b/quest/m1/unbounded-groups/js-byte-holes.md index a51cbaca1d4..3c7742d899f 100644 --- a/quest/m1/unbounded-groups/js-byte-holes.md +++ b/quest/m1/unbounded-groups/js-byte-holes.md @@ -2,9 +2,9 @@ ## Goal -`@moq/net` speaks the lite wip byte offset on range ends and group headers -as Rust does, so a JS reader cut off inside a large frame continues it from -the byte it reached instead of failing. +`@moq/net` speaks the lite wip byte offset on FETCH's frame start and group +headers as Rust does, so a JS reader cut off inside a large frame continues it +from the byte it reached instead of failing. ## Plan @@ -20,8 +20,8 @@ has `Group.Producer.createFrame` and `Group.Consumer.nextFrame` with 32 MiB tail, and streams payloads past one segment on lite and moq-transport. What is left here is the wire: -- Mirror the byte offset on the same lite wip version as Rust, on range - ends and the group stream header, and refill a hole inside a frame the way +- Mirror the byte offset on the same lite wip version as Rust, on FETCH's + frame start and the group stream header, and refill a hole inside a frame the way Rust does. - A consumer that took a frame to stream and loses its copy partway through fails today, since resuming at the next frame would drop the rest @@ -34,9 +34,18 @@ moq-transport. What is left here is the wire: - If [JS-only @moq/net from Rust](/quest/m2/rs2ts-js.md) is adopted first, this shrinks to exposing its byte-offset recovery. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ the byte offset rides +FETCH's frame start plus the group header, not a SUBSCRIBE range end. +SUBSCRIBE ranges are whole groups since 2026-11-03 +([Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md), +[moq-dev/moq#7675](https://github.com/moq-dev/moq/pull/7675)), and flights +ride lite FETCH since [moq-dev/moq#7944](https://github.com/moq-dev/moq/pull/7944). +This waits for that quest. + Public API: none beyond the recovery. Wire: the lite wip byte offset, as Byte holes defines it. ## Required - [Byte holes](/quest/m1/unbounded-groups/byte-holes.md) - the Rust contract and the lite wire this mirrors +- [Lite-07 FETCH is single-group only](/quest/m1/subscribe-ranges/lite07-fetch.md) - SUBSCRIBE ranges become whole groups, so the offset goes on FETCH diff --git a/quest/m1/webrtc-rename.md b/quest/m1/webrtc-rename.md index 88adb4b524f..a129f356c80 100644 --- a/quest/m1/webrtc-rename.md +++ b/quest/m1/webrtc-rename.md @@ -24,4 +24,4 @@ Public API: breaking (crate rename; `moq_tokio::webrtc` moves). Wire: none. ## Related -- [moq-rtc REMB and TIAS](/rs/moq-rtc/src/server/whip.rs) - #7373 adds the capped answer in moq-rtc; carry it through the move +- [moq-rtc REMB and TIAS](/rs/moq-rtc/src/server/whip.rs) - #7373 added the capped answer in moq-rtc; carry it through the move diff --git a/quest/m2/README.md b/quest/m2/README.md index 84e83de8cb9..cb067930bf9 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -35,6 +35,8 @@ lite-07; bitrate enforcement is not part of this release. - [JS announced coalescing](/quest/m2/js-announced-coalesce.md) - `@moq/net`'s `Announced` keeps one pending event per path, like Rust - [An audio track's final flush joins its open group](/quest/m2/audio-flush-group.md) - a zero-`delay.max` subscriber gets the tail, not `Old` - [Release execution](/quest/m2/release/README.md) - publication, installed-artifact proof, cleanup, and downstream adoption after m1 +- [Release pull requests read the R2 Rust cache](/quest/m2/mbx-r2-release-cache.md) - a release PR's `Check the cache` step reports effective read-only once the cut brings the cache to `release` +- [Binary release publishers run on their tag](/quest/m2/release-tag-publishers.md) - brew, Go and Swift releases stop running through `workflow_run` on main, once the cut brings the workflows to `release` - [One policy for oversized container metadata](/quest/m2/import-metadata-policy.md) - fMP4 and MKV refuse or stream huge metadata by one documented rule - [Wire fuzz coverage](/quest/m2/wire-fuzz-coverage.md) - the cmsg walks in moq-sock and moq-uring have invariant fuzz targets, and the unsafe peer input reaches runs under Miri - [VA-API renderer tests](/quest/m2/vaapi-render-tests.md) - the VA-API renderer, decode, and transcode tests run in `just rs gpu` on AMD and Intel and fail instead of skipping, and hosted CI reports them ignored @@ -45,7 +47,7 @@ lite-07; bitrate enforcement is not part of this release. - [moq-auth drops the unused peer grant API](/quest/m2/auth-drop-peer-grant.md) - P2P trusts its peers, so `PeerGrant` and its `KeySet` methods go - [rust2's exporter is ready for moq](/quest/m2/rust2-exporter.md) - waiting on moq-dev/rust2's exporter to generate every language moq ships - [Switch to rust2's exporter](/quest/m2/ffi-exporter.md) - moq's bindings come from rust2-ffi, moq-ffi shrinks to its remainder, and moq's UniFFI generator code is deleted -- [Generated C bindings](/quest/m2/c/README.md) - C generated from moq-ffi ships as `moq-c` 0.8.0 and replaces the hand-written crate +- [Generated C bindings](/quest/m2/c/README.md) - C generated from moq-ffi ships as `moq-c` at a later cut's shared minor and replaces the hand-written crate - [A C origin can discover eagerly, like a relay](/quest/m2/c-origin-relay.md) - the C API puts an origin in relay mode, so forwarding a client session's routes needs no local announce watcher - [A runtime-free QUIC driver](/quest/m2/quic-sansio-driver.md) - a caller's own loop moves UDP datagrams and polls moq sessions over moq-quic, for rust2's bindings - [Benchmark sources](/quest/m2/bench-sources.md) - every measuring nightly benchmark feeds the regression table, and none is a smoke run diff --git a/quest/m2/c/README.md b/quest/m2/c/README.md index 2979fde4076..963e4372658 100644 --- a/quest/m2/c/README.md +++ b/quest/m2/c/README.md @@ -32,7 +32,9 @@ Decided earlier, still standing: scalars are `{has_value, value}`, each async function has its own callback typedef, and unnamed variant fields are `v1`, as in C++. - The generated package takes over the `moq-c` name and `moq::c` target at - 0.8.0, a minor bump over the hand-written 0.7.x. + the shared minor of the cut that ships it, after the hand-written crate's + 0.22 (CONTRIBUTING.md's [Versions](/CONTRIBUTING.md#versions), + [moq-dev/moq#7610](https://github.com/moq-dev/moq/pull/7610)). - Docs change inline: the consumer quest rewrites `doc/lib/c`, and its Impact bullet carries the move for the package's `MIGRATE.md`. diff --git a/quest/m2/c/consumers.md b/quest/m2/c/consumers.md index 781c3f25577..2ade0c5d38b 100644 --- a/quest/m2/c/consumers.md +++ b/quest/m2/c/consumers.md @@ -22,7 +22,7 @@ the smoke client (`test/smoke/clients/c`), which Waits for the cut and the generator switch (found when first started, 2026-10-28; decided 2026-10-31). Until the cut, [moq-c parity](/quest/m1/c/README.md) ships the -hand-written 0.7 and proves it with this interop client and the current +hand-written crate at 0.22 and proves it with this interop client and the current `doc/lib/c`, and `doc/` describes only what ships, so either half landing first drops the shipping crate's proof and documents an unpublished API. The switch re-cases every generated C type (`moq_session` becomes `MoqSession`), so a port @@ -39,5 +39,5 @@ so it can move only once the generated archive publishes, after this quest; ## Required -- [Breaking release cut](/quest/m2/release/cut.md) - the hand-written 0.7 ships with this client and these docs as its proof +- [Breaking release cut](/quest/m2/release/cut.md) - the hand-written crate ships at 0.22 with this client and these docs as its proof - [Switch to rust2's exporter](/quest/m2/ffi-exporter.md) - the generated C type names settle before consumers are written against them diff --git a/quest/m2/mbx-r2-release-cache.md b/quest/m2/mbx-r2-release-cache.md new file mode 100644 index 00000000000..557988a0185 --- /dev/null +++ b/quest/m2/mbx-r2-release-cache.md @@ -0,0 +1,27 @@ +# [XS] Release pull requests read the R2 Rust cache + +## Goal + +A release pull request's `Check the cache` step reports `effective +read-only`, and the PR that closes this records it. Condition: `release` +carries the platform Rust cache, which its `platform.yml` still lacks on +2026-11-05; check with +`git show origin/release:.github/workflows/platform.yml | grep rust-cache`. + +## Plan + +Decided 2026-11-05 (maintainer, /quest-audit): ✅ split from +[Verify the R2 Rust cache](/quest/m0/ci/mbx-r2-verify.md) and moved to m2 +behind [the cut](/quest/m2/release/cut.md), which brings `main`'s platform +Rust cache to `release` when it merges `main` into it. Not chosen: moving +the whole R2 verification quest; merging `main` into `release` now, which +reverses the 2026-11-04 decision. + +Once the cut lands, inspect the first release pull request's `Check the +cache` step. + +Public API: none. Wire: none. + +## Required + +- [Cut and publish the prepared breaking release](/quest/m2/release/cut.md) - brings the platform Rust cache to `release` diff --git a/quest/m2/relay-io-uring-package.md b/quest/m2/relay-io-uring-package.md index 7fe15fa06c0..533e4520ee8 100644 --- a/quest/m2/relay-io-uring-package.md +++ b/quest/m2/relay-io-uring-package.md @@ -38,8 +38,13 @@ ships, not the default. (`listen.lb_id` QUIC-LB server ids). That refusal is a recorded exception to parity, not a prerequisite, until a consumer asks. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ this waits for +[the io_uring relay path using moq-net's policy](/quest/m1/session-policy/uring.md), +so packaging never publishes the hand-copied lifecycle path. + Public API: none. Wire: none. ## Required +- [The io_uring relay path uses moq-net's policy](/quest/m1/session-policy/uring.md) - the ring serves through the shared accept policy before it ships - [One port on the io_uring workers](/quest/m2/uring-demux.md) - a one-port config is served on the ring too diff --git a/quest/m0/ci/release-tag-publishers.md b/quest/m2/release-tag-publishers.md similarity index 54% rename from quest/m0/ci/release-tag-publishers.md rename to quest/m2/release-tag-publishers.md index 625626776b3..db56ae8a3f1 100644 --- a/quest/m0/ci/release-tag-publishers.md +++ b/quest/m2/release-tag-publishers.md @@ -12,6 +12,15 @@ Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-c the `bot` Environment today, which admits `main`; moving them needs `bot` to admit the binary release tags, a maintainer action to list in the PR. +Decided 2026-11-05 (maintainer, /quest-audit): ✅ moved from m0 to m2 behind +[the cut](/quest/m2/release/cut.md), since tags run `release`'s copies of the +workflows and `release` gets `main`'s only when the cut merges it. Not +chosen: moving all four release-gated m0 CI quests, including +[Drop main from the publish Environment](/quest/m0/ci/publish-release-only.md), +which backports its own change instead; merging `main` into `release` now, +which reverses the 2026-11-04 decision. + ## Required +- [Cut and publish the prepared breaking release](/quest/m2/release/cut.md) - brings `main`'s workflows to `release`, where tags run them - [Release credentials off main](/quest/m0/ci/publish-release-only.md) - the same move for the `publish` jobs lands first From d26bbbf46efb7f6db1154faa14c5abf5cbb0a56b Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 5 Nov 2026 13:19:14 -0800 Subject: [PATCH 2/5] quest: unblock m0 and m1 (2026-11-05) Co-Authored-By: Claude Opus 5.5 --- quest/m0/ci/README.md | 1 + quest/m0/ci/cachix-retire.md | 42 +++++++++++++++++++ quest/m1/README.md | 2 - .../m1/audio-jitter-target/native-stretch.md | 42 +++++-------------- quest/m1/bench-publish.md | 4 +- quest/m1/moq-e2ee-remove.md | 2 +- quest/m2/README.md | 2 + quest/{m1 => m2}/crates-trusted-publisher.md | 16 ++++++- quest/{m1 => m2}/release-rs-oidc.md | 7 +++- 9 files changed, 79 insertions(+), 39 deletions(-) create mode 100644 quest/m0/ci/cachix-retire.md rename quest/{m1 => m2}/crates-trusted-publisher.md (77%) rename quest/{m1 => m2}/release-rs-oidc.md (86%) diff --git a/quest/m0/ci/README.md b/quest/m0/ci/README.md index fc184c48f49..d29366a02fb 100644 --- a/quest/m0/ci/README.md +++ b/quest/m0/ci/README.md @@ -180,6 +180,7 @@ The historical samples locate candidates; they are not controlled benchmarks. - [Verify the Nix cache](/quest/m0/ci/nix-cache-verify.md) - confirm releases use `nix.moq.dev`, check its bucket sizes, and retire Cachix - [Record hosted cargo-hakari evidence](/quest/m0/ci/hakari.md) - compare scheduled macOS and Windows cache hits and estimated compiler work saved before and after the workspace-hack - [Drop main from the publish Environment](/quest/m0/ci/publish-release-only.md) - the maintainer narrows `publish` to `release` and release tags once no job naming it runs as `main` +- [Release tags push to nix.moq.dev, and Cachix is retired](/quest/m0/ci/cachix-retire.md) - backport `release-nix.yml` to `release`, drop `cachix.yml`, then delete the Cachix token and cache after a tag proves nix.moq.dev - [Measure the Linux cache effect of native media exclusions](/quest/m0/ci/hakari-followups.md) - scheduled Linux jobs measure cache reuse after unrelated tests stop compiling PipeWire and libclang - [A release merge opens no stale release PR](/quest/m0/ci/release-pr-after-release.md) - `just rs release` publishes before it proposes, so a merged release isn't re-proposed - [Build two queue entries at once if it helps](/quest/m0/ci/queue-concurrency.md) - a measured trial of `maximumEntriesToBuild: 2` against the serial lane's burst latency diff --git a/quest/m0/ci/cachix-retire.md b/quest/m0/ci/cachix-retire.md new file mode 100644 index 00000000000..b5896b957ed --- /dev/null +++ b/quest/m0/ci/cachix-retire.md @@ -0,0 +1,42 @@ +# [S] Release tags push to nix.moq.dev, and Cachix is retired + +## Goal + +Tags cut from `release` push their Nix packages to nix.moq.dev through +`release-nix.yml`, `release` no longer runs `cachix.yml`, and once a release +tag's uploads and a clean-machine `nix run` substitution are proven, the +`CACHIX_AUTH_TOKEN` repository secret and the `kixelated` Cachix cache are +deleted. + +## Plan + +Decided 2026-11-05 (maintainer, /quest-unblock): ✅ backport now and retire +Cachix after the next patch cut on `release`, rather than waiting for the m2 +cut to merge `main` into `release`. Not chosen: retiring it at the m2 cut with +`CACHIX_AUTH_TOKEN` copied into `publish` meanwhile; retiring it at the m2 cut +with the token left at repository scope. This pulls the Cachix part out of +the release Nix cache quest that +[moq-dev/moq#7662](https://github.com/moq-dev/moq/pull/7662) adds in m2, which keeps +only what needs the cut. + +Today `release`'s `cachix.yml` pushes `moq-relay-v*`, `moq-cli-v*`, +`moq-boy-v*`, `libmoq-v*` and `moq-gst-v*` tag builds to Cachix. Its job names +`publish`, which does not hold `CACHIX_AUTH_TOKEN`, so it reads the repository +copy. That copy is what blocks step 3 of +[Keep pull-request CI read-only](/quest/m0/ci/read-only-secrets.md); retiring +Cachix removes it instead of moving it. + +- Backport `main`'s `release-nix.yml` to `release` and delete `cachix.yml` + there, in one PR against `release` that the maintainer merges (agents never + merge into `release`). Match `release`'s own tag patterns (it still cuts + `libmoq-v*`, where `main` cuts `moq-c-v*`) and the flake attributes + `release` builds; the `cache-write` Environment must admit those tags. +- Prove it on the first tag after the backport: Release Nix uploads succeed + on all three platforms, and a clean machine substitutes the tagged package + from nix.moq.dev. +- Then delete `CACHIX_AUTH_TOKEN` and the `kixelated` cache (a Cachix login, + so `Maintainer:`), and drop Cachix from docs that still name it. + +## Related + +- [Publish off main](/quest/m0/ci/publish-release-only.md) - the other workflow backport to `release` decided in the 2026-11-05 audit diff --git a/quest/m1/README.md b/quest/m1/README.md index 764cb21631f..21b2143d288 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -174,8 +174,6 @@ quests that require them. - [TS fidelity and recovery](/quest/m1/ts-reliability/README.md) - both modes have explicit profiles, automated validation, loss tests, and a dedicated guide - [WebGPU on Safari](/quest/m1/webgpu-safari.md) - the WebGPU renderer is verified on Safari 26 for macOS and iOS - [Remove the moq-e2ee stub](/quest/m1/moq-e2ee-remove.md) - `rs/moq-e2ee` leaves the workspace and release config now that its final release points to moq-crypto -- [crates.io trusts the workflow](/quest/m1/crates-trusted-publisher.md) - maintainer action: every published crate gets a trusted publisher for `release-rs.yml` -- [Rust releases publish through OIDC](/quest/m1/release-rs-oidc.md) - release-plz publishes with trusted publishing and `CARGO_REGISTRY_TOKEN` is revoked - [Main is no slower than release](/quest/m1/release-perf/README.md) - every benchmark where main is slower than release is fixed or accepted with a reason, checked by a final paired run before the cut - [Calibrate the paired nightly benchmarks](/quest/m1/bench-ci.md) - A/A and deliberately slowed Nightly runs set the paired comparison's threshold, so its regression alerts can be trusted - [moq-json's table/deltas bench measures the same work every iteration](/quest/m1/bench-json-deltas.md) - the `table/deltas/1%` cases stop flipping between snapshot and delta timings, so their trend history is usable diff --git a/quest/m1/audio-jitter-target/native-stretch.md b/quest/m1/audio-jitter-target/native-stretch.md index fc024d27efa..69461a8e24b 100644 --- a/quest/m1/audio-jitter-target/native-stretch.md +++ b/quest/m1/audio-jitter-target/native-stretch.md @@ -88,39 +88,19 @@ nightlies on `main` read 160 to 280 ms. So the ceiling stays as it is, as `test/audio-quality/budgets.json`'s note budgets startup holds as measured, until the seven-nightly calibration below. +Listened 2026-11-05 (maintainer, /quest-unblock): the stretch is inaudible +in all four runs on `kixtop` at `main` `7e621623a8`, two minutes each of +`say` speech from `LICENSE-APACHE` over Opus 128 kb/s, the relay at +`test/audio-quality/relay.toml`, and the shaper's `bursty` profile, seed 7. +The player's metrics confirm the stretch was active: media per render second +was 1.0020 (fast, direct) and 1.0018 (fast, shaped) against a 1.002 +publisher, and 0.9981 and 0.9979 against 0.998; the shaped runs raised the +target delay from 120 to 260 ms. Each direct run stalled once at startup, +none in steady state. This settles the perceptual check; the calibration and +bench waits below remain. + ## Waiting -- Maintainer: listen for the stretch on `kixtop` and record whether it is - audible. Recommend this check before claiming the perceptual goal; - automated amplitude tests cannot decide it. - Run it in `~/work/moq` on `kixtop`, with its speakers or headphones as - the default output, on `main`, where - [moq-dev/moq#7856](https://github.com/moq-dev/moq/pull/7856) landed. The - source is - macOS's `say` voice reading `LICENSE-APACHE`, about ten minutes of - continuous speech, so nothing is downloaded (an archive's speech file - returned 403): - - ```bash - nix develop - mkdir -p .tmp/listen && say -v Samantha -o .tmp/listen/speech.aiff -f LICENSE-APACHE - # Terminal 1: the relay, and a shaper in front of it replaying the audio-quality `bursty` path. - cargo run -p moq-relay -- test/audio-quality/relay.toml & - cargo run -p moq-shaper -- --listen 127.0.0.1:4500 --target 127.0.0.1:4443 --seed 7 --profile bursty - # Terminal 2: publish 2 ms/s fast (accelerate); rerun with -readrate 0.998 for 2 ms/s slow (preemptive expand). - ffmpeg -hide_banner -v error -readrate 1.002 -stream_loop -1 -i .tmp/listen/speech.aiff \ - -ac 2 -c:a libopus -b:a 128k -f mp4 -movflags cmaf+separate_moof+delay_moov+skip_trailer -frag_duration 1000 - | - cargo run -p moq-cli --features play -- --connect http://127.0.0.1:4443 --broadcast speech.hang import fmp4 - # Terminal 3: two minutes direct (drift alone), then two through the shaper (the measured expansions). - cargo run -p moq-cli --features play -- --connect http://127.0.0.1:4443 --broadcast speech.hang \ - play --video off --metrics .tmp/listen/drift.ndjson - cargo run -p moq-cli --features play -- --connect https://127.0.0.1:4500 \ - --connect-tls-fingerprint "$(curl -s http://127.0.0.1:4443/certificate.sha256)" \ - --broadcast speech.hang play --video off --metrics .tmp/listen/bursty.ndjson - ``` - - Record, for each of the four runs (fast/slow × direct/shaped), whether the - stretching is audible, and attach the `.ndjson` files. - moq-dev/moq: collect seven scheduled native nightly rows for this implementation, then apply the existing calibration rule. Keep the current provisional budgets until those artifacts exist. diff --git a/quest/m1/bench-publish.md b/quest/m1/bench-publish.md index 97026b1709d..8bd6259e384 100644 --- a/quest/m1/bench-publish.md +++ b/quest/m1/bench-publish.md @@ -50,9 +50,9 @@ crate, like CONTRIBUTING's bench-only backport. Otherwise skip it, say so in the PR, and moq-bench publishes at the cut. The first publish goes out by token, so add moq-bench to the -[crates.io trusted publisher](/quest/m1/crates-trusted-publisher.md) +[crates.io trusted publisher](/quest/m2/crates-trusted-publisher.md) `Waiting` list (done in this planning PR). ## Related -- [crates.io trusts the workflow](/quest/m1/crates-trusted-publisher.md) - moq-bench needs a trusted publisher after its first publish +- [crates.io trusts the workflow](/quest/m2/crates-trusted-publisher.md) - moq-bench needs a trusted publisher after its first publish diff --git a/quest/m1/moq-e2ee-remove.md b/quest/m1/moq-e2ee-remove.md index e56d075fdff..8e2aa3fd0bd 100644 --- a/quest/m1/moq-e2ee-remove.md +++ b/quest/m1/moq-e2ee-remove.md @@ -10,7 +10,7 @@ is on crates.io (published 2026-11-03). ## Plan Decided 2026-11-05 (maintainer, /quest-audit): ✅ retire the stub before -[Rust releases publish through OIDC](/quest/m1/release-rs-oidc.md), so the +[Rust releases publish through OIDC](/quest/m2/release-rs-oidc.md), so the crate never needs a trusted publisher. - Delete `rs/moq-e2ee` (the workspace's `rs/*` glob picks it up) and its diff --git a/quest/m2/README.md b/quest/m2/README.md index ee09744ac93..06261af46a3 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -37,6 +37,8 @@ lite-07; bitrate enforcement is not part of this release. - [Release execution](/quest/m2/release/README.md) - publication, installed-artifact proof, cleanup, and downstream adoption after m1 - [Release pull requests read the R2 Rust cache](/quest/m2/mbx-r2-release-cache.md) - a release PR's `Check the cache` step reports effective read-only once the cut brings the cache to `release` - [Binary release publishers run on their tag](/quest/m2/release-tag-publishers.md) - brew, Go and Swift releases stop running through `workflow_run` on main, once the cut brings the workflows to `release` +- [crates.io trusts the workflow](/quest/m2/crates-trusted-publisher.md) - maintainer action: the crates the cut first-publishes by token get a trusted publisher for `release-rs.yml` +- [Rust releases publish through OIDC](/quest/m2/release-rs-oidc.md) - release-plz publishes with trusted publishing and `CARGO_REGISTRY_TOKEN` is revoked - [One policy for oversized container metadata](/quest/m2/import-metadata-policy.md) - fMP4 and MKV refuse or stream huge metadata by one documented rule - [Wire fuzz coverage](/quest/m2/wire-fuzz-coverage.md) - the cmsg walks in moq-sock and moq-uring have invariant fuzz targets, and the unsafe peer input reaches runs under Miri - [VA-API renderer tests](/quest/m2/vaapi-render-tests.md) - the VA-API renderer, decode, and transcode tests run in `just rs gpu` on AMD and Intel and fail instead of skipping, and hosted CI reports them ignored diff --git a/quest/m1/crates-trusted-publisher.md b/quest/m2/crates-trusted-publisher.md similarity index 77% rename from quest/m1/crates-trusted-publisher.md rename to quest/m2/crates-trusted-publisher.md index 7c5828c6168..23d1e883246 100644 --- a/quest/m1/crates-trusted-publisher.md +++ b/quest/m2/crates-trusted-publisher.md @@ -4,12 +4,12 @@ Every crate that `release-rs.yml` publishes has a crates.io trusted publisher for `moq-dev/moq`, workflow `release-rs.yml`, and environment `publish`, so -[Rust releases publish through OIDC](/quest/m1/release-rs-oidc.md) can start. +[Rust releases publish through OIDC](/quest/m2/release-rs-oidc.md) can start. Delete this quest once every crate has one. ## Waiting -- Maintainer: after the next `main` to `release` cut publishes kio-macros, moq-c, +- Maintainer: after [the cut](/quest/m2/release/cut.md) publishes kio-macros, moq-c, moq-congestion, moq-crypto, moq-ice, moq-quic, and moq-rtsp by token (and moq-bench, whenever [its first publish](/quest/m1/bench-publish.md) lands), add their trusted publishers the same way. Settings pages need a crates.io @@ -17,6 +17,14 @@ Delete this quest once every crate has one. ## Plan +Decided 2026-11-05 (maintainer left the choice to the agent, /quest-unblock): +✅ move this quest and [Rust releases publish through OIDC](/quest/m2/release-rs-oidc.md) +to m2 behind [the cut](/quest/m2/release/cut.md). The seven crates the cut +first-publishes by token cannot get a trusted publisher before it, and the cut +runs after m1, so neither quest could finish inside m1. Not chosen: keeping +both in m1 and treating the cut as part of finishing m1. + + Moved from m2 to m1 on 2026-10-29 (maintainer): after [moq-dev/moq#7166](https://github.com/moq-dev/moq/pull/7166) moved publish secrets into the `publish` Environment, `CARGO_REGISTRY_TOKEN` is the @@ -48,3 +56,7 @@ Decided 2026-11-05 (maintainer, /quest-audit): moq-e2ee, published but retired in favor of moq-crypto, gets no trusted publisher; [Remove the moq-e2ee stub](/quest/m1/moq-e2ee-remove.md) takes it out of the workspace instead. + +## Required + +- [Cut the release](/quest/m2/release/cut.md) - the cut first-publishes the seven crates by token diff --git a/quest/m1/release-rs-oidc.md b/quest/m2/release-rs-oidc.md similarity index 86% rename from quest/m1/release-rs-oidc.md rename to quest/m2/release-rs-oidc.md index 8992e5456a2..ac0b7ec9551 100644 --- a/quest/m1/release-rs-oidc.md +++ b/quest/m2/release-rs-oidc.md @@ -8,6 +8,11 @@ secret is removed and revoked. ## Plan +Moved to m2 on 2026-11-05 (/quest-unblock), with +[crates.io trusts the workflow](/quest/m2/crates-trusted-publisher.md), which +waits on the cut's first publishes. + + Moved from m2 to m1 on 2026-10-29 (maintainer): after [moq-dev/moq#7166](https://github.com/moq-dev/moq/pull/7166) moved publish secrets into the `publish` Environment, `CARGO_REGISTRY_TOKEN` is the @@ -30,4 +35,4 @@ authentication Action is needed. ## Required - [Remove the moq-e2ee stub](/quest/m1/moq-e2ee-remove.md) - release-plz stops tracking a retired crate that has no trusted publisher -- [crates.io trusts the workflow](/quest/m1/crates-trusted-publisher.md) - every published crate has the trusted publisher configured +- [crates.io trusts the workflow](/quest/m2/crates-trusted-publisher.md) - every published crate has the trusted publisher configured From 40389622ecf3aa6d72ea1f99877f131ae84dda5c Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 5 Nov 2026 14:32:39 -0800 Subject: [PATCH 3/5] quest: address #7982 review: publish the moq-e2ee stub, fold the release Nix cache into cachix-retire Co-Authored-By: Claude Opus 5.5 --- quest/m0/ci/README.md | 2 +- quest/m0/ci/cachix-retire.md | 89 ++++++++++++++-------- quest/m0/ci/mbx-r2-verify.md | 5 +- quest/m0/ci/nix-cache-verify.md | 11 ++- quest/m0/ci/publish-release-only.md | 8 +- quest/m0/test-flakes-2/p2p-data-channel.md | 6 +- quest/m1/moq-e2ee-remove.md | 12 ++- quest/m2/README.md | 1 - quest/m2/release-nix-cache.md | 59 -------------- 9 files changed, 88 insertions(+), 105 deletions(-) delete mode 100644 quest/m2/release-nix-cache.md diff --git a/quest/m0/ci/README.md b/quest/m0/ci/README.md index 776aa02f6b2..ab5f523859b 100644 --- a/quest/m0/ci/README.md +++ b/quest/m0/ci/README.md @@ -180,7 +180,7 @@ The historical samples locate candidates; they are not controlled benchmarks. - [Verify the Nix runtime cache](/quest/m0/ci/nix-cache-verify.md) - hosted Cache uploads `main`'s relay and CLI, and Smoke's nix channel substitutes them - [Record hosted cargo-hakari evidence](/quest/m0/ci/hakari.md) - compare scheduled macOS and Windows cache hits and estimated compiler work saved before and after the workspace-hack - [Drop main from the publish Environment](/quest/m0/ci/publish-release-only.md) - the maintainer narrows `publish` to `release` and release tags once no job naming it runs as `main` -- [Release tags push to nix.moq.dev, and Cachix is retired](/quest/m0/ci/cachix-retire.md) - backport `release-nix.yml` to `release`, drop `cachix.yml`, then delete the Cachix token and cache after a tag proves nix.moq.dev +- [Release tags push to nix.moq.dev, and Cachix stops taking writes](/quest/m0/ci/cachix-retire.md) - backport `release-nix.yml` and its Just module to `release`, drop `cachix.yml`, prove a tag substitutes from nix.moq.dev, then revoke the Cachix token (the cache stays for old tags) - [Measure the Linux cache effect of native media exclusions](/quest/m0/ci/hakari-followups.md) - scheduled Linux jobs measure cache reuse after unrelated tests stop compiling PipeWire and libclang - [A release merge opens no stale release PR](/quest/m0/ci/release-pr-after-release.md) - `just rs release` publishes before it proposes, so a merged release isn't re-proposed - [Build two queue entries at once if it helps](/quest/m0/ci/queue-concurrency.md) - a measured trial of `maximumEntriesToBuild: 2` against the serial lane's burst latency diff --git a/quest/m0/ci/cachix-retire.md b/quest/m0/ci/cachix-retire.md index b5896b957ed..872075be70c 100644 --- a/quest/m0/ci/cachix-retire.md +++ b/quest/m0/ci/cachix-retire.md @@ -1,42 +1,69 @@ -# [S] Release tags push to nix.moq.dev, and Cachix is retired +# [S] Release tags push to nix.moq.dev, and Cachix stops taking writes ## Goal Tags cut from `release` push their Nix packages to nix.moq.dev through -`release-nix.yml`, `release` no longer runs `cachix.yml`, and once a release -tag's uploads and a clean-machine `nix run` substitution are proven, the -`CACHIX_AUTH_TOKEN` repository secret and the `kixelated` Cachix cache are -deleted. +`release-nix.yml`, and a clean machine substitutes a tagged package from +there. `release` no longer runs `cachix.yml`, and `CACHIX_AUTH_TOKEN` is +deleted. Both nix.moq.dev bucket sizes hold under the CI bucket's 30-day +expiry. ## Plan Decided 2026-11-05 (maintainer, /quest-unblock): ✅ backport now and retire -Cachix after the next patch cut on `release`, rather than waiting for the m2 -cut to merge `main` into `release`. Not chosen: retiring it at the m2 cut with -`CACHIX_AUTH_TOKEN` copied into `publish` meanwhile; retiring it at the m2 cut -with the token left at repository scope. This pulls the Cachix part out of -the release Nix cache quest that -[moq-dev/moq#7662](https://github.com/moq-dev/moq/pull/7662) adds in m2, which keeps -only what needs the cut. - -Today `release`'s `cachix.yml` pushes `moq-relay-v*`, `moq-cli-v*`, -`moq-boy-v*`, `libmoq-v*` and `moq-gst-v*` tag builds to Cachix. Its job names -`publish`, which does not hold `CACHIX_AUTH_TOKEN`, so it reads the repository -copy. That copy is what blocks step 3 of -[Keep pull-request CI read-only](/quest/m0/ci/read-only-secrets.md); retiring -Cachix removes it instead of moving it. - -- Backport `main`'s `release-nix.yml` to `release` and delete `cachix.yml` - there, in one PR against `release` that the maintainer merges (agents never - merge into `release`). Match `release`'s own tag patterns (it still cuts - `libmoq-v*`, where `main` cuts `moq-c-v*`) and the flake attributes - `release` builds; the `cache-write` Environment must admit those tags. -- Prove it on the first tag after the backport: Release Nix uploads succeed - on all three platforms, and a clean machine substitutes the tagged package - from nix.moq.dev. -- Then delete `CACHIX_AUTH_TOKEN` and the `kixelated` cache (a Cachix login, - so `Maintainer:`), and drop Cachix from docs that still name it. +Cachix after the first `release` tag that proves nix.moq.dev, rather than +waiting for the m2 cut to merge `main` into `release`. Not chosen: retiring it +at the m2 cut with `CACHIX_AUTH_TOKEN` copied into `publish` meanwhile; +retiring it at the m2 cut with the token left at repository scope. This +absorbs Release tags substitute from nix.moq.dev, which +[moq-dev/moq#7662](https://github.com/moq-dev/moq/pull/7662) had split into m2 +behind the cut; the backport removes its only reason to wait. + +Decided 2026-11-05 (maintainer, /quest-unblock): ✅ revoke the token but keep +the `kixelated` cache read-only. Older tags' flakes list only +`kixelated.cachix.org`, so deleting the cache would make `nix run` on them +build from source. Not chosen: copying the retained release paths to +nix.moq.dev first (old flakes still only name Cachix); deleting the cache and +accepting source builds. + +Today tags run `release`'s copies of the workflows. `release` still has +`cachix.yml` and `cache.yml` and no `release-nix.yml`, so every tag so far, +through `moq-relay-v0.17.9` and `moq-cli-v0.14.9` on 2026-10-28, pushed to +Cachix and never reached nix.moq.dev. `cachix.yml` names `publish`, which does +not hold `CACHIX_AUTH_TOKEN`, so it reads the repository copy. That copy is +what [Keep pull-request CI read-only](/quest/m0/ci/read-only-secrets.md) would +otherwise have to move. + +- Backport to `release`, in one PR the maintainer merges (agents never merge + into `release`): `main`'s `release-nix.yml`, the `infra/nix` Just module and + its entry in `infra/justfile` (`release` has neither, so `just infra nix + push` would fail), any local action it uses, and the deletion of + `cachix.yml`. Match `release`'s own tag patterns (it still cuts `libmoq-v*` + where `main` cuts `moq-c-v*`) and the flake attributes `release` builds; the + `cache-write` Environment must admit those tags. +- On the first `moq-relay-v*` or `moq-cli-v*` tag after the backport, record + its `release-nix.yml` pushes from all three legs, then + `nix run github:moq-dev/moq/#moq-relay --accept-flake-config` + substituting on a clean machine (`#moq` for a CLI tag), such as a fresh + container with only Nix installed. +- Then the maintainer deletes `CACHIX_AUTH_TOKEN` (a repository secret, so + `Maintainer:`), and docs stop naming Cachix as a current cache. + +Public API: none. Wire: none. + +## Waiting + +- Maintainer: record both bucket sizes no earlier than 2026-11-24, a month + after the first `cache.yml` push to `nix-ci-moq-dev` on 2026-10-24, against + the 30-day expiry in `infra/nix/lifecycle.json`. Sizes need a + `wrangler login` to the Cloudflare account, which agents lack. A path + expires 30 days after upload even while CI still reads it, and `nix copy` + re-uploads it on the next merge. Look for Nightly jobs that fell back to + source builds once paths expired (`building '/nix/store/...uniffi-bindgen` + in a job log), and refresh on a schedule or switch to a closure-aware + collector (niks3) if they recur. ## Related -- [Publish off main](/quest/m0/ci/publish-release-only.md) - the other workflow backport to `release` decided in the 2026-11-05 audit +- [Verify the Nix runtime cache](/quest/m0/ci/nix-cache-verify.md) - the same cache's `main` evidence +- [Drop main from the publish Environment](/quest/m0/ci/publish-release-only.md) - the other workflow backport to `release` decided in the 2026-11-05 audit diff --git a/quest/m0/ci/mbx-r2-verify.md b/quest/m0/ci/mbx-r2-verify.md index e81792c20a2..9ad7fc95641 100644 --- a/quest/m0/ci/mbx-r2-verify.md +++ b/quest/m0/ci/mbx-r2-verify.md @@ -78,7 +78,10 @@ compilation is "not looked up". [Windows job](https://github.com/moq-dev/moq/actions/runs/42050683248/job/127326015447) of run 42050683248 set up mbx 1.29.2, and its workspace build, against a manifest of 2,604 predictions, reported 846 hits, 224 misses, 168 not looked - up and 1,019 prefetched. Windows inheritance pays. + up and 1,019 prefetched. Its `Cargo.lock` differed from the previous + scheduled run's, so those hits point to an inherited manifest, but the + summary does not name the manifest identity it looked up; record that + identity from a later Windows job before relying on inheritance. - macOS: on 2026-10-28 the build did inherit, prefetching 732 predictions, yet hit only 13, with 1565 compilations not looked up. The install order is not the cause. Find out why the inherited predictions mostly miss, for diff --git a/quest/m0/ci/nix-cache-verify.md b/quest/m0/ci/nix-cache-verify.md index d86532056a9..3f67ea55449 100644 --- a/quest/m0/ci/nix-cache-verify.md +++ b/quest/m0/ci/nix-cache-verify.md @@ -30,10 +30,13 @@ credentials. Decided 2026-11-05 (maintainer, /quest-audit, [moq-dev/moq#7975](https://github.com/moq-dev/moq/pull/7975)): ✅ keep only this `main` evidence in m0 and move the release-tag proof, Cachix retirement, -and bucket sizes to -[Release tags substitute from nix.moq.dev](/quest/m2/release-nix-cache.md) -behind the release cut. Not chosen: moving the whole quest to m2; merging -`main` into `release` now. +and bucket sizes to an m2 quest behind the release cut. Not chosen: moving the +whole quest to m2; merging `main` into `release` now. + +Superseded the same day (maintainer, /quest-unblock): the release-tag proof, +Cachix retirement, and bucket sizes moved to +[Release tags push to nix.moq.dev](/quest/m0/ci/cachix-retire.md), which +backports `release-nix.yml` to `release` now instead of waiting for the cut. Use the scheduled and push runs; never dispatch Nightly for this evidence. diff --git a/quest/m0/ci/publish-release-only.md b/quest/m0/ci/publish-release-only.md index 250364fd4e2..d8a783618e3 100644 --- a/quest/m0/ci/publish-release-only.md +++ b/quest/m0/ci/publish-release-only.md @@ -23,10 +23,10 @@ The same PR dropped Cachix from `main` (decided 2026-11-02): Smoke's nix channel substitutes from `nix.moq.dev` and no longer pushes, so it names no Environment and `CACHIX_AUTH_TOKEN` needs no new home. The alternatives were moving the token into `cache-write`, or deleting Cachix everywhere now with a -`release` backport. `release` keeps its Cachix workflows until the next cut -merges `main` into it, and -[Release tags substitute from nix.moq.dev](/quest/m2/release-nix-cache.md) deletes the Cachix -cache and token once a release tag substitutes from `nix.moq.dev`. +`release` backport. Changed 2026-11-05 (maintainer, /quest-unblock): +[Release tags push to nix.moq.dev](/quest/m0/ci/cachix-retire.md) backports +`release-nix.yml` and drops `cachix.yml` on `release` now, and deletes +`CACHIX_AUTH_TOKEN` once a release tag substitutes from `nix.moq.dev`. Decided 2026-11-05 (maintainer, /quest-audit): `publish` still admits `main`, so this does not wait for the next cut. diff --git a/quest/m0/test-flakes-2/p2p-data-channel.md b/quest/m0/test-flakes-2/p2p-data-channel.md index 7993d1d4c1d..a7d681550aa 100644 --- a/quest/m0/test-flakes-2/p2p-data-channel.md +++ b/quest/m0/test-flakes-2/p2p-data-channel.md @@ -19,8 +19,10 @@ channel error just before: ERROR:third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc:867] Send failedINVALID_STATE ``` -A send on a data channel that was not open (or already closing) failed, and -the transfer then stalled instead of failing. It timed out once before, in +The log names neither the channel's sender nor its timing against the +stall, so this is a correlation to investigate, not a diagnosis: a send on a +data channel that was not open (or already closing) failed, and the transfer +stalled instead of failing. It timed out once before, in [41668668824](https://github.com/moq-dev/moq/actions/runs/41668668824), and passed locally then. diff --git a/quest/m1/moq-e2ee-remove.md b/quest/m1/moq-e2ee-remove.md index 8e2aa3fd0bd..1a8a05ceba0 100644 --- a/quest/m1/moq-e2ee-remove.md +++ b/quest/m1/moq-e2ee-remove.md @@ -4,8 +4,8 @@ `rs/moq-e2ee` leaves the workspace, along with any release or version config that names it, so release-plz stops tracking a crate whose final release is -out. moq-e2ee 0.0.21, the final no-code release pointing users to moq-crypto, -is on crates.io (published 2026-11-03). +out. moq-e2ee 0.0.22, the final no-code release pointing users to +moq-crypto, is on crates.io. ## Plan @@ -13,6 +13,14 @@ Decided 2026-11-05 (maintainer, /quest-audit): ✅ retire the stub before [Rust releases publish through OIDC](/quest/m2/release-rs-oidc.md), so the crate never needs a trusted publisher. +Published 2026-11-05 (maintainer, /quest-unblock, by an agent at the +maintainer's request): moq-e2ee 0.0.22 from `main`'s stub, with only the +version raised from 0.0.11 locally, since 0.0.21 on crates.io (2026-11-03) and +on `release` is still the full implementation. A 0.0.x caret requirement never +resolves to the next patch, so no dependent upgrades into the stub +unasked. Not chosen: publishing it through the m2 cut; deleting the crate +with no final release. + - Delete `rs/moq-e2ee` (the workspace's `rs/*` glob picks it up) and its `Cargo.lock` entry. - Search release-plz, `version.json`, workflows, and docs for `moq-e2ee` and diff --git a/quest/m2/README.md b/quest/m2/README.md index 9724cf8678b..764a707aea7 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -39,7 +39,6 @@ lite-07; bitrate enforcement is not part of this release. - [Binary release publishers run on their tag](/quest/m2/release-tag-publishers.md) - brew, Go and Swift releases stop running through `workflow_run` on main, once the cut brings the workflows to `release` - [crates.io trusts the workflow](/quest/m2/crates-trusted-publisher.md) - maintainer action: the crates the cut first-publishes by token get a trusted publisher for `release-rs.yml` - [Rust releases publish through OIDC](/quest/m2/release-rs-oidc.md) - release-plz publishes with trusted publishing and `CARGO_REGISTRY_TOKEN` is revoked -- [Release tags substitute from nix.moq.dev](/quest/m2/release-nix-cache.md) - the first tag after the cut substitutes on a clean machine, bucket sizes hold, and Cachix is retired - [One policy for oversized container metadata](/quest/m2/import-metadata-policy.md) - fMP4 and MKV refuse or stream huge metadata by one documented rule - [Wire fuzz coverage](/quest/m2/wire-fuzz-coverage.md) - the cmsg walks in moq-sock and moq-uring have invariant fuzz targets, and the unsafe peer input reaches runs under Miri - [VA-API renderer tests](/quest/m2/vaapi-render-tests.md) - the VA-API renderer, decode, and transcode tests run in `just rs gpu` on AMD and Intel and fail instead of skipping, and hosted CI reports them ignored diff --git a/quest/m2/release-nix-cache.md b/quest/m2/release-nix-cache.md deleted file mode 100644 index cd0cca0cc3c..00000000000 --- a/quest/m2/release-nix-cache.md +++ /dev/null @@ -1,59 +0,0 @@ -# [S] Release tags substitute from nix.moq.dev - -## Goal - -The first release tag cut from `main` substitutes from `nix.moq.dev` on a -clean machine, both bucket sizes hold under the CI bucket's 30-day expiry, and -Cachix is retired. - -## Plan - -Decided 2026-11-05 (maintainer, /quest-audit, -[moq-dev/moq#7975](https://github.com/moq-dev/moq/pull/7975)): ✅ split from -[Verify the Nix runtime cache](/quest/m0/ci/nix-cache-verify.md) and moved to -m2 behind [the cut](/quest/m2/release/cut.md), which brings `main`'s -`release-nix.yml` to `release` when it merges `main` into it. Not chosen: -moving the whole verification quest; merging `main` into `release` now, -which reverses the 2026-11-04 decision. - -Tags run `release`'s copies of the workflows. `release` still has -`cachix.yml` and `cache.yml` and no `release-nix.yml`, so every tag so far, -through `moq-relay-v0.17.9` and `moq-cli-v0.14.9` on 2026-10-28, pushed to -Cachix and never reached `nix.moq.dev`; -`gh run list --workflow release-nix.yml` stays empty until the cut. - -Once the cut lands: - -1. Record the first `moq-relay-v*` or `moq-cli-v*` tag's `release-nix.yml` - pushes from all three legs. -2. Record `nix run github:moq-dev/moq/#moq-relay --accept-flake-config` - substituting on a clean machine (`#moq` for a CLI tag), such as a fresh - container with only Nix installed. -3. Retire Cachix (decided 2026-10-29): that tag is the first release a - downstream user could fetch from `nix.moq.dev`. The cut also brings - `main`'s removal of `cachix.yml` to `release`. - -Public API: none. Wire: none. - -## Waiting - -- Maintainer: Record both bucket sizes no earlier than 2026-11-24, a month - after the first `cache.yml` push to `nix-ci-moq-dev` on 2026-10-24, against - the 30-day expiry in `infra/nix/lifecycle.json`. Sizes need a - `wrangler login` to the Cloudflare account, which agents lack. A path - expires 30 days after upload even while CI still reads it, and `nix copy` - re-uploads it on the next merge. Look for Nightly jobs that fell back to - source builds once paths expired (`building '/nix/store/...uniffi-bindgen` - in a job log), and refresh on a schedule or switch to a closure-aware - collector (niks3) if they recur. -- Maintainer: After step 2, delete the `CACHIX_AUTH_TOKEN` secret and the - `kixelated` Cachix cache; the Cachix account is the maintainer's, and - deleting the cache is irreversible. - -## Required - -- [Cut and publish the prepared breaking release](/quest/m2/release/cut.md) - brings `release-nix.yml` to `release`, where tags run it - -## Related - -- [Verify the Nix runtime cache](/quest/m0/ci/nix-cache-verify.md) - the same cache's `main` evidence From 2449d6e5eb8f4caecaa2ada04f3d13b3e71bd198 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 5 Nov 2026 14:53:39 -0800 Subject: [PATCH 4/5] quest: address #7982 review round 2 Co-Authored-By: Claude Opus 5.5 --- quest/m0/ci/cachix-retire.md | 6 +++--- quest/m0/ci/publish-release-only.md | 7 +++++-- quest/m1/cluster-routing/routes/README.md | 4 +++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/quest/m0/ci/cachix-retire.md b/quest/m0/ci/cachix-retire.md index 872075be70c..8947ac560ec 100644 --- a/quest/m0/ci/cachix-retire.md +++ b/quest/m0/ci/cachix-retire.md @@ -15,8 +15,8 @@ Cachix after the first `release` tag that proves nix.moq.dev, rather than waiting for the m2 cut to merge `main` into `release`. Not chosen: retiring it at the m2 cut with `CACHIX_AUTH_TOKEN` copied into `publish` meanwhile; retiring it at the m2 cut with the token left at repository scope. This -absorbs Release tags substitute from nix.moq.dev, which -[moq-dev/moq#7662](https://github.com/moq-dev/moq/pull/7662) had split into m2 +absorbs [moq-dev/moq#7662](https://github.com/moq-dev/moq/pull/7662)'s m2 +"Release tags substitute from nix.moq.dev" quest, which it had split out behind the cut; the backport removes its only reason to wait. Decided 2026-11-05 (maintainer, /quest-unblock): ✅ revoke the token but keep @@ -28,7 +28,7 @@ accepting source builds. Today tags run `release`'s copies of the workflows. `release` still has `cachix.yml` and `cache.yml` and no `release-nix.yml`, so every tag so far, -through `moq-relay-v0.17.9` and `moq-cli-v0.14.9` on 2026-10-28, pushed to +through `moq-relay-v0.17.12` and `moq-cli-v0.14.12` on 2026-11-03, pushed to Cachix and never reached nix.moq.dev. `cachix.yml` names `publish`, which does not hold `CACHIX_AUTH_TOKEN`, so it reads the repository copy. That copy is what [Keep pull-request CI read-only](/quest/m0/ci/read-only-secrets.md) would diff --git a/quest/m0/ci/publish-release-only.md b/quest/m0/ci/publish-release-only.md index d8a783618e3..8995b044b34 100644 --- a/quest/m0/ci/publish-release-only.md +++ b/quest/m0/ci/publish-release-only.md @@ -44,8 +44,11 @@ What remains, in order: 1. Open the backport PR against `release` (agent work). 2. Once it merges, the maintainer drops `main` from `publish`'s deployment - policy and removes `DISCORD_WEBHOOK` and `CACHIX_AUTH_TOKEN` from - `publish`. Environment settings need the maintainer's admin access. + policy. Environment settings need the maintainer's admin access. + `publish` holds neither `DISCORD_WEBHOOK` (it lives in `alert`) nor + `CACHIX_AUTH_TOKEN` (a repository secret that + [Release tags push to nix.moq.dev](/quest/m0/ci/cachix-retire.md) revokes), + so there is nothing to remove from it. Decided 2026-11-04 (maintainer, /quest-unblock): ✅ cut the combined patch release on `release` soon, once [moq-dev/moq#7596](https://github.com/moq-dev/moq/pull/7596)'s diff --git a/quest/m1/cluster-routing/routes/README.md b/quest/m1/cluster-routing/routes/README.md index 72a12885f5e..c3369242f93 100644 --- a/quest/m1/cluster-routing/routes/README.md +++ b/quest/m1/cluster-routing/routes/README.md @@ -158,7 +158,9 @@ the bullets below are the contract it carries. losing one of two uplinks under one key (`scoped_delivery_through_two_uplinks_reaches_one_key`). - Decided 2026-11-04 (maintainer): a scoped peer's routing identities are - keyed by the route key the peer proves, from a shared key file + keyed by the route key the peer proves, so relays configured with the same + key file fail over as one; a scoped peer that proves no key, such as one on + qmux, gets a per-session key ([session integration](/quest/m1/cluster-routing/routes/session.md), [Scoped peers prove a route key](/quest/m1/cluster-routing/routes/proof.md)). The router takes the key from the caller (`Scope::qualify`). From 5e6df9f4e704715cde065c0c99e7c2377db39c22 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Thu, 5 Nov 2026 15:08:09 -0800 Subject: [PATCH 5/5] quest: cachix-retire also replaces release's cache.yml Co-Authored-By: Claude Opus 5.5 --- quest/m0/ci/cachix-retire.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quest/m0/ci/cachix-retire.md b/quest/m0/ci/cachix-retire.md index 8947ac560ec..238a1ee54a5 100644 --- a/quest/m0/ci/cachix-retire.md +++ b/quest/m0/ci/cachix-retire.md @@ -37,8 +37,10 @@ otherwise have to move. - Backport to `release`, in one PR the maintainer merges (agents never merge into `release`): `main`'s `release-nix.yml`, the `infra/nix` Just module and its entry in `infra/justfile` (`release` has neither, so `just infra nix - push` would fail), any local action it uses, and the deletion of - `cachix.yml`. Match `release`'s own tag patterns (it still cuts `libmoq-v*` + push` would fail), any local action it uses, the deletion of + `cachix.yml`, and `main`'s `cache.yml` in place of `release`'s, whose + dispatch-only `warm` job still runs `cachix push kixelated` with + `CACHIX_AUTH_TOKEN` and would fail once the token is gone. Match `release`'s own tag patterns (it still cuts `libmoq-v*` where `main` cuts `moq-c-v*`) and the flake attributes `release` builds; the `cache-write` Environment must admit those tags. - On the first `moq-relay-v*` or `moq-cli-v*` tag after the backport, record