diff --git a/quest/m0/README.md b/quest/m0/README.md index 8447b4fe55f..7daf1289a1b 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -2,11 +2,14 @@ ## Goal -The work in flight now, in two independent tracks. Relay hardening: legal -moq-transport input never fails a session in current interop coverage, every resource a peer can make the relay hold is bounded by what -it sent or by a budget, and no peer input panics the process. Identity: nothing treats who published a route as what it carries; a path and -the epoch on its route are the only content identity, and every first-party -publisher that can restart mints a fresh epoch, so #4741 stalls nobody. +The work in flight now. Relay hardening: legal moq-transport input never fails +a session in current interop coverage, every resource a peer can make the +relay hold is bounded by what it sent or by a budget, and no peer input panics +the process. Identity: nothing treats who published a route as what it +carries; a path and the epoch on its route are the only content identity, and +every first-party publisher that can restart mints a fresh epoch, so #4741 +stalls nobody. Alongside them: fixes for the `release` line, CI cost, and the +recurring audits. ## Plan @@ -26,7 +29,7 @@ edge, which embeds moq-relay; it moved there on 2026-09-28. Identity: the [broadcast epoch](/quest/m0/broadcast-epoch/README.md) line gates the next release (decided 2026-10-03: #4741 resumes an un-epoched republish into the old broadcast and stalls its -viewers). #4741 can merge to main, but no release ships until first-party +viewers). #4741 is on main, but no release ships until first-party publishers mint epochs. Backport patches cut from `release` don't carry #4741 and aren't gated (decided 2026-10-08). diff --git a/quest/m0/broadcast-epoch/README.md b/quest/m0/broadcast-epoch/README.md index 396e06f4d22..defd571a6d6 100644 --- a/quest/m0/broadcast-epoch/README.md +++ b/quest/m0/broadcast-epoch/README.md @@ -127,7 +127,3 @@ End+Start. The child quests own their focused regressions. ## Required - [Reference announcements](/quest/m0/broadcast-epoch/reference-announcements.md) - native readers restart a replaced referenced sibling on its announcements, never past a named epoch - -## Related - -- [JS consume identity](https://github.com/moq-dev/moq/pull/5254) - requests carry the serving prefix's epoch and new winners cannot reuse an old cached broadcast diff --git a/quest/m0/ci/README.md b/quest/m0/ci/README.md index f893d782bb6..3fee91ca6af 100644 --- a/quest/m0/ci/README.md +++ b/quest/m0/ci/README.md @@ -46,13 +46,18 @@ Decisions (maintainer, 2026-10-13): and run uncached. - Decided 2026-10-19: the merge queue is trusted like `main`, since a queued PR is about to land. Rust cache writers are the jobs on `main` and in its - queue, and no separate warm rebuilds what landed. + queue, and no separate warm rebuilds what landed. Since + [#6040](https://github.com/moq-dev/moq/pull/6040) the queue runs on the + self-hosted `moq-queue` runner with mbx's local store, so the R2 writers are + the hosted Nightly jobs on `main`. - Self-hosted CI is dropped: hosted runners plus the R2 caches replace the spare-desktop runner, its cache server, and the cache release it waited on. - Reopened 2026-10-19, conditionally: [faster runners](/quest/m0/ci/runners.md) - compares it again once the pipeline is optimized. Since 2026-10-20 the - queue runs on the persistent `nix/runner` VM; that quest records its - measurements. + Reopened 2026-10-19, conditionally, to compare runners once the pipeline + was optimized. Decided 2026-10-22 (maintainer): the queue runner is the + persistent `nix/runner` VM (no host mounts or tailnet, firewalled to public + egress), in use since 2026-10-20. Over 32 one-pass entries it took a median + 5.5 minutes per merged PR (p90 11.9, at most 24.2) against 21 minutes on a + hosted runner, with no per-minute bill. Blacksmith is not pursued. Decided 2026-10-15: local CPU admission, test-cost reductions, and setup reductions are all m0. `quest gate` owns generic command admission; repositories @@ -77,7 +82,6 @@ The historical samples locate candidates; they are not controlled benchmarks. - [Require the release gate](/quest/m0/ci/release-gates.md) - condition: the next cut carries `release-gate.yml`; then release PRs require it - [Share local check capacity](/quest/m0/ci/local-gate.md) - gate expensive phases and bound internal fanout -- [Verify the R2 Rust cache](/quest/m0/ci/mbx-r2-verify.md) - condition: the maintainer bootstrap; then measure hits, restore time, and expiry +- [Verify the R2 Rust cache](/quest/m0/ci/mbx-r2-verify.md) - condition: the maintainer bootstrap; then measure the hosted Nightly jobs' hits, restore time, and expiry - [Verify the Nix cache](/quest/m0/ci/nix-cache-verify.md) - confirm CI and releases use `nix.moq.dev` and retire Cachix - [First shared FFI release](/quest/m0/ci/nightly-ffi-reuse.md) - condition: the first `moq-ffi-v*` tag that runs `Release FFI`, and a `Shipping sizes` run; verify the wrappers and size keys -- [Faster runners](/quest/m0/ci/runners.md) - pick hosted, Blacksmith or the NixOS desktop from measurements of the optimized queue diff --git a/quest/m0/ci/mbx-r2-verify.md b/quest/m0/ci/mbx-r2-verify.md index b257bd8a28d..5207fb2cc9b 100644 --- a/quest/m0/ci/mbx-r2-verify.md +++ b/quest/m0/ci/mbx-r2-verify.md @@ -2,28 +2,33 @@ ## Goal -Condition: the `mbx-moq-dev` bootstrap in `infra/README.md` is complete, -including the `cache-write` Environment's `gh-readonly-queue/main/*` branch -policy, and the merge queue has merged Rust changes since. Check it with -`gh run list --workflow check.yml --event merge_group`. - -Then confirm the cache earns its keep, and record the numbers in the PR that -closes this: - -- Each merge queue and `main` job's `Check the cache` step reports - `effective read-write`, and a release pull request's reports - `effective read-only`. -- The merge queue's Check show mbx remote hits for code the queued - pull request did not touch, and Nightly's macOS and Windows jobs hit what - the previous Nightly wrote. +Condition: the `mbx-moq-dev` bootstrap in `infra/README.md` is complete and +scheduled Nightly runs on `main` have built Rust since. Check it with +`gh run list --workflow nightly.yml --branch main`. + +Then 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: + +- Each Nightly job's `Check the cache` step reports `effective read-write`, + and a release pull request's reports `effective read-only`. +- 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 - store it replaced, from the same diff before and after. -- Each object expires 30 days after upload, and the queue builds only what - its diff selects, so an expired crate stays cold until a queue or `main` - job builds it again. Count how often a queue entry pays that rebuild. + store it replaced, from the same commit before and after. +- Each object expires 30 days after upload, so a crate no Nightly builds in + that window stays cold for the next hosted job. Count how often a Nightly + job pays that rebuild. - Bucket size and request counts after a month, against the 30-day expiry in `infra/mbx/lifecycle.json`. Shorten or lengthen it from that. +## Plan + +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 +writes R2. + ## Related - [Require the release gate](/quest/m0/ci/release-gates.md) - the macOS and Windows jobs this cache serves diff --git a/quest/m0/ci/nix-cache-verify.md b/quest/m0/ci/nix-cache-verify.md index 403de9054f2..16818bfe36a 100644 --- a/quest/m0/ci/nix-cache-verify.md +++ b/quest/m0/ci/nix-cache-verify.md @@ -2,9 +2,9 @@ ## Goal -`nix.moq.dev` serves CI and releases: Nix jobs substitute the dev shell -instead of building it, release tags substitute on a clean machine, its -bucket sizes hold under the 30-day expiry, and Cachix is retired. +`nix.moq.dev` serves CI and releases: hosted Nix jobs enter the dev shell +without compiling it, release tags substitute on a clean machine, its bucket +sizes hold under the 30-day expiry, and Cachix is retired. ## Plan @@ -12,28 +12,37 @@ bucket sizes hold under the 30-day expiry, and Cachix is retired. CI. The maintainer ran the bootstrap in `infra/README.md` on 2026-10-19 and 2026-10-20 (the release tag ruleset, both buckets and the Worker, the `cache-write` Environment's tag policies and secrets, and the signing key). Check it with -`curl https://nix.moq.dev/nix-cache-info` and -`gh run list --workflow cache.yml --branch main`. +`curl https://nix.moq.dev/nix-cache-info`. + +Decided 2026-10-22 (maintainer): +[#6040](https://github.com/moq-dev/moq/pull/6040) deleted `cache.yml`, so +nothing pushes the dev shell to `nix.moq.dev`; only `release-nix.yml` pushes, +on release tags. First measure one hosted Nightly job's dev-shell entry time, +no earlier than 2026-11-20: `cache.yml`'s last push to `nix.moq.dev` ran +2026-10-20, and those paths serve a warm entry until the 30-day expiry +removes them. If it still compiles `uniffi-bindgen-go`, `uniffi-bindgen-cpp` and `quest` +(the 12-14 minute baseline below), restore a dev-shell push. Otherwise this +narrows to release-tag substitution and Cachix retirement. Then confirm it, and record the numbers in the PR that closes this: -- The first `main` warm pushes the dev shell, and a later merge queue or - Nightly job enters `nix develop` without compiling uniffi-bindgen-go. The - baseline, measured 2026-10-16 in Nightly run 38897397428: every workload - spent 12-14 minutes building `uniffi-bindgen-go`, `uniffi-bindgen-cpp` and - `quest` before entering the dev shell, because Cachix had no copy. +- A hosted Nightly job enters `nix develop` without compiling + uniffi-bindgen-go. The baseline, measured 2026-10-16 in Nightly run + 38897397428: every workload spent 12-14 minutes building + `uniffi-bindgen-go`, `uniffi-bindgen-cpp` and `quest` before entering the + dev shell, because Cachix had no copy. - The next `moq-relay-v*` or `moq-cli-v*` tag pushes from all three `release-nix.yml` legs, and `nix run github:moq-dev/moq/#moq-relay --accept-flake-config` substitutes on a clean machine. -- Dev shell upload time and both bucket sizes after a month, against the - 30-day expiry in `infra/nix/lifecycle.json`. A path expires 30 days after - its upload even while CI still reads it, and only the next warm restores - it, which runs on a flake or `nix/**` change or a dispatch. Look for jobs - that fell back to source builds in that window. If they recur, add a daily - schedule to `cache.yml` (and alert on its scheduled failures) or switch to - a closure-aware collector (niks3). +- Both bucket sizes after a month, against the 30-day expiry in + `infra/nix/lifecycle.json`. A path expires 30 days after its upload even + while CI still reads it. If a dev-shell push is restored, look for jobs + that fell back to source builds once its paths expired, and refresh it on a + schedule or switch to a closure-aware collector (niks3) if they recur. - Delete the `CACHIX_AUTH_TOKEN` secret and the `kixelated` Cachix cache once - the maintainer decides downstream flakes have had long enough to switch. + the maintainer decides downstream flakes have had long enough to switch, + along with `smoke.yml`'s Cachix substituter and its push step for the nix + channel. ## Related diff --git a/quest/m0/ci/runners.md b/quest/m0/ci/runners.md deleted file mode 100644 index 033e84cfbf7..00000000000 --- a/quest/m0/ci/runners.md +++ /dev/null @@ -1,43 +0,0 @@ -# [S] Faster runners for the merge queue - -## Goal - -The merge queue runs on whichever runner gives the best wall time per dollar -once the pipeline is optimized: hosted runners with the R2 caches, -Blacksmith, or the maintainer's NixOS desktop as a self-hosted runner. The -choice is made from measurements of the optimized pipeline, and its cost per -merged PR is recorded. - -## Plan - -Decided 2026-10-19: pick the runner only after the optimization quests land, -so a faster runner doesn't pay for waste. This reopens the 2026-10-13 -decision to drop self-hosted CI, conditionally: compare all three options -against the new baseline. - -- Main PRs run no cloud CI, so the comparison is the queue's Linux gate, plus - whatever nightly and release PRs need. -- A self-hosted runner on the desktop would run contributor-controlled code: - a maintainer enqueues the PR, but the merge group still builds and runs - what the contributor wrote. Treat every job as untrusted. The desktop is - not a candidate until ephemeral NixOS VMs keep jobs away from its - credentials, files and network, as the closed - [#5218](https://github.com/moq-dev/moq/pull/5218) prepared. -- Blacksmith: compare its price per minute and its cache against hosted ARM - runners plus the R2 caches. -- Measure queue wall time per entry and cost per merged PR on each candidate. - -Measured by the CI pipeline audit (2026-10-21): since 2026-10-20 the queue -runs on the persistent `nix/runner` VM (`MOQ_QUEUE_RUNNER`, 8 cores) with -mbx's local store, so `target/` persists and a checkout rewrites only the -changed files. A `moq-quic` change recompiled only its dependents. Over 32 -one-pass entries, the job took a median 5.5 minutes, p75 8.5, p90 11.9, and -at most 24.2 (every module selected), against 21 minutes for queue run -[39471110155](https://github.com/moq-dev/moq/actions/runs/39471110155) on a -hosted runner before the one pass. Queue waits fell to seconds once Check and -Test merged into one job. The job summary now lists seconds per module, and -the Rust test builds upload Cargo's `--timings` reports. - -## Required - -- [Verify the R2 Rust cache](/quest/m0/ci/mbx-r2-verify.md) - the hosted baseline's cache diff --git a/quest/m1/README.md b/quest/m1/README.md index 8d853307b57..8b436884a86 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -47,9 +47,8 @@ before those quests). The moq-transport passthrough fields remain crate-private, the existing explicit exception to the public model audit. -Added 2026-10-16: refresh, ranked after moq-transport passthrough, whose -dynamic-groups path it promotes. It is a breaking `Demand` change, so it -lands before the cut. +Added 2026-10-16: refresh, a breaking `Demand` change, so it lands before +the cut. Added 2026-10-20 (maintainer): the probe target, native probing, and the native rung disable moved up from the [m2 probe epic](/quest/m2/probe/README.md), @@ -78,6 +77,7 @@ lite-07 stream type here. - [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 - [Broadcast archives](/quest/m1/archive/README.md) - ANNOUNCE, TRACKS, and a SUBSCRIBE per track record every track under a prefix to any object_store, a host serves a stored broadcast back, and the catalog drops its archive pointer for an opt-in `hls` field - [Compressed tracks](/quest/m1/compress/README.md) - a track flagged `compress` is DEFLATEd per group by moq-net, forwarded compressed, and inflated once on the relay for peers that cannot signal it; `catalog.json.z` and moq-flate go away +- [lite-06 max sequence](/quest/m1/lite06-max-sequence.md) - group sequence 2^62-1 reaches a lite-06 subscriber or is refused loudly, instead of vanishing - [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 - [Moxygen minimal interop](/quest/m1/smoke-moxygen.md) - waiting on Moxygen to send a registered filter type, then the smoke lane stops hiding its failure - [More tests under load](/quest/m1/test-flakes-2/README.md) - the second round of load-only failures, one quest per flake, fixed at the cause @@ -105,14 +105,12 @@ lite-07 stream type here. - [WebGPU on Safari](/quest/m1/webgpu-safari.md) - the WebGPU renderer is verified on Safari 26 for macOS and iOS - [Interop finish](/quest/m1/interop-finish.md) - the interop matrix proves a clean broadcast finish across implementations - [Exporters follow a rendition to a new track](/quest/m1/export-rendition-rebind.md) - the fMP4, TS, MKV and FLV exporters rebuild a rendition whose resolved `track` or `broadcast` changes under the same ID -- [lite-06 max sequence](/quest/m1/lite06-max-sequence.md) - group sequence 2^62-1 reaches a lite-06 subscriber or is refused loudly, instead of vanishing - [Track live signal](/quest/m1/track-live.md) - a reader can wait for its track's feed to be live, so a player skips old cached groups while a fresh upstream subscription starts - [moq-net compiles once](/quest/m1/net-erase-transport.md) - the session drivers stop monomorphizing per transport and per crate, saving several MiB of the relay, FFI library, `libmoq` and CLI - [Audio devices on ARM](/quest/m1/audio-devices-arm.md) - `just rs audio-devices` passes on the hosted ARM runner - [CI housekeeping](/quest/m1/ci-housekeeping.md) - validate queue nextest at 24 threads and remove the actionlint queue ignore after its release - [Interop audio delivery](/quest/m1/interop-audio.md) - every interop subscriber decodes and checks the publishers' 440 Hz tone, and the Rust publisher sends Opus and AAC - [Native audio decode conformance](/quest/m1/audio-decode-conformance.md) - Opus and AAC decode through every moq-audio backend, moq-c, and moq-ffi is checked against known tones and clips, like moq-video's suite -- [Allocation-free single-range subscriber window](/quest/m1/window-alloc.md) - a one-range subscribe resolves its window without a heap allocation, recovering the join cost per-subscriber ranges added - [moq-net internals](/quest/m1/net-internals.md) - no per-group session clones, no transport type parameter in lite and IETF internals, and the `Local` check measured - [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 - [Subscribe update churn](/quest/m1/subscribe-update-churn.md) - a viewer sends SUBSCRIBE_UPDATE only on a meaningful change, measured after the publisher stall fix diff --git a/quest/m1/audio-devices-arm.md b/quest/m1/audio-devices-arm.md index a3a12067609..c3190a28e26 100644 --- a/quest/m1/audio-devices-arm.md +++ b/quest/m1/audio-devices-arm.md @@ -11,9 +11,16 @@ The recipe first ran nightly on 2026-10-20 and failed all five playback tests on ARM; nothing owned it ([moq-dev/moq#6155](https://github.com/moq-dev/moq/pull/6155)). [moq-dev/moq#6175](https://github.com/moq-dev/moq/pull/6175) then fixed -PulseAudio's 20 ms playback period for these tests. Check a nightly after -#6175 first: if ARM passes, delete this quest. Otherwise reproduce on ARM -and fix the cause, not the timing. +PulseAudio's 20 ms playback period for these tests. + +But Nightly +[39600361153](https://github.com/moq-dev/moq/actions/runs/39600361153) +(2026-10-21, before #6175 merged) already passed all five on +`ubuntu-24.04-arm`, after the 2026-10-20 failure, with no moq-audio change +between. So a green nightly alone does not prove #6175 fixed it: the failure +may be intermittent. Decided 2026-10-22 (maintainer): delete this quest only +after three consecutive green Nightlies on ARM; on another failure, reproduce +on ARM and fix the cause, not the timing. Public API: none. Wire: none. diff --git a/quest/m1/audio-jitter-target/README.md b/quest/m1/audio-jitter-target/README.md index 76e9ccd03d8..5a3e3580667 100644 --- a/quest/m1/audio-jitter-target/README.md +++ b/quest/m1/audio-jitter-target/README.md @@ -37,8 +37,7 @@ native playback against its budgets. ## Required - [Watch](/quest/m1/audio-jitter-target/watch.md) - the browser's measured target, proven on Chrome and Safari against the public relay -- [Capped budgets](/quest/m1/audio-jitter-target/capped-budgets.md) - post-cap nightlies confirm AAC bursty discards about as much audio as Opus bursty, and every browser row's budgets are re-measured from them -- [Opus near-zero budgets](/quest/m1/audio-jitter-target/opus-near-zero-budgets.md) - post-flush nightlies confirm the first row no longer stalls, and its budgets are tightened from them +- [Capped budgets](/quest/m1/audio-jitter-target/capped-budgets.md) - post-cap nightlies confirm AAC bursty discards about as much audio as Opus bursty and the first row no longer stalls, and every browser row's budgets are re-measured from them ## Closes diff --git a/quest/m1/audio-jitter-target/capped-budgets.md b/quest/m1/audio-jitter-target/capped-budgets.md index 5157f3025c9..5380d15b28d 100644 --- a/quest/m1/audio-jitter-target/capped-budgets.md +++ b/quest/m1/audio-jitter-target/capped-budgets.md @@ -5,16 +5,32 @@ Seven scheduled nightlies on `main` after the estimator began capping how much weight one observation takes show the AAC `bursty` browser rows discarding about as much audio a minute as the Opus `bursty` rows, on both rings, and -`test/audio-quality/budgets.json` carries every browser row's ceilings -re-measured from them. +the Opus `near-zero` `isolated` row holding the same 60 ms target as the +`plain` row with no underrun episodes. `test/audio-quality/budgets.json` +carries every browser row's ceilings re-measured from them. ## Plan Waits on the nightlies: check the `audio-quality-run` artifacts of the scheduled Nightly runs on `main` (`gh run download -n audio-quality-run`) once seven have run since the change merged. Never dispatch the nightly by -hand. Re-measure by the rule in the budgets note, and drop the note's sentence -that budgets the AAC bursty discards against Opus's. +hand. Re-measure by the rule in the budgets note, and drop the note's sentences +that budget the AAC bursty discards against Opus's and the isolated row's +one-second drops as measured. + +Decided 2026-10-22 (maintainer): the Opus near-zero budgets quest folded in +here, so one pass over the same seven nightlies covers both. The cap +([#6164](https://github.com/moq-dev/moq/pull/6164)) merged 2026-10-22T00:10Z, +after the build flush, so post-cap nightlies are also post-flush; none had run +yet. + +The near-zero stall was never the isolated ring. That row is simply the +matrix's first, and a cold `cargo build` left about 800 MB dirty when it +started. On the ARM runner each periodic writeback burst froze the page's main +thread for 100 to 320 ms until the backlog drained, and the harness now +flushes its build before the first row. If the first row still shows +long-task clusters, compare `.longtasks.json` against the runner's disk +activity before changing the player. The cap changed every row's startup, not only AAC bursty's: the prior is replaced in about five seconds instead of two, and a late interval in those @@ -32,7 +48,3 @@ discarding several times Opus's, the remaining source is the publisher: each seven-frame PES flush is seven one-frame groups, delivered newest first, so the oldest frame of a flush waits behind every newer group on a path that cannot carry them together. - -## Related - -- [Opus near-zero budgets](/quest/m1/audio-jitter-target/opus-near-zero-budgets.md) - re-measures some of the same rows from nightlies; take them after the cap so one pass covers both diff --git a/quest/m1/audio-jitter-target/opus-near-zero-budgets.md b/quest/m1/audio-jitter-target/opus-near-zero-budgets.md deleted file mode 100644 index 95697de66ec..00000000000 --- a/quest/m1/audio-jitter-target/opus-near-zero-budgets.md +++ /dev/null @@ -1,28 +0,0 @@ -# [XS] Tighten the Opus near-zero browser budgets after the build flush - -## Goal - -Seven scheduled nightlies on `main` after the harness began flushing its build -before the first row show the Opus `near-zero` `isolated` row holding the -same 60 ms target as the `plain` row with no underrun episodes, and -`test/audio-quality/budgets.json` carries ceilings re-measured from them. - -## Plan - -Waits on the nightlies: check the `audio-quality-run` artifacts of the -scheduled Nightly runs on `main` (`gh run download -n audio-quality-run`) -once seven have run since the fix merged. Never dispatch the nightly by hand. - -The stall was never the isolated ring. That row is simply the matrix's first, -and a cold `cargo build` left about 800 MB dirty when it started. On the ARM -runner each periodic writeback burst (100 to 280 MB, about 10 s apart) froze -the page's main thread for 100 to 320 ms until the backlog drained, about 30 s -in. A branch experiment put the plain ring first after a cold build, and it -failed the same way (540 ms target, the same 10 s long-task clusters). -Isolated-first, with the build flushed beforehand, held 60 ms. - -Re-measure the Opus near-zero rows by the rule in the budgets note, and drop -the note's sentence that budgets the isolated row's one-second drops as -measured. If the first row still shows long-task clusters, compare -`.longtasks.json` against the runner's disk activity before changing the -player. diff --git a/quest/m1/audio-jitter-target/watch.md b/quest/m1/audio-jitter-target/watch.md index 3be4ba1c33f..214b14f199e 100644 --- a/quest/m1/audio-jitter-target/watch.md +++ b/quest/m1/audio-jitter-target/watch.md @@ -58,4 +58,4 @@ defer validation of the current player. ## Related - [A/V clock](/quest/m1/av-clock.md) - reshapes `SyncInput` around the per-track target this line produces -- [Opus near-zero budgets](/quest/m1/audio-jitter-target/opus-near-zero-budgets.md) - confirms the build-flush fix on the nightlies, no gate on this proof +- [Capped budgets](/quest/m1/audio-jitter-target/capped-budgets.md) - confirms the build-flush fix on the nightlies, no gate on this proof diff --git a/quest/m1/audit-ci.md b/quest/m1/audit-ci.md index de67de5203e..4c70b366d97 100644 --- a/quest/m1/audit-ci.md +++ b/quest/m1/audit-ci.md @@ -103,12 +103,15 @@ Check first (from the m0 CI pipeline audit, 2026-10-21): - Cold builds (release PRs, Nightly) still compile both rustls backends and aws-lc-sys once per environment; the queue VM keeps those built. - Nightly on 2026-10-20 took about 1,450 runner-minutes (320 macOS) and was - red for ten causes. Features' clippy is fixed except moq-net's group bench - ([#6117](https://github.com/moq-dev/moq/pull/6117)), and `gh test` was fixed - by [#6086](https://github.com/moq-dev/moq/pull/6086). Unowned: - `rs audio-devices`, new on 2026-10-20, fails all five playback tests on the - hosted ARM runner and passes on x86_64 Linux. Owned elsewhere besides the - above: the Rust and JS benchmark legs by the + red for ten causes. Features' clippy was fixed by + [#6117](https://github.com/moq-dev/moq/pull/6117) (its 2026-10-21 failure + is in tests). `gh test` failed again on 2026-10-21 after + [#6086](https://github.com/moq-dev/moq/pull/6086), then + [#6154](https://github.com/moq-dev/moq/pull/6154) removed the assertion. + `rs audio-devices` failed all five playback tests on the hosted ARM runner + on 2026-10-20 and passed on the 2026-10-21 Nightly; it is owned by + [Audio devices on ARM](/quest/m1/audio-devices-arm.md). Owned elsewhere + besides the above: the Rust and JS benchmark legs by the [performance audit](/quest/m1/audit-perf.md), Audio quality's budgets by the [audio jitter target](/quest/m1/audio-jitter-target/README.md), and the bun advisories with the Rust ones. diff --git a/quest/m1/audit-perf.md b/quest/m1/audit-perf.md index efd65f1efd9..4179cf10e5a 100644 --- a/quest/m1/audit-perf.md +++ b/quest/m1/audit-perf.md @@ -93,8 +93,10 @@ large to review alongside the rest; those become `/quest-plan` follow-ups: Bisect the second pair first, and treat a larger catalog as intended. 4. `annexb` export also gained +9k in `c389bd051`..`eb6ac57cb` and +10k in `75d9bf1c0`..`dcd7d2cbb`, and +27k at `fe722cec9` (#5929), of which the m0 PR recovered 8.5k; attribute the rest only if it persists. -5. The subscribe path's remaining ~1,260 instructions over pre-#5929 belong to - [Allocation-free single-range subscriber window](/quest/m1/window-alloc.md). +5. The subscribe path's remaining ~1,260 instructions over pre-#5929 stay: + an inline single-range window ([#6241](https://github.com/moq-dev/moq/pull/6241)) + removed three allocations but regressed join time about 6%, so it was + dropped (maintainer, 2026-10-22). ### Unbenchmarked hot and fan-out paths, ranked @@ -132,7 +134,3 @@ browser, not node or bun. Benchmarks never gate the merge queue (decided 2026-10-20, maintainer): each Nightly compares them into the git.moq.dev report, which the [nightly benchmark regression report](/quest/m2/bench-ci.md) owns; don't duplicate it. - -## Related - -- [Allocation-free single-range subscriber window](/quest/m1/window-alloc.md) - the subscribe cost the m0 run left after its fix diff --git a/quest/m1/binding-timestamps.md b/quest/m1/binding-timestamps.md index 241adbc930b..fa43d65ee37 100644 --- a/quest/m1/binding-timestamps.md +++ b/quest/m1/binding-timestamps.md @@ -32,9 +32,10 @@ Decided with the maintainer on 2026-10-18: - **m1**, beside data consumer timestamps. - **#5677 shipped** the data-value timestamps with the interim microsecond fields; this quest converts every site at once, `MoqJsonValue` included. -- **Shape mirrors the core:** one `{value, scale}` per value, `value` at most - `2^62 - 1` and `scale` non-zero and at most `2^62 - 1`, matching - `Timestamp::new` and `Timescale::new`. The FFI boundary refuses anything else with +- **Shape mirrors the core:** one `{value, scale}` per value, `value` bounded + as `Timestamp::new` bounds it (`2^61 - 1` once + [#6168](https://github.com/moq-dev/moq/pull/6168) lands, decided 2026-10-22) + and `scale` non-zero and at most `2^62 - 1`, matching `Timescale::new`. The FFI boundary refuses anything else with an error. Rejected: raw ticks at the track scale beside `MoqTrackInfo.timescale`, because a producer argument needs its own scale and per-value records match the core and JS. diff --git a/quest/m1/catalog-identity-rs.md b/quest/m1/catalog-identity-rs.md index 2860c955c90..0aa0f2e26e1 100644 --- a/quest/m1/catalog-identity-rs.md +++ b/quest/m1/catalog-identity-rs.md @@ -70,6 +70,10 @@ Decided 2026-10-20 (maintainer): the moq-c half lands on the [generated C package](/quest/m1/c/README.md), not the frozen hand-written ABI, so C users break once. +The branch checkpoint `origin/quest/m1/catalog-identity-rs` predates the +2026-10-15 decision to mint a new rendition name, so rework it against that +decision rather than resuming it as is. + ## Required - [Generated C bindings](/quest/m1/c/README.md) - the moq-c config re-declaration fix lands on the generated package, not the frozen hand-written ABI diff --git a/quest/m1/cluster-routing/identity.md b/quest/m1/cluster-routing/identity.md index befa96364a8..af40adf53d3 100644 --- a/quest/m1/cluster-routing/identity.md +++ b/quest/m1/cluster-routing/identity.md @@ -41,20 +41,18 @@ its own is refused; a proof copied onto another session is refused; a session with no proof advertises no route of its own. Wire into CI with Rust/JS interop. -Decided 2026-10-20 (audit): this waits only on -[Token in band](/quest/m1/auth/token-in-band.md), not on the whole auth line. -That quest defines the AUTH stream (AUTH, AUTH_OK, AUTH_ERROR); this one adds -AUTH_CNF and the proof to it and specifies their order in the draft, so Rust -and JS implement one stream. +Decided 2026-10-22 (maintainer): this extends the AUTH stream from +[#4039](https://github.com/moq-dev/moq/pull/4039) (`### Auth` in +`drafts/draft-lcurley-moq-lite.md`, `rs/moq-net/src/lite/auth.rs`), adding +AUTH_CNF and the proof to it and specifying their order in the draft, so Rust +and JS implement one stream. It no longer Requires +[Token in band](/quest/m1/auth/token-in-band.md); the auth line stays ranked +ahead of it as a rank, not a block. Wire: `drafts/draft-lcurley-moq-lite.md` gains the key and proof messages in lite-07-wip; `just drafts check` passes. Public API: likely none beyond connection setup; report any key handle that leaks into `moq-ffi`. -## Required - -- [Token in band](/quest/m1/auth/token-in-band.md) - defines the AUTH stream the key and its proof extend - ## Related - [Peer grants](/quest/m2/p2p/peer-grant.md) - binds this key as `cnf` for direct sessions diff --git a/quest/m1/compress/migrate.md b/quest/m1/compress/migrate.md index 76915941907..f43070e290d 100644 --- a/quest/m1/compress/migrate.md +++ b/quest/m1/compress/migrate.md @@ -58,7 +58,13 @@ reader, so this quest lands after both and only sets the flag. Public API: removals listed above. Wire: the hang catalog loses `compression` and the `.z` tracks, in its draft too; moq-net none. +Decided 2026-10-22 (maintainer): this waits on +[Refresh JSON](/quest/m1/refresh/json.md), since both rewrite moq-json's +`snapshot::Config` and moq-stats' `TrackPair` +([#6054](https://github.com/moq-dev/moq/pull/6054) implements it). + ## Required - [Catalog HLS field](/quest/m1/archive/catalog-hls.md) - renames the timeline to `.hls`, which this compresses - [Archive consumer](/quest/m1/archive/consumer.md) - replaces the CLI archive reader that reads `.z` timelines +- [Refresh JSON](/quest/m1/refresh/json.md) - rewrites `snapshot::Config` and moq-stats' `TrackPair` first diff --git a/quest/m1/lite07-finalize.md b/quest/m1/lite07-finalize.md index 83d90ff6813..f9682241f68 100644 --- a/quest/m1/lite07-finalize.md +++ b/quest/m1/lite07-finalize.md @@ -86,6 +86,11 @@ identifier. This release adopts the new routing contract end to end. Public API: the lite-07 version constant and ALPN lose `-wip`. Wire: lite-07 is published; older versions are unchanged. +Decided 2026-10-22 (maintainer): lite-07 also waits for the lite-06 +max-sequence quest, since it may change what the final wire carries. +Timestamp provenance landed in +[#6150](https://github.com/moq-dev/moq/pull/6150). + ## Required - [Token in band](/quest/m1/auth/token-in-band.md) - lite-07 carries the Auth Stream and UNAUTHORIZED (0x3B) @@ -94,6 +99,7 @@ is published; older versions are unchanged. - [Drop set](/quest/m1/drop-set.md) - lite-07's SUBSCRIBE_DROP carries `Max Age`, so a widening re-offers groups reported dropped - [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - SUBSCRIBE carries ranges and an order and lite FETCH is gone, in Rust and JS - [Announcement takeover](/quest/m1/announce-takeover.md) - ANNOUNCE_TAKEOVER preserves a proven instance under a new independent route +- [lite-06 max sequence](/quest/m1/lite06-max-sequence.md) - the refusal boundary for an uncarriable sequence is settled before lite-07 freezes - [TRACKS in js/net](/quest/m1/archive/tracks-js.md) - JS speaks lite-07's Tracks Stream, which Rust already does - [lite-07 padding](/quest/m1/lite07-padding.md) - lite-07 reserves the padding stream type the browser probes with diff --git a/quest/m1/quic/README.md b/quest/m1/quic/README.md index e0bc59479ae..73b76f896ff 100644 --- a/quest/m1/quic/README.md +++ b/quest/m1/quic/README.md @@ -14,8 +14,9 @@ fairness gives the crate-private send domains (#5872) their consumer in qmux already runs on the shared stream state machine, outside this epic. Per-stream acknowledgment progress, per-stream deadlines, and the experiments (the egress profile, ECN measurement, deadline keep-alive) live in -[m2](/quest/m2/README.md); media -probing is its own [m2 epic](/quest/m2/probe/README.md); receive timestamps +[m2](/quest/m2/README.md); padding and the browser rung disable stay in the +[m2 probe epic](/quest/m2/probe/README.md); native probing is +[m1](/quest/m1/probe-native.md); receive timestamps and a delay-based uplink controller are the [m2 realtime epic](/quest/m2/quic-realtime/README.md); L4S and careful resume live in [m3](/quest/m3/README.md). None of them gate this line. diff --git a/quest/m1/quic/receive-memory.md b/quest/m1/quic/receive-memory.md index 1e2c83477a9..b99433a0b28 100644 --- a/quest/m1/quic/receive-memory.md +++ b/quest/m1/quic/receive-memory.md @@ -18,8 +18,9 @@ peer-visible QUIC flow control instead of a separate header quota error. The native transport primitive is a separate prerequisite; do not activate whole-message retention without its recovery policy in this quest. -In flight as [#5878](https://github.com/moq-dev/moq/pull/5878) (draft); -the earlier drafts #5735 and #5752 were closed in its favor. +In flight as [#5878](https://github.com/moq-dev/moq/pull/5878) (ready for +review) on branch `quest/m1/quic/receive-memory-lease`; the earlier drafts +#5735 and #5752 were closed in its favor. Decided 2026-10-20 (maintainer): three quests break moq-net's `transport::poll` traits, so they land in order and each rebases its trait diff --git a/quest/m1/refresh/README.md b/quest/m1/refresh/README.md index d3d57d3dea1..a255071319f 100644 --- a/quest/m1/refresh/README.md +++ b/quest/m1/refresh/README.md @@ -16,8 +16,8 @@ Boundaries: themselves without a timer. - Joining is the only trigger. There is no explicit subscriber request; a decoder that lost sync rereads the cached group from its start. -- Non-goals: flate modes, json stream mode, and importers that cannot force - a keyframe (CMAF, TS). +- Non-goals: json stream mode and importers that cannot force a keyframe + (CMAF, TS). ## Plan diff --git a/quest/m1/release-perf/recheck.md b/quest/m1/release-perf/recheck.md index 1baf90d6e49..96fe6a23552 100644 --- a/quest/m1/release-perf/recheck.md +++ b/quest/m1/release-perf/recheck.md @@ -42,8 +42,9 @@ Leads from reading code on 2026-10-21, strongest first: datagram ring twice ([#5195](https://github.com/moq-dev/moq/pull/5195)). Track the newest datagram timestamp on push. The window's construction cost from [#5929](https://github.com/moq-dev/moq/pull/5929) was cut in - [#6112](https://github.com/moq-dev/moq/pull/6112), and the rest belongs to - [Allocation-free single-range subscriber window](/quest/m1/window-alloc.md). + [#6112](https://github.com/moq-dev/moq/pull/6112); an inline single-range + window ([#6241](https://github.com/moq-dev/moq/pull/6241)) regressed join + time, so the rest stays. 5. `track_parallel_write`, `track_fanout_frame`, `track_empty_run`, `group_write_frames` (1.2 to 1.6x). This is constant per-group and per-frame cost from several features. Resolve `now` once per poll in diff --git a/quest/m1/resolved-demand.md b/quest/m1/resolved-demand.md index f7e01852efd..0ab1b24a644 100644 --- a/quest/m1/resolved-demand.md +++ b/quest/m1/resolved-demand.md @@ -21,8 +21,8 @@ copy's first one. Found while building SUBSCRIBE_ALL ([moq-dev/moq#5931](https://github.com/moq-dev/moq/pull/5931)), which -patched it for listed tracks only by sending the resolved start as an -absolute floor (`listed_demand` in `f074d09e7`). +closed unmerged; its listed-track workaround (sending the resolved start as +an absolute floor) never reached main. Decided by the maintainer on 2026-10-19: re-offer when the max age widens, with no wire change. diff --git a/quest/m1/resume-rust-end.md b/quest/m1/resume-rust-end.md index 4e434faed59..679381b8dd9 100644 --- a/quest/m1/resume-rust-end.md +++ b/quest/m1/resume-rust-end.md @@ -26,6 +26,12 @@ narrower Rust `route_failed`, moved to the recovery verdicts work. Regression test per gap, on a mocked clock, mirrored in JS where JS lacks one. +Decided 2026-10-22 (maintainer), settled in +[#6224](https://github.com/moq-dev/moq/pull/6224)'s review: Rust refuses a copy +declaring a different end with the same non-route-failure classification as +JS's `Incompatible` (`js/net/src/resume.ts`). Merge order: #6136, then #6224 +(#6209 and #6251 have landed). + Public API: behavior only. Wire: none. ## Related diff --git a/quest/m1/simulcast-rung-disable.md b/quest/m1/simulcast-rung-disable.md index d574517ea65..84cdce3db26 100644 --- a/quest/m1/simulcast-rung-disable.md +++ b/quest/m1/simulcast-rung-disable.md @@ -85,3 +85,4 @@ publishers expose for it. Wire: none; `enabled` already exists. - [Ladder controller](/quest/m3/ladder/controller.md) - the same rung disable for generated transcode ladders - [OBS multitrack](/quest/m2/obs-multitrack.md) - OBS's native multitrack encoders as the renditions this disables - [Viewer up-switch](/quest/m2/probe/viewer-upswitch.md) - the viewer side of moving between renditions as capacity changes +- [Closed rung disable](https://github.com/moq-dev/moq/pull/5850) - reference code from before the 2026-10-20 split, closed as superseded diff --git a/quest/m1/smoke-moxygen.md b/quest/m1/smoke-moxygen.md index 2c8a3fbe312..70d1243490e 100644 --- a/quest/m1/smoke-moxygen.md +++ b/quest/m1/smoke-moxygen.md @@ -27,8 +27,9 @@ SUBSCRIPTION_FILTER parameter whose Filter Type varint is 250. they accept any subscribe error, including that session close; once the client is fixed they must still pass on a real REQUEST_ERROR. -Advance it by reporting the reproducer to facebookexperimental/moxygen once -the maintainer approves posting there; the fix is a registered default +Reported upstream as +[facebookexperimental/moxygen#225](https://github.com/facebookexperimental/moxygen/issues/225), +acknowledged 2026-10-16; check it and the Smoke job. The fix is a registered default (Largest Object or Next Group Start) for drafts that lack LargestGroup. Do not accept 0xFA in moq-relay. diff --git a/quest/m1/subscribe-ranges/lite.md b/quest/m1/subscribe-ranges/lite.md index ea10d101460..6600a91b9ad 100644 --- a/quest/m1/subscribe-ranges/lite.md +++ b/quest/m1/subscribe-ranges/lite.md @@ -53,6 +53,14 @@ the priority table in `doc/concept/moq-lite.md`: it now describes the field FETCH, answered through the model's ranges. Run `just drafts check` and `just test interop --all`. +Decided 2026-10-22 (maintainer): SUBSCRIBE_OK carries the resolved start for +a relative range start, so a reader's ordered cursor takes its floor from it +([Container reads drop backfill](/quest/m1/read-backfill.md)). + ## Required - [Dynamic range requests](/quest/m1/subscribe-ranges/dynamic.md) - the misses a relay fills upstream by range + +## Related + +- [Container reads drop backfill](/quest/m1/read-backfill.md) - floors its ordered cursor on the resolved start diff --git a/quest/m1/test-flakes-2/README.md b/quest/m1/test-flakes-2/README.md index 49eb823a56f..a3d66d51d46 100644 --- a/quest/m1/test-flakes-2/README.md +++ b/quest/m1/test-flakes-2/README.md @@ -32,16 +32,8 @@ times on a loaded machine, as the first round did. The redundant failover drift moved to m0 on 2026-10-20 (maintainer) and is fixed by [moq-dev/moq#6113](https://github.com/moq-dev/moq/pull/6113). -Added 2026-10-20 (maintainer): three more from that day's merge batch, the -draft-16 cancel race first since it fails on a mocked clock and so may hide -an ordering bug. The failed-listen test was meant to join the redial quest, -which #6032 had already finished, so it reuses #6032's reserved-port fix as -its own child. moq-uring's `host_tracks_moq_clock` was seen the same day -but #6056 had already fixed it by measuring the calibration gap. - -Added 2026-10-21 (maintainer): three small flakes and a fresh-worktree -interop failure from the m0/m1 merge run, kept in one child since each is -small. +Added 2026-10-21 (maintainer): small flakes from the m0/m1 merge run, kept +in one child; only the OBS stop drain remains. Public API: none. Wire: none. diff --git a/quest/m1/ts-reliability/README.md b/quest/m1/ts-reliability/README.md index 525abf4dd6f..2cedd1b3ba6 100644 --- a/quest/m1/ts-reliability/README.md +++ b/quest/m1/ts-reliability/README.md @@ -41,10 +41,9 @@ periodic cuts, and an intact object alone do not ensure available PAT/PMT, codec configuration, clock context, or references for every MPTS program. The README owns the guide and integration proof for the modes present in -m1: semantic remux and raw import/carriage. The deferred raw export quest -extends the guide and proves its output when it lands; it does not block -this proof. Reuse the children's fixtures and CI recipes, including their -known-bad controls. Publish +m1: semantic remux and raw import/carriage. Raw export and its packet-level +proof landed in #5856; the guide covers it too. Reuse the children's +fixtures and CI recipes, including their known-bad controls. Publish a coverage table linking each supported profile and loss guarantee to its test; unsupported or unmeasured cells stay explicit. Keep CLI instructions and the MPEG-TS draft consistent in each feature change. diff --git a/quest/m1/window-alloc.md b/quest/m1/window-alloc.md deleted file mode 100644 index 74e84686151..00000000000 --- a/quest/m1/window-alloc.md +++ /dev/null @@ -1,28 +0,0 @@ -# [S] Allocation-free single-range subscriber window - -## Goal - -Subscribing with one range, as nearly every subscriber does, resolves its -`Window` without a heap allocation, so a join costs what it did before -per-subscriber ranges ([#5929](https://github.com/moq-dev/moq/pull/5929)). - -## Plan - -The m0 performance audit measured `track_subscriber_join` with callgrind: -3,233 instructions per join before #5929, 6,950 after it, and 4,492 once the -audit's PR resolved the servable window once and kept a single run inline -(`Servable`). The remaining ~1,260 instructions are `Window::new` in -`rs/moq-net/src/model/subscription/window.rs` and its drop: it clones the -ranges into a `Vec`, pushes the spans into another, and inserts the groups into -a `RangeInclusiveSet`, so a default subscription allocates three times. - -Give the common case an inline representation: one range, one span, and its -groups as a single run, spilling to the current collections only for several -ranges. This is private to moq-net. Measure instructions per join the way the -audit did (a loop of `subscribe` plus `poll_subscription_changed`, the -difference of two iteration counts under callgrind), and keep -`track_subscriber_join` and `track_subscriber_churn` as the Nightly check. - -## Related - -- [Performance audit](/quest/m1/audit-perf.md) - the recurring audit that found the cost diff --git a/quest/m2/README.md b/quest/m2/README.md index e57782b25aa..d5d9f8cc95f 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -34,7 +34,7 @@ ranked just below deterministic TS legs, which it requires. - [Kotlin calls](/quest/m2/kt-ffi-calls.md) - Kotlin calls into moq-ffi cost about what Python's and Go's do, sync and async, once the fork's Kotlin generator drops JNA's per-call overhead - [Poll-native async](/quest/m2/ffi-poll-migrate.md) - moq-ffi's pure-kio async exports poll their state directly instead of going through `ffi::Task` - [Foreign poll for hot reads](/quest/m2/ffi-poll-protocol.md) - the fork's generators give each wrapper a sync poll plus a registered waker for track and group reads, so a ready read skips the event-loop round trip and a cancel never loses a frame -- [QoS](/quest/m2/qos/README.md) - broadcast health: relay starvation and timeliness histograms +- [QoS](/quest/m2/qos/README.md) - the relay's egress `lag` histogram and `dropped` counters on the stats totals and prefix tracks - [Plan: watch worker](/quest/m2/plan-watch-worker.md) - prototype an invisible page worker against app-spawned workers, and land the jank harness that decides - [Watch worker](/quest/m2/watch-worker.md) - watch playback runs in a worker onto an OffscreenCanvas, so main-thread jank never stalls video or audio - [Vulkan Video encode on AMD](/quest/m2/vulkan-encode.md) - H.264 and H.265 from an external Vulkan image on RADV, hand-rolled on ash, proven on an RX 9070 @@ -144,7 +144,7 @@ ranked just below deterministic TS legs, which it requires. - [Link quality](/quest/m2/link-quality.md) - a radio link's cost follows its measured quality without flapping routes - [Ring drain GOAWAY](/quest/m2/uring-ring-drain.md) - the ring sends moq-transport 17+ sessions their drain GOAWAY - [Relay io_uring packages](/quest/m2/relay-io-uring-package.md) - Linux relay packages ship io_uring once the ring is on par with tokio -- [moq-transport machines](/quest/m2/uring-transport-machines.md) - moq-transport polls named state machines, retiring `Boxable` and `moq_uring::transport::Local` +- [io_uring thread check](/quest/m2/uring-transport-machines.md) - the relay fanout bench measures `moq_uring::transport::Local`'s per-call thread check after the transport is boxed, removing it only if it shows - [Opus implementation](/quest/m2/audio-opus-backend.md) - compare Opus codec quality, CPU, build cost, and the loss recovery each backend offers - [Latency ledger](/quest/m2/latency-ledger.md) - a viewer reports its share of playback delay stage by stage: jitter buffer, decode, render, and device - [Media Foundation decode](/quest/m2/audio-decode-mediafoundation.md) - Windows decodes HE-AAC, multichannel AAC, and what else the MFTs offer @@ -174,7 +174,7 @@ ranked just below deterministic TS legs, which it requires. - [GPU capacity and health](/quest/m2/gpu-health.md) - moq-video reports each device's sessions, memory, utilization, and health on NVIDIA, AMD, and Intel alike - [A release carries multi-vendor GPU input](/quest/m2/gpu-release.md) - `release` carries the GPU surface validated on AMD and Intel; health follows separately - [Runtime trait](/quest/m2/runtime-trait.md) - one runtime trait for spawn and time replaces web-async, with tokio, browser, io_uring, and sim implementations -- [QUIC on the sim](/quest/m2/quic-sim.md) - the sim drives `moq-quic` over in-memory datagrams with latency and loss +- [QUIC on the sim](/quest/m2/quic-sim.md) - MoQ sessions and the relay run over `moq-quic` on the seeded sim, reusing its `Pair` and `Link` - [Seeded sim](/quest/m2/sim-seed.md) - sim tests draw every jitter from one seeded generator and replay bit-exact - [DVR rewind](/quest/m2/archive-dvr.md) - follow-on capability after the release contract is stable diff --git a/quest/m2/audio-decode-audiotoolbox.md b/quest/m2/audio-decode-audiotoolbox.md index 69633f6229e..df09f5c2b3b 100644 --- a/quest/m2/audio-decode-audiotoolbox.md +++ b/quest/m2/audio-decode-audiotoolbox.md @@ -32,9 +32,8 @@ alongside the `objc2-core-audio-types` the crate already carries. end up where `Layout` says). - iOS: the binding compiles into the moq-ffi iOS slice; runtime proof waits on a device like the rest of the mobile line. -- Docs: `doc/lib/rs/moq-audio.md` drops its caveat that multichannel AAC and - HE-AAC are refused on macOS and iOS, and its backend table names what this - host decodes. +- Docs: the `decode` row in `doc/lib/rs/moq-audio.md` ("AAC-LC (mono or + stereo)") names what macOS and iOS also decode. ## Related diff --git a/quest/m2/audit-docs.md b/quest/m2/audit-docs.md index dfe13580b3c..54ef0e1bec7 100644 --- a/quest/m2/audit-docs.md +++ b/quest/m2/audit-docs.md @@ -28,7 +28,10 @@ the codec lists in `doc/bin/rtmp.md` and `srt.md`. Read those kinds of pages claim by claim against the code first; the pages recent PRs edit are the freshest. Baselines: -- Rust: 28 crates set `#![warn(missing_docs)]`; m1 added `moq-shaper` and +- Rust: 31 crates set `#![warn(missing_docs)]`, including `moq-mux`, + `moq-ffi`, and `moq-c` since + [#6088](https://github.com/moq-dev/moq/pull/6088) and + [#6091](https://github.com/moq-dev/moq/pull/6091); m1 added `moq-shaper` and `moq-wasm`. Count the rest with `cargo rustdoc -p --lib --all-features -- -W missing_docs`, and `moq-wasm` with `--target wasm32-unknown-unknown`, since it is empty on @@ -37,11 +40,7 @@ freshest. Baselines: `moq-audio`, `moq-video`, and `moq-sock` were also clean on Linux but stay unlinted for their macOS, Windows, and Android items. `moq-gst` has 3 items from `gst::plugin_define!`. `moq-v4l` reports 3108, nearly all its generated - `sys` bindings; whether the fork earns docs is still undecided. `moq-mux`, - `moq-ffi`, and `moq-c` had follow-ups in flight - ([docs-mux](https://github.com/moq-dev/moq/pull/6088), - [docs-bindings](https://github.com/moq-dev/moq/pull/6091)); check that they - landed and set the lint. + `sys` bindings; whether the fork earns docs is still undecided. - JS: since [docs-js](https://github.com/moq-dev/moq/pull/6163), every published package's build runs `js/common/docs.ts`, which fails on an undocumented export or public class member, so check only that its diff --git a/quest/m2/drop-dead-items.md b/quest/m2/drop-dead-items.md index 6870a4980b9..ab6128a8b96 100644 --- a/quest/m2/drop-dead-items.md +++ b/quest/m2/drop-dead-items.md @@ -4,17 +4,17 @@ The uncalled items the dead-code audit found are gone: moq-cli's `nvenc` and `nvdec` Cargo feature aliases, `moq_net::Version::uses_setup_negotiation`, -and moq-net's test helpers `track::Subscriber::assert_error`, -`AnnounceConsumer::assert_next_restarted`, and -`AnnounceConsumer::assert_next_ended`. +and moq-net's test helper `track::Subscriber::assert_error`. The +`AnnounceConsumer::assert_next_*` helpers stay: `model/origin.rs` calls them +since [#5678](https://github.com/moq-dev/moq/pull/5678). ## Plan From [moq-dev/moq#6166](https://github.com/moq-dev/moq/pull/6166). Decided 2026-10-21 with the maintainer: m2. Verify each still has no caller across the repo, bindings included, before removing it; keep any that gained one. -The test helpers live in `model/track.rs` and `model/origin.rs`, which many -open PRs churn, so expect merge conflicts there. +The test helper lives in `model/track.rs`, which many open PRs churn, so +expect merge conflicts there. Public API: breaking for moq-cli (features) and moq-net (`Version`), with a `MIGRATE.md` entry in each. Wire: none. diff --git a/quest/m2/error-cleanups.md b/quest/m2/error-cleanups.md index 98b2e5d2ad1..853c8ec8e8b 100644 --- a/quest/m2/error-cleanups.md +++ b/quest/m2/error-cleanups.md @@ -2,7 +2,7 @@ ## Goal -`moq_net::Error::SessionClosed`, which nothing outside tests constructs, is +`moq_net::Error::SessionClosed`, which has no meaning of its own, is deleted. ## Plan @@ -18,6 +18,9 @@ behavior and its tests; only the `SessionClosed` removal remains here. `SessionClosed` has match arms in `rs/moq-net` (`error.rs`, `model/resume.rs`), `rs/moq-ffi/src/error.rs` and `rs/moq-relay`, and -test-only uses in `rs/moq-hls`, `rs/moq-gst` and `rs/moq-relay`. Removing a +test-only uses in `rs/moq-hls`, `rs/moq-gst` and `rs/moq-relay`. +`rs/moq-net/src/model/track.rs`'s `close` constructs it only to convert it; +decided 2026-10-22 (maintainer): keep the removal and construct +`StreamError::Session(SessionError::Cancel)` there directly. Removing a public variant is a breaking Rust change: add the `rs/moq-net/MIGRATE.md` entry. Wire: none. diff --git a/quest/m2/go-first-dial-failure.md b/quest/m2/go-first-dial-failure.md index a161c12cf42..721071f788c 100644 --- a/quest/m2/go-first-dial-failure.md +++ b/quest/m2/go-first-dial-failure.md @@ -15,7 +15,6 @@ failure accessor; add it the way the other wrappers expose it. [moq-dev/moq#6170](https://github.com/moq-dev/moq/pull/6170) found that `doc/lib/kt/index.md` and `doc/lib/dart/index.md` say `client.failure()` while their examples only use `Moq.connect`, which never hands back a -`Client` before connecting. Align that wording once the linger and auth -binding PRs that also touch those pages have landed. +`Client` before connecting. Align that wording. Public API: Go additive. Wire: none. diff --git a/quest/m2/intra-refresh/README.md b/quest/m2/intra-refresh/README.md index ac72c0af628..08ceca2a431 100644 --- a/quest/m2/intra-refresh/README.md +++ b/quest/m2/intra-refresh/README.md @@ -52,7 +52,7 @@ make these presentation guarantees true even when sweep lengths change. - [Join earlier group](/quest/m2/intra-refresh/join-earlier-group.md) - max-delay decoders, native and browser, start a group before the live edge even when the live edge arrives first - [Dual decoder](/quest/m2/intra-refresh/dual-decoder.md) - js/watch runs a min-delay and a max-delay decoder and shows the max-delay picture whenever it has caught up - [Play dual decoder](/quest/m2/intra-refresh/play-dual-decoder.md) - `moq play`'s paced pipeline reuses that pair -- [Plan: recovery boundaries](/quest/m2/intra-refresh/plan-boundary.md) - settle safe precision and publication ordering before consumers rely on a duration +- [Plan: recovery boundaries](/quest/m2/intra-refresh/plan-boundary.md) - settle publication ordering and amend the draft so a dual-decoder player may present before `warmup` ends - [Consumer warmup](/quest/m2/intra-refresh/consumer-warmup.md) - the transcoder decodes the groups covering `warmup` as history before each group, except at a true IDR - [H.264 import](/quest/m2/intra-refresh/h264-import.md) - the splitter keeps `recovery_frame_cnt` and import publishes `warmup` from it - [H.265 import](/quest/m2/intra-refresh/h265-import.md) - the splitter reads the recovery-point SEI so an HEVC intra-refresh stream forms groups and publishes `warmup` diff --git a/quest/m2/intra-refresh/consumer-warmup.md b/quest/m2/intra-refresh/consumer-warmup.md index 17ce8bd805f..1ffafd36f0d 100644 --- a/quest/m2/intra-refresh/consumer-warmup.md +++ b/quest/m2/intra-refresh/consumer-warmup.md @@ -38,8 +38,8 @@ The fix is history rather than a withhold rule: slice NAL type (H.264 type 5; H.265 `IDR_W_RADL`, `IDR_N_LP`, the BLA types) with the NAL walkers in `rs/moq-mux/src/codec/{h264,h265}`. Other codecs never set `warmup`. -- Rung fetch: fetch groups N-K through N-1 alongside N, decode them first, and - start the encoder at N. If history is no longer available, fail the fetch +- Rung fetch: fetch groups N-K through N as one range subscription, decode + N-K through N-1 first, and start the encoder at N. If history is no longer available, fail the fetch loudly instead of encoding stripes. - Live feed: for a `warmup` rendition, read groups in sequence order, not arrival order. Treat a skipped sequence as a discontinuity and decode the K @@ -56,3 +56,7 @@ The fix is history rather than a withhold rule: ## Required - [Plan: recovery boundaries](/quest/m2/intra-refresh/plan-boundary.md) - K derives from `warmup`, which must be a safe upper bound + +## Related + +- [Fetch as a range](/quest/m1/subscribe-ranges/fetch-range.md) - the range read the history fetch uses diff --git a/quest/m2/intra-refresh/h264-import.md b/quest/m2/intra-refresh/h264-import.md index 7dc8e8eebed..677340d4317 100644 --- a/quest/m2/intra-refresh/h264-import.md +++ b/quest/m2/intra-refresh/h264-import.md @@ -12,9 +12,11 @@ were immediately decodable. ## Plan The recovery-boundary planning prerequisite must settle the precision and -publication ordering before implementing the duration proposal below. In -particular, rounding down and raising a catalog value after a longer sweep -are not yet proven safe for a viewer that already received those pictures. +publication ordering before implementing the duration proposal below. Raising +a catalog value after a longer sweep is not yet proven safe for a viewer that +already received those pictures. Decided 2026-10-22 (maintainer): precision +follows the hang draft, which rounds up +([#5212](https://github.com/moq-dev/moq/pull/5212)). - `rs/moq-mux/src/codec/h264/split.rs`: `sei_has_recovery_point` returns the `recovery_frame_cnt` the `h264-parser` crate already exposes on @@ -31,8 +33,8 @@ are not yet proven safe for a viewer that already received those pictures. reference picture whose `frame_num` is the recovery point's plus the count, modulo `MaxFrameNum`), so the importer tracks slice-header `frame_num` from the recovery point, finds that picture, and sets `warmup` to its timestamp - minus the group start, rounded down to whole milliseconds so the recovery - picture itself is never withheld. The catalog is published once the first + minus the group start, rounded up to whole milliseconds as the hang draft + requires, so the history always reaches the recovery picture. The catalog is published once the first sweep has measured it; a later, longer sweep mutates it upward. A stream whose recovery picture never arrives before the next recovery point is refused, not published with a guess. @@ -45,4 +47,4 @@ are not yet proven safe for a viewer that already received those pictures. ## Required -- [Plan: recovery boundaries](/quest/m2/intra-refresh/plan-boundary.md) - resolve the rounded and later-mutated warmup contract before implementing it +- [Plan: recovery boundaries](/quest/m2/intra-refresh/plan-boundary.md) - resolve the later-mutated warmup contract before implementing it diff --git a/quest/m2/intra-refresh/plan-boundary.md b/quest/m2/intra-refresh/plan-boundary.md index 4f3c755c7ad..d3f8643c621 100644 --- a/quest/m2/intra-refresh/plan-boundary.md +++ b/quest/m2/intra-refresh/plan-boundary.md @@ -15,6 +15,15 @@ to milliseconds and raises the global value after observing a longer sweep. rounded value can leave the history short of the recovery picture, and a later catalog update cannot recall pictures a subscriber has already displayed using the old value. +Decided 2026-10-22 (maintainer): precision is settled; the hang draft rounds a +fractional-millisecond `warmup` up +([#5212](https://github.com/moq-dev/moq/pull/5212)). This quest amends the +draft's `warmup` rule so a consumer running a parallel max-delay decoder MAY +present min-delay pictures before the group start plus `warmup`, which keeps +the merged dual decoder in `decode::Consumer` +([#5842](https://github.com/moq-dev/moq/pull/5842)). Publication ordering for +a later, longer sweep remains to settle. + Ask the maintainer to choose between an exact per-group boundary and a safe bound known and published before the affected content, including the latency and catalog/container consequences. Test timestamp precision, reordered diff --git a/quest/m2/mux-vr-fields.md b/quest/m2/mux-vr-fields.md index 296ec358771..5628aebbc9b 100644 --- a/quest/m2/mux-vr-fields.md +++ b/quest/m2/mux-vr-fields.md @@ -34,8 +34,10 @@ landed the fields. `ambisonic`, and zeroth order or a non-diegetic stereo pair (1, 3, 6, 11, ... channels) is refused. A count RFC 8486 forbids is malformed and refused the same way. -- `mp4-atom` 0.16.2 has no `st3d` or `sv3d` atom; add them in - kixelated/mp4-atom. `webm-iterable` already names the Matroska elements. +- kixelated/mp4-atom#244 added `st3d`/`sv3d` (plus Apple `vexu`/`hfov`); + take mp4-atom 0.17.0 (kixelated/mp4-atom#247, not yet released), whose + sample entries gain a `spatial` field. Importing Apple's `vexu`/`hfov` + stays out of scope. `webm-iterable` already names the Matroska elements. - An fMP4 Opus track needs the `dOps` mapping table that [CMAF surround Opus](/quest/m2/cmaf-opus-surround.md) adds, so ambisonic fMP4 follows it; Matroska and raw Opus do not wait. diff --git a/quest/m2/net-wrap/e2ee.md b/quest/m2/net-wrap/e2ee.md index f159d63f10a..24fc09fb1ed 100644 --- a/quest/m2/net-wrap/e2ee.md +++ b/quest/m2/net-wrap/e2ee.md @@ -83,3 +83,7 @@ and each compressed object's authenticated inflated size. ## Required - [moq-net traits](/quest/m2/net-wrap/traits.md) - the traits this implements + +## Related + +- [Compressed tracks](/quest/m1/compress/README.md) - the per-group compression the wrapper applies before AEAD diff --git a/quest/m2/net-wrap/traits.md b/quest/m2/net-wrap/traits.md index ae8a649ae9f..e30095867be 100644 --- a/quest/m2/net-wrap/traits.md +++ b/quest/m2/net-wrap/traits.md @@ -30,8 +30,10 @@ the methods exactly as moq-net has them today. `broadcast::Dynamic`, whose `requested_track` yields its own `track::Request`, so generic code serves undeclared names (as [E2EE dynamic names](/quest/m2/e2ee/dynamic-names.md) needs). A track - dynamic's `requested_group` yields its own `group::Request`, whose - `accept` returns its own group producer. + dynamic's `requested_fill` yields its own `track::Fill`, whose + `accept` returns its own group producer and whose `drop_groups` names + the rest dropped + ([dynamic range requests](/quest/m1/subscribe-ranges/dynamic.md)). - Pending operations: `track::Consumer::subscribe` resolves to the wrapper's own subscriber, so E2EE decrypts behind it; `Querying` and `Fetching` resolve to the wrapper's logical metadata and groups. @@ -58,3 +60,10 @@ the methods exactly as moq-net has them today. to `MIGRATE.md`. Public API: new moq-net traits, plus the hidden test-wrapper feature. Wire: none. + +Decided 2026-10-22 (maintainer): the traits break moq-net's public API, so +they wait for the breaking release cut. + +## Required + +- [Breaking release cut](/quest/m2/release/cut.md) - the traits land after the cut that ships m1's breaks diff --git a/quest/m2/perf/relay-allocs.md b/quest/m2/perf/relay-allocs.md index 125894f5c50..b09e07b24fe 100644 --- a/quest/m2/perf/relay-allocs.md +++ b/quest/m2/perf/relay-allocs.md @@ -24,4 +24,13 @@ that grows with the table shows as a slope. Decided 2026-10-17 (maintainer): m2, under perf. +Decided 2026-10-22 (maintainer): this waits on +[dropping web-transport-trait](/quest/m2/drop-web-transport-trait.md), which +replaces the session clones and boxed opens at the top of this profile; +re-profile after it lands before fixing what remains. + Public API: none expected. Wire: none. + +## Required + +- [Drop web-transport-trait](/quest/m2/drop-web-transport-trait.md) - removes the per-stream session clone and boxed future, so the profile is retaken after it diff --git a/quest/m2/probe/rung-disable-js.md b/quest/m2/probe/rung-disable-js.md index 09de623431f..a6e5fb5808a 100644 --- a/quest/m2/probe/rung-disable-js.md +++ b/quest/m2/probe/rung-disable-js.md @@ -36,3 +36,7 @@ Public API: whatever knob `@moq/publish` exposes for the rule. Wire: none. - [Native rung disable](/quest/m1/simulcast-rung-disable.md) - the shared rule and constants this mirrors - [Padding probes](/quest/m2/probe/padding.md) - the browser's sender, which raises the estimate so a disabled rung can resume + +## Related + +- [Closed rung disable](https://github.com/moq-dev/moq/pull/5850) - reference code from before the 2026-10-20 split, closed as superseded diff --git a/quest/m2/publish-announce-never.md b/quest/m2/publish-announce-never.md index e991d80588c..4684d5d07c5 100644 --- a/quest/m2/publish-announce-never.md +++ b/quest/m2/publish-announce-never.md @@ -22,7 +22,3 @@ document that on the `announce` attribute. Public API: `@moq/publish`'s `announce` attribute and property. Also check `demo/web` for uses. - -## Closes - -- [#5703](https://github.com/moq-dev/moq/issues/5703) - Announce is required to be subscribed by moq-watch diff --git a/quest/m2/qos/README.md b/quest/m2/qos/README.md index 46498189b18..2bea01c97a7 100644 --- a/quest/m2/qos/README.md +++ b/quest/m2/qos/README.md @@ -34,8 +34,9 @@ and publisher timeliness lives downstream. This line only reports the counters. Decided (2026-10-06 audit): stats prefix tracks (`/traffic.json`) -landed first, since they are a prerequisite of the lag API; both are deferred to m2 by the maintainer -on 2026-10-15; the lag histogram lands on the stats totals and +landed first in #5811, since they are a prerequisite of the lag API; the lag +histogram was deferred to m2 by the maintainer on 2026-10-15 and lands on the +stats totals and prefix tracks rather than the per-path `publisher.json` and `subscriber.json` map rows, which stay unchanged for existing readers (2026-10-12). diff --git a/quest/m2/qos/lag-histogram.md b/quest/m2/qos/lag-histogram.md index fc07250d37a..8e39b45126b 100644 --- a/quest/m2/qos/lag-histogram.md +++ b/quest/m2/qos/lag-histogram.md @@ -14,9 +14,10 @@ last partial interval. Decided 2026-10-08: split out of the QoS line so the dashboard and publisher timeliness can require a histogram that exists on `main`. This quest lands it -on `main` once prefix tracks have, moved from the per-path `publisher.json` -and `subscriber.json` map rows it writes today onto the totals and prefix -tracks. +on `main` now that prefix tracks have landed +([#5811](https://github.com/moq-dev/moq/pull/5811)), moved from the +per-path `publisher.json` and `subscriber.json` map rows it writes today +onto the totals and prefix tracks. Decided 2026-10-09: the QoS line ([#4133](https://github.com/moq-dev/moq/pull/4133)) closed without landing, diff --git a/quest/m2/quic-ack-hook.md b/quest/m2/quic-ack-hook.md index 18587e955d8..76d4b8482a0 100644 --- a/quest/m2/quic-ack-hook.md +++ b/quest/m2/quic-ack-hook.md @@ -49,9 +49,9 @@ everything was acknowledged, so the adapter answers from that. The trait method takes a byte offset, like `moq-quic` (decided 2026-10-17 on #5817); the starvation quest's writer counts the bytes it writes. Leave the browser transport on the default; the browser's `WebTransportSendStream.getStats()` is unimplemented in shipping Chrome and its `bytesAcknowledged` is at risk in the -W3C draft. qmux over a reliable transport may treat serialization as -acknowledgment only if the qmux quest decides that is honest; until then it -also reports unsupported. +W3C draft. Decided 2026-10-22 (maintainer): qmux's `poll_acked` reports +unsupported too, since writing into TCP is not delivery; over qmux the +histogram stays at group granularity. Tests cover: offset already acknowledged before the first poll, an offset in the middle of an in-flight frame, several waiters on one stream in offset diff --git a/quest/m2/quic-sim.md b/quest/m2/quic-sim.md index 9869acedc3c..bcf3ecc3509 100644 --- a/quest/m2/quic-sim.md +++ b/quest/m2/quic-sim.md @@ -2,19 +2,22 @@ ## Goal -The `moq-clock` sim drives two `moq-quic` endpoints over in-memory datagrams -with configurable latency, loss, reordering, and bandwidth, so QUIC behavior -(BBR, reliable reset, stream deadlines, the transport race) and MoQ over -real QUIC are tested deterministically with no sockets. +The `moq-clock` sim drives MoQ sessions and the relay over `moq-quic`, with +configurable latency, loss, reordering, and bandwidth, so MoQ over real QUIC +(the transport race, relay hops, recovery) is tested deterministically with +no sockets. ## Plan The in-memory session and the relay connection over it -(`moq_relay::Accepted`) landed first; simulated UDP follows. -`moq-quic` already takes `moq_clock::Instant`, so this is a datagram link plus a -driver. Start from moq-shaper's in-memory `UdpSocket` (`rs/moq-shaper/src/mem.rs`). -BBR's controller-level `Sim` in `bbr3/mod.rs` stays separate unless this -replaces it cleanly. +(`moq_relay::Accepted`) landed first. `moq-quic`'s own tests already run two +endpoints on a seeded, impaired sim (`Pair` and `Link` in +`rs/moq-quic/src/tests/{util,sim}.rs`, from +[#5780](https://github.com/moq-dev/moq/pull/5780) and +[#5989](https://github.com/moq-dev/moq/pull/5989)), so QUIC-level behavior is +covered there. Decided 2026-10-22 (maintainer): rescoped to MoQ sessions and +the relay over that sim, reusing `Pair` and `Link` rather than starting from +moq-shaper's in-memory `UdpSocket`. Keep random loss for recovery correctness. Any acceptance or performance consumer uses a rate below its media bitrate behind a deep but finite queue, diff --git a/quest/m2/release/cpp-release.md b/quest/m2/release/cpp-release.md index 6d181c642bd..4fc68bfb173 100644 --- a/quest/m2/release/cpp-release.md +++ b/quest/m2/release/cpp-release.md @@ -19,7 +19,7 @@ from the release line's C build (`obs-moq-v0.6.17`, 2026-10-17); the first plugin built on the C++ package replaces it at this tag. Decided when the C++ line landed on `main` (#4079): the first plugin built on the C++ package must not drop the Advanced settings or the dock's protocol and reconnect reason that the moq-c -build had, so those parity quests gate this release. +build had; that parity landed in #5726 and #6131. The nightly C++ and OBS release checks pass: the [2026-10-20 Nightly](https://github.com/moq-dev/moq/actions/runs/39421743227), @@ -32,10 +32,6 @@ the tag's source build and archive check on all four hosts, then both OBS builds, and publishes nothing. This quest owns that dry run, tagging, and verifying the published downloads. -Decided in the 2026-10-10 audit: the tag also waits for Codecs and the epoch -rename, so consumers take the binding breaks in one -release. - ## Required - [Breaking release cut](/quest/m2/release/cut.md) - prepared code reaches release before artifact publication and installed proof diff --git a/quest/m2/release/dart-publish.md b/quest/m2/release/dart-publish.md index 82e1b2429be..4a3f306743a 100644 --- a/quest/m2/release/dart-publish.md +++ b/quest/m2/release/dart-publish.md @@ -13,9 +13,6 @@ tag-driven publish works. `moq` has only 0.1.0 (2026-09-25), the one `moq-dart-v*` tag so far, so whether its tag publishes unattended through trusted publishing is still unproven. -Decided in the 2026-10-10 audit: publication waits for Codecs and the epoch -rename, so Dart takes the binding breaks in one -release. This replaces the 2026-10-05 decision to drop the FFI shape wait. Trusted-publishing configuration and checks of already-published artifacts can proceed independently; cutting the tag cannot. diff --git a/quest/m2/render-d3d11.md b/quest/m2/render-d3d11.md index ef902188fef..0f3c2648d16 100644 --- a/quest/m2/render-d3d11.md +++ b/quest/m2/render-d3d11.md @@ -19,9 +19,10 @@ rather than copying, keeping the same per-path fallback and disable behavior the other import paths use: a machine where the import cannot work should quietly take the I420 route, not fail to present. -This is where the epic's "egress accessors for the other GPU variants as their -consumers land" comes due for `d3d11::Texture`: the renderer is that consumer, -so whatever access it needs becomes public here rather than ahead of it. +The renderer is the first consumer of `d3d11::Texture`'s contents outside +moq-video's frame module (its fields are `pub(crate)`, +`rs/moq-video/src/frame.rs`), so whatever access it needs becomes public here +rather than ahead of it. Worth doing on Windows specifically because 4K screen sharing is where the download plus re-upload costs most, and WGC screen capture makes that the diff --git a/quest/m2/route-health/README.md b/quest/m2/route-health/README.md index 1d41f3a4540..c37fddb05d8 100644 --- a/quest/m2/route-health/README.md +++ b/quest/m2/route-health/README.md @@ -19,8 +19,9 @@ Decided with the maintainer, 2026-10-13: - A route that dies without a close counts as such a stall until the QUIC idle timeout fires (decided 2026-10-20, from [#6062](https://github.com/moq-dev/moq/issues/6062)): a killed relay - starves a same-epoch subscription for the whole timeout, and a subscriber - max age below it sheds that backlog even though resume asks for it. + starves a same-epoch subscription until the QUIC idle timeout fires; since + [#6183](https://github.com/moq-dev/moq/pull/6183) resume recovers only what + max age still holds, so a max age below the timeout still loses media. - Application-assigned connection priority remains ahead of additive cost. Deterministic hashing still chooses distinct equal routes; a new connection diff --git a/quest/m2/route-health/design.md b/quest/m2/route-health/design.md index ae3030f8816..06a22be2d84 100644 --- a/quest/m2/route-health/design.md +++ b/quest/m2/route-health/design.md @@ -14,7 +14,9 @@ reproducing a stall that transport failure and ordinary reconnect miss; if none exists, bring abandoning the line back to the maintainer. A killed relay in a same-epoch diamond qualifies until the idle timeout fires ([#6062](https://github.com/moq-dev/moq/issues/6062)); measure the media it -loses and how far a standby shortens that. Preserve +loses and how far a standby shortens that, starting from +[#6183](https://github.com/moq-dev/moq/pull/6183)'s mock-time diamond in +`rs/moq-net/tests/integration/route_change.rs`. Preserve application priorities, automatic health-driven switching and failback, a payload-free steady standby, and bounded payload overlap to verify delivery. The mechanism is entirely excluded for epochless broadcasts. diff --git a/quest/m2/rs2ts-js.md b/quest/m2/rs2ts-js.md index 0e043da3188..4fbc3fd8e1c 100644 --- a/quest/m2/rs2ts-js.md +++ b/quest/m2/rs2ts-js.md @@ -30,8 +30,6 @@ Retire obsolete runtime loaders, package paths, and CI only after JS-only parity and adoption. Preserve the Rust binding crate, WASM build tools, or WASM comparison baseline wherever generation or tests still need them; wasm2js may still require WASM at build time. Preserve shared browser tests. -Review the linked older WASM issues against the delivered behavior and close -only those actually resolved, rather than closing them merely on deletion. Public API: `@moq/net` remains; enumerate any approved changes and obsolete unpublished package removals. Wire: none. @@ -39,7 +37,3 @@ unpublished package removals. Wire: none. ## Required - [WASM-to-JS evaluation](/quest/m2/rs2ts-wasm2js.md) - the selected route, evidence, and any additional prerequisites - -## Related - -- [#2907](https://github.com/moq-dev/moq/issues/2907) - reassess against the replacement before retiring WASM paths diff --git a/quest/m2/rs2ts-wasm2js.md b/quest/m2/rs2ts-wasm2js.md index 56ebb2c56c8..9c6315d83ea 100644 --- a/quest/m2/rs2ts-wasm2js.md +++ b/quest/m2/rs2ts-wasm2js.md @@ -64,8 +64,8 @@ Preserve earlier source-translation evidence: - [#5337](https://github.com/moq-dev/moq/issues/5337) reports closure-body retention and control-flow duplication fixes in Charon [#1513](https://github.com/AeneasVerif/charon/pull/1513) and - [#1514](https://github.com/AeneasVerif/charon/pull/1514). Verify their status - and pin before relying on them; its emitter benchmark does not establish + [#1514](https://github.com/AeneasVerif/charon/pull/1514). Both merged + upstream; pin a Charon revision carrying them before relying on them; its emitter benchmark does not establish the performance of a future emitter. - Source translation must establish precise Drop/Arc/Weak behavior, kio wakers and guards, unsafe storage, nested Option states, trait objects, diff --git a/quest/m2/rs2ts/wasm-bindings.md b/quest/m2/rs2ts/wasm-bindings.md index e4a0e779053..cbcb4eee43e 100644 --- a/quest/m2/rs2ts/wasm-bindings.md +++ b/quest/m2/rs2ts/wasm-bindings.md @@ -25,8 +25,8 @@ moves to [adoption](/quest/m2/rs2ts/wasm-adopt.md). Until [ubrn reads UniFFI 0.32](/quest/m2/rs2ts/ubrn-032.md), generation keeps applying `test/wasm/uniffi/pin.patch` to a scratch checkout. -Gaps the spike found against `@moq/net` and moq-wasm: moq-ffi exposes no negotiated -version and has no WebSocket fallback on wasm, and payload copies cost about 7 to 8 ns +Gaps the spike found against `@moq/net` and moq-wasm: moq-ffi has no WebSocket +fallback on wasm, and payload copies cost about 7 to 8 ns per byte (see [Payload bytes](/quest/m2/ffi-bytes.md)). Measure boundary calls, Promise allocation, payload copies, and retained memory. Compare a batched poll/event-drain boundary if these dominate, including latency and backpressure effects; diff --git a/quest/m2/site/move.md b/quest/m2/site/move.md index c9f4fc5dd44..ef44c084f27 100644 --- a/quest/m2/site/move.md +++ b/quest/m2/site/move.md @@ -60,6 +60,10 @@ Decided 2026-10-20 in planning: moq.dev's [hosted worklet adoption](https://github.com/moq-dev/moq.dev/blob/main/quest/m0/dogfood-assets.md) can fold back into it. Rank the voice demo quests in m2 on their own, not under this epic, so they do not hold it open. + Decided 2026-10-22 (maintainer): moq.dev's m0/biome-local and + m0/lean-agents-md are made moot by the move (the monorepo's Biome and + `AGENTS.md` govern) and are not ported; m0/astro-typecheck is ported as + the Astro type check in the `site` CI module. - **Port the open draft posts** by re-applying their MDX under `site/` as draft PRs here: moq-dev/moq.dev#148 (Update 02), #145 (Web Datagrams), #132 (AI Influencer outline), and #124 (More Hops, Lower Latency). Close the stale #16 diff --git a/quest/m2/starvation-frames.md b/quest/m2/starvation-frames.md index 4760ae8f2ab..6663375ceb8 100644 --- a/quest/m2/starvation-frames.md +++ b/quest/m2/starvation-frames.md @@ -4,15 +4,15 @@ Each subscription's acknowledged frontier moves at every frame boundary instead of once per group, so the starvation histogram and dropped-media -counters from the group slice read a frontier at most one frame stale, and a +counters from the lag histogram read a frontier at most one frame stale, and a second histogram reports per-frame delivery delay so viewer jitter is visible -per broadcast. The wire shape from the group slice is unchanged apart from +per broadcast. The wire shape from the lag histogram is unchanged apart from the new histogram. ## Plan A frame is atomic to the viewer: it is useful only once fully delivered. The -sampler from the parent quest is unchanged; what changes is how often the +sampler from the lag histogram is unchanged; what changes is how often the frontier it reads moves. `Writer` in `rs/moq-net/src/coding/writer.rs` gains a monotonic written-offset counter, since every write funnels through it, so at each frame end the per-group serve task knows the stream offset and the @@ -24,7 +24,7 @@ acknowledged in order for the purpose of this metric, so poll the oldest pending frame and retire everything at or below the acknowledged offset. Each acknowledged frame moves the subscription's frontier to that frame's -timestamp, so the interval samples from the parent quest read a frontier that +timestamp, so the interval samples from the lag histogram read a frontier that is at most one frame stale instead of one group. When a stream is reset before a frame is acknowledged, `dropped_duration` now grows by the span from the newest acknowledged frame to the newest written one, which is @@ -39,16 +39,16 @@ and the peer's delayed-ACK timer, since the hook reports no corrected instant histogram absent, never zero. Backends that return unsupported from `poll_acked` keep the group-granularity -sampling from the parent quest, so the histogram never disappears over qmux or +sampling from the lag histogram, so the histogram never disappears over qmux or a browser transport; document which resolution a node offers. Deferred to m2 with the parent QoS sampler. Group-granularity lag lands first after the next release; frame-granularity sampling then adds the ACK hook without making either resolution a release gate. -Decided 2026-10-08: the group-granularity sampler is the egress lag histogram -from the QoS line, which so far exists only on its line branch, so that quest -is Required. +Decided 2026-10-08: the group-granularity sampler is the +[viewer lag histogram](/quest/m2/qos/lag-histogram.md), not yet on main (its +code is on `wip/4133-lag-histogram`), so that quest is Required. Tests: the frontier tracking frame ends under a peer that acknowledges in bursts, with interval samples landing one bucket lower than group-granularity diff --git a/quest/m2/stats/js.md b/quest/m2/stats/js.md index a9ba86c21d0..561bd628e83 100644 --- a/quest/m2/stats/js.md +++ b/quest/m2/stats/js.md @@ -2,7 +2,8 @@ ## Goal -`` announces a stats track in its catalog and fills it. +`` announces a stats track in its catalog and fills it, and an +attribute solicits feedback by setting the catalog's `echo` section. ``, given an echo name, publishes an `.echo` broadcast under the echo path of a catalog soliciting feedback. Both use the `@moq/hang` schemas. @@ -17,6 +18,8 @@ echo path of a catalog soliciting feedback. Both use the `@moq/hang` schemas. A `stats` attribute enables it. - `transport` carries PROBE rtt only, because `WebTransport.getStats()` returns nothing useful in Chromium or Firefox today. + - An `echo-path` attribute sets the catalog's `echo` section, matching + Rust's `moq import --echo-path` (decided 2026-10-22, maintainer). - `js/watch`: - The decoder `Stats` signals grow late frames, stalls and stalled duration, underruns from the worklet's count, decode errors, and the diff --git a/quest/m2/stats/rust.md b/quest/m2/stats/rust.md index 03b32a5008d..c6b7acbd982 100644 --- a/quest/m2/stats/rust.md +++ b/quest/m2/stats/rust.md @@ -7,8 +7,10 @@ - `moq play`, given `--echo `, publishes an `.echo` broadcast under each watched catalog's echo path and fills its feedback track with what it received, decoded, and played. -- The gateway imports (`hls`, `rtmp`, `srt`, `rtc`) and `archive` take +- The gateway imports (`hls`, `rtmp`, `srt`, `rtsp`, `rtc`) and `archive` take `--stats`. +- `moq import --echo-path ` solicits feedback: it sets the catalog's + `echo` section, named apart from the viewer's `--echo `. ## Plan @@ -39,6 +41,11 @@ `--echo` when it adds one: they would publish rendition IDs and per-track counters in plaintext beside it. +- Decided 2026-10-22 (maintainer): the publisher's solicit option moved here + from [encoder feedback](/quest/m3/stats-encoder-feedback.md), which keeps + only the adaptation loop and reuses `--echo-path`. + ## Related - [Encrypted native CLI](/quest/m2/e2ee/cli.md) - refuses stats and feedback on an encrypted broadcast +- [Encoder feedback](/quest/m3/stats-encoder-feedback.md) - the adaptation loop that reads what `--echo-path` solicits diff --git a/quest/m2/uniffi-fork.md b/quest/m2/uniffi-fork.md index 4e0a15b30dc..21c63bb638d 100644 --- a/quest/m2/uniffi-fork.md +++ b/quest/m2/uniffi-fork.md @@ -25,7 +25,9 @@ UniFFI: external generator has released for 0.32, so moq already carries three forks, each pinned in about five places. The core also blocks work moq needs: byte copies, zero-copy returns, and namespaced external types - (mozilla/uniffi-rs#3026). + (mozilla/uniffi-rs#3026, auto-closed by our + [#5498](https://github.com/moq-dev/moq/pull/5498) and still unfixed + upstream). - **Hard fork, fresh repo**: `moq-dev/uniffi` is a new repository, not a GitHub fork and not submodules. Import uniffi-rs at the 0.32.2 release and the three generators at their pinned tags diff --git a/quest/m2/uniffi-namespaces.md b/quest/m2/uniffi-namespaces.md index e8c945ac712..ed3ae3dda22 100644 --- a/quest/m2/uniffi-namespaces.md +++ b/quest/m2/uniffi-namespaces.md @@ -11,7 +11,9 @@ and C from [moq-dev/uniffi](/quest/m2/uniffi-fork.md). Decided with the maintainer on 2026-10-13: fix [mozilla/uniffi-rs#3026](https://github.com/mozilla/uniffi-rs/issues/3026) -in the fork instead of waiting for upstream. +in the fork instead of waiting for upstream. That issue shows closed only +because our [#5498](https://github.com/moq-dev/moq/pull/5498) auto-closed it; +it remains unfixed upstream. - `TypeUniverse` keys types by `(module_path, name)` instead of bare name, and each generator qualifies cross-crate references through the other diff --git a/quest/m2/uring-transport-machines.md b/quest/m2/uring-transport-machines.md index e4664aec709..ca93b95acd5 100644 --- a/quest/m2/uring-transport-machines.md +++ b/quest/m2/uring-transport-machines.md @@ -1,24 +1,33 @@ -# [L] moq-transport runs as named state machines +# [S] Measure the io_uring transport's thread check ## Goal -moq-transport sessions poll named state machines instead of boxed futures, -so the io_uring workers drive them without `transport::poll::Boxable` or -`moq_uring::transport::Local`'s per-call thread check. +The relay fanout benchmark measures what `moq_uring::transport::Local`'s +per-call thread check costs on the ring once +[moq-net compiles once](/quest/m1/net-erase-transport.md) lands, and the +check is removed only if it shows up. `transport::poll::Boxable` stays the +single bound. ## Plan #5821 serves moq-transport on the ring by wrapping its transport in `moq_uring::transport::Local` (renamed from `Pinned`), which checks the thread on every call because the ietf path requires `Boxable`. Decided with -#5821 (maintainer): ship `Local` public now and convert to named machines -later, retiring both. Kept in m2 (decided 2026-10-17). +#5821 (maintainer): ship `Local` public now. Kept in m2 (decided 2026-10-17). -Measure the per-call cost `Local` adds on the ring before and after, on the -relay fanout benchmark swept over sessions and subscribers. +Decided 2026-10-22 (maintainer): rescoped from converting moq-transport to +named state machines to measuring the check after +[#6176](https://github.com/moq-dev/moq/pull/6176) boxes the transport. Sweep +the fanout benchmark over sessions and subscribers, with and without the +check, and remove it only if the difference shows. -Public API: `moq_uring::transport::Local` and `Boxable` go away. Wire: none. +Public API: none unless the check goes, which removes +`moq_uring::transport::Local`. Wire: none. + +## Required + +- [moq-net compiles once](/quest/m1/net-erase-transport.md) - boxes the transport the check wraps ## Related -- [Relay io_uring packages](/quest/m2/relay-io-uring-package.md) - not blocked on this; `Local` already gives parity +- [Relay io_uring packages](/quest/m2/relay-io-uring-package.md) - not blocked on this; `Local` already gives parity, and only its cost is measured here diff --git a/quest/m2/webgpu-hdr.md b/quest/m2/webgpu-hdr.md index 938986b7ea7..bea853dc759 100644 --- a/quest/m2/webgpu-hdr.md +++ b/quest/m2/webgpu-hdr.md @@ -11,8 +11,8 @@ drawn as if it were SDR as today. ## Plan Decided 2026-10-08 in the WebGPU renderer `/quest-plan` interview: SDR and -wide gamut first in the `@moq/video` WebGPU renderer (`js/video`), HDR here, -HDR and its catalog extension now follow in m2. +wide gamut first in the `@moq/video` WebGPU renderer (`js/video`). HDR +follows here; the catalog colour fields it reads landed in #5846. Facts (2026-10): diff --git a/quest/m3/stats-encoder-feedback.md b/quest/m3/stats-encoder-feedback.md index 660d438b5c3..079e1ada45a 100644 --- a/quest/m3/stats-encoder-feedback.md +++ b/quest/m3/stats-encoder-feedback.md @@ -18,7 +18,7 @@ Decided 2026-10-08: parked, and the transcode leg is out. The `moq-transcode` rung's target, so `moq transcode --echo` feeds the folded stall signal to that controller rather than to `rate::Control`; split it into its own quest requiring the controller if this is revived. This quest -covers the encode producers and `moq import --echo`, which need no ladder. +covers the encode producers and `moq import --echo-path`, which need no ladder. - `encode::Options` in `rs/moq-video` and `rs/moq-audio` (the producer options, beside `bandwidth`) gains `echo: Option`. @@ -54,8 +54,8 @@ covers the encode producers and `moq import --echo`, which need no ladder. (`Options::bandwidth` in `rs/moq-audio/src/encode/producer.rs` reserves only). It follows this signal only once the grant quest lands; until then the loop drives video. -- `moq import --echo ` sets the catalog's `echo` section and wires the - handle. +- `moq import --echo-path `, which already sets the catalog's `echo` + section ([Rust stats](/quest/m2/stats/rust.md)), also wires the handle. - Test: the CLI publishes to a relay, and two `moq play --echo` viewers report under the echo path, one of them throttled through the impairment profile. The target bitrate drops within two intervals of the throttled diff --git a/quest/m3/teleop-robot.md b/quest/m3/teleop-robot.md index 144b43eaa13..040a1aa36ca 100644 --- a/quest/m3/teleop-robot.md +++ b/quest/m3/teleop-robot.md @@ -45,6 +45,9 @@ that might exceed the budget before encoding, leaving the log intact and writable (`rs/moq-json/src/stream/mod.rs`). It never rolls its one group; when its budget is spent the publisher opens a new track. A link drop or reconnect loses what was in flight. +Those caps hold until [Unbounded groups](/quest/m2/unbounded-groups/README.md) +lands; after it, a lagging reader refills a shed part of the group or sees +`Evicted`. So the contract is ordered, gap-free delivery for a live reader within one bounded log, and recovery after a reconnect belongs to the application protocol. That is an acceptable division for MAVLink, whose mission, parameter @@ -121,4 +124,5 @@ control then it is the wrong abstraction. ## Related +- [Unbounded groups](/quest/m2/unbounded-groups/README.md) - removes the group caps that bound the reliable class's one log - [arbitration](/quest/m3/teleop-arbitration.md) - which controller is obeyed diff --git a/test/wasm/generator.md b/test/wasm/generator.md index 09bf2338c47..bb5e94733c7 100644 --- a/test/wasm/generator.md +++ b/test/wasm/generator.md @@ -175,7 +175,7 @@ three bindings. moq-wasm's column is the existing suite in [`src/main.ts`](src/m | case | moq-wasm | moq-ffi, UniFFI | slice, UniFFI and BoltFFI | |---|---|---|---| -| negotiates each relay's version | yes, via `version()` | yes, by offering only that version: no negotiated-version accessor | same as moq-ffi | +| negotiates each relay's version | yes, via `version()` | yes, by offering only that version (the spike predates `MoqConnectionStats.version`, [#5723](https://github.com/moq-dev/moq/pull/5723)) | same as moq-ffi | | reads a published broadcast, every byte, 128 KiB frames | yes | yes | yes | | refuses a missing track | yes | yes: rejects with `NotFound` (transport-19) or `Protocol` (lite) | yes: rejects with the slice's `Net { reason: "not found" }` | | publishes | no: consume only | yes | yes |