diff --git a/quest/m1/README.md b/quest/m1/README.md index 94972b1a360..5c14bbdb4f9 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -124,7 +124,6 @@ lite-07 stream type here. - [Artifact size audit](/quest/m1/audit-size.md) - binary, FFI, WASM, and bundle growth since the m0 run is explained, fixed, or planned - [Compile time audit](/quest/m1/audit-compile-time.md) - build-time hotspots are measured against the m0 baselines and the worst are fixed or planned - [Performance audit](/quest/m1/audit-perf.md) - benchmarks that regressed since the m0 run are explained, fixed, or planned, and unbenched hot paths get coverage -- [Quest tree audit](/quest/m1/audit-quests.md) - the tree agrees with itself and with main ## Related diff --git a/quest/m1/audit-quests.md b/quest/m1/audit-quests.md deleted file mode 100644 index 9156e7567ab..00000000000 --- a/quest/m1/audit-quests.md +++ /dev/null @@ -1,46 +0,0 @@ -# [M] Quest tree audit - -## Goal - -The quest tree agrees with itself and with `main`: done, stale, -conflicting, and misranked quests are fixed. - -## Plan - -Recurs once per major release (decided 2026-10-19). The PR that finishes -this run also adds the next one with the same file name at the end of the next -milestone's `Required` (m0 to m1, m1 to m2). The successor keeps the Goal -and this paragraph; the rest of its Plan is rewritten with what this run -learned: baselines, results, and what to check first. A successor placed in m2 -also lists the [release cut](/quest/m2/release/cut.md) under `Required`, so it -waits for the release in flight to ship. Only `/quest-delete` ends the -recurrence. Fixes land in the run's PR, one commit each, rather than as follow-ups. -Only a change that needs a maintainer decision (public API, scope) or is -independently landable and too large to review alongside the rest becomes a -follow-up through `/quest-plan`. - -Run `/quest-audit`. After a release cut shifts the milestones, also check -that the move left no broken links or misplaced quests. Earlier runs: ad hoc -2026-09-30, 10-05, 10-08, 10-10; recurring 2026-10-19 and 10-20. - -Checkpoint, 2026-10-20, against `main` at `96d6b5bd4`: - -- Read all 426 documents and the 22 questline branches on origin with nine - parallel auditors, together with the moq.pro tree, since many of its quests - wait on ours. `quest check` was clean, so every finding was content. -- Settled the four conflicts the 10-19 run left, plus about 20 more with the - maintainer: e2ee publishes through a moq-net wrapper trait - ([net-wrap](/quest/m2/net-wrap/README.md)); m1 holds everything before the - cut, breaking or not; C halves wait on the generated package; the timeline - is `.hls` with `compress: true`; the publisher priority is the send - order tiebreak; an auth handle backs one live session; GroupState storage - is benchmarked before either redesign. -- Retired landed work whose PRs left the quest behind: goaway coverage - (#5998), the JS dead-route error (#5939), the uring stream header (#5690), - and the catalog-reader smoke. Deleted 29 merged questline branches. -- Most common findings, so check these first next run: ranks inside a - milestone README that put a quest above its own prerequisites; "after - #N" or "held until #N" wording after #N merged; questline branches on - origin whose directory is gone from `main`; and plans built on a design - another quest has since replaced (SUBSCRIBE_ALL, the e2ee bridge, the - per-PR CI model before #6038). diff --git a/quest/m1/audit-size.md b/quest/m1/audit-size.md index 9f1e4f1f07a..7d916912263 100644 --- a/quest/m1/audit-size.md +++ b/quest/m1/audit-size.md @@ -25,9 +25,11 @@ the quests below. The run finishes after before the breaking cut sees its result and the rest of m1. What to check first: whether the nightly `sizes` job (`sh/size/`) has run. -It needs the Linux release builds, which still fail to link -([moq-dev/moq#6090](https://github.com/moq-dev/moq/pull/6090) was open on -2026-10-21). If it has, its history replaces the local method below. Then +The Linux release-link fix +[moq-dev/moq#6090](https://github.com/moq-dev/moq/pull/6090) merged on +2026-10-22 UTC; verify the first scheduled Nightly after it before treating +the sizes history as available. Once it runs, its history replaces the local +method below. Then re-attribute the native rows for the erasure quest, and measure `@moq/net` with the track compression codec in `js/net`. diff --git a/quest/m1/c/README.md b/quest/m1/c/README.md index 4fff85ea948..a466cd6f0ba 100644 --- a/quest/m1/c/README.md +++ b/quest/m1/c/README.md @@ -53,9 +53,13 @@ That change owns its C tests and `MIGRATE.md` entries; other API reshaping stays Decided 2026-10-20 (maintainer): m1 quests that change the C API ([exact binding timestamps](/quest/m1/binding-timestamps.md), [scope track priority](/quest/m1/track-priority-scope.md), -[Rust identity enforcement](/quest/m1/catalog-identity-rs.md), and -[dynamic subscribe ranges](/quest/m1/subscribe-ranges/dynamic.md)) Require this +and [Rust identity enforcement](/quest/m1/catalog-identity-rs.md)) Require this line and land their C half on the generated package, so C users break once. +[Dynamic subscribe ranges](/quest/m1/subscribe-ranges/dynamic.md) is the +settled exception from its later plan in +[moq-dev/moq#6123](https://github.com/moq-dev/moq/pull/6123): if generation +has not landed, the frozen C crate splits fills into its existing per-group +requests internally and keeps its ABI, so that quest does not wait here. ## Required diff --git a/quest/m1/lazy-discovery/README.md b/quest/m1/lazy-discovery/README.md index 5caa447d073..ebdc00f7849 100644 --- a/quest/m1/lazy-discovery/README.md +++ b/quest/m1/lazy-discovery/README.md @@ -30,8 +30,11 @@ Shared rules for the children: - A pattern watch requests its literal head (`room/*/chat` watches `room/`; `**` watches the root), the rule `interests()` uses today; the origin filters locally. -- When the last watcher of a prefix leaves, its request lingers for the - connection's existing `linger` (default 2s) before closing. No new option. +- When the last watcher of a prefix leaves, its request lingers for a fixed + 2s before closing, matching `LINGER` in `js/net/src/connection/forward.ts` + and the Rust child's plan. This discovery linger is separate from the + configurable shared-connection linger; one-shot sessions have no such + option. No new option. - A plain JS `request(path)` stays blind: it opens no announce request and subscribes at once. Rust has no blind requests or answers (decided 2026-10-20, recorded in [the Rust child](/quest/m1/lazy-discovery/rust.md)). diff --git a/quest/m1/test-flakes-2/README.md b/quest/m1/test-flakes-2/README.md index b270c59b001..49eb823a56f 100644 --- a/quest/m1/test-flakes-2/README.md +++ b/quest/m1/test-flakes-2/README.md @@ -47,7 +47,7 @@ Public API: none. Wire: none. ## Required -- [OBS drain and JS allocation flakes](/quest/m1/test-flakes-2/three-flakes.md) - reproduce the OBS stop-drain failure and verify the existing RSS replacement under load +- [OBS drain under load](/quest/m1/test-flakes-2/three-flakes.md) - verify the existing close-tail fix against the reproduced OBS stop-drain failure; the merged JS allocation replacement passed under load ## Related diff --git a/quest/m1/test-flakes-2/three-flakes.md b/quest/m1/test-flakes-2/three-flakes.md index e9349a6cea6..781f050eff1 100644 --- a/quest/m1/test-flakes-2/three-flakes.md +++ b/quest/m1/test-flakes-2/three-flakes.md @@ -1,28 +1,33 @@ -# [XS] OBS drain and JS allocation flakes +# [XS] OBS drain holds up under load ## Goal -Each passes reliably under a loaded `just check`, fixed at its cause: - -- OBS "stop drains the session" (`cpp/obs/test/moq-output-test.cpp`, a - 16 MiB frame under TSan), seen in - [moq-dev/moq#6131](https://github.com/moq-dev/moq/pull/6131) and - [moq-dev/moq#6137](https://github.com/moq-dev/moq/pull/6137). -- The js/net RSS memory test, which flakes under load - ([moq-dev/moq#6128](https://github.com/moq-dev/moq/pull/6128)). +OBS "stop drains the session" (`cpp/obs/test/moq-output-test.cpp`, a +16 MiB frame under TSan) passes reliably under a loaded `just check`, fixed +at its cause. Seen in +[moq-dev/moq#6131](https://github.com/moq-dev/moq/pull/6131) and +[moq-dev/moq#6137](https://github.com/moq-dev/moq/pull/6137). ## Plan Reproduce before fixing, with no retries, sleeps, or raised timeouts. -The unchanged OBS suite passed both a full TSan run and an output-only TSan -run pinned to one CPU on 2026-10-21. Its artificial 16 MiB frame competes -with the session's intentional one-second drain deadline, but a local -failure has not yet established the right regression. Keep the lifecycle -assertions when separating that contract from throughput. - -[moq-dev/moq#6188](https://github.com/moq-dev/moq/pull/6188) owns the RSS -replacement: bounded algorithm assertions rather than process RSS. Do not -duplicate it; verify its merged result under load. +On 2026-10-22 UTC, the unchanged full OBS TSan suite on main +`e0cde150d75fe6c00e18efcbfea773e3770f1a5d` failed the `ended` and final +timestamp assertions (`moq-output-test.cpp:665-666`) at natural load 35-42 +on 24 CPUs. A temporary clean merge of +[moq-dev/moq#5762](https://github.com/moq-dev/moq/pull/5762), head +`f2e52db684f7c2cca6162bd417819820297815b5`, made the unchanged full suite +pass. Baseline repeats also passed: this covers a reproduced failure, +not proof that every historical flake has the same cause. That PR owns the +close-tail drain fix; verify its merged result under load before closing +this quest. Keep the lifecycle assertions rather than weakening them around +throughput. `just obs test` is the repository entry point; exact original +shell invocations were not retained. + +The JS obligation is complete: the loaded js/net suite passed all 2,493 +tests, including the bounded Path assertions merged in +[moq-dev/moq#6188](https://github.com/moq-dev/moq/pull/6188). No RSS-based +assertion remains to replace here. The original audio-quality RTT and fresh-worktree interop conditions are implemented: the sampler observes PROBE while sampling, and the interop diff --git a/quest/m2/README.md b/quest/m2/README.md index 07d03d5ac0c..e57782b25aa 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -202,3 +202,5 @@ ranked just below deterministic TS legs, which it requires. - [Test coverage audit](/quest/m2/audit-test-coverage.md) - repeat the coverage audit against the m1 baselines after the next release ships - [Documentation audit](/quest/m2/audit-docs.md) - repeat the docs audit after the release ships, against the m1 baselines - [Test cost audit](/quest/m2/audit-test-cost.md) - the slowest, flakiest, and least valuable tests are fixed, deleted, or planned once the release ships + +- [Quest tree audit](/quest/m2/audit-quests.md) - repeat the whole-tree audit after the release ships, against the m1 baseline diff --git a/quest/m2/audit-docs.md b/quest/m2/audit-docs.md index eb79cf76ac0..dfe13580b3c 100644 --- a/quest/m2/audit-docs.md +++ b/quest/m2/audit-docs.md @@ -62,8 +62,9 @@ freshest. Baselines: property `doc/bin/gstreamer.md` names. - Cross-Package Sync: walked from `9b90cdd569` through `7d2a91fe66`. Walk the next run from there. Go has no `Client` failure accessor because `Dial` - returns only once connected; the maintainer chose to leave that until a Go - caller needs it, so it is not a gap. + returns only once connected. The newer 2026-10-21 maintainer decision + plans that gap in [Go first-dial failure](/quest/m2/go-first-dial-failure.md); + verify its accessor and the Kotlin/Dart wording when that quest lands. ## Required diff --git a/quest/m2/audit-quests.md b/quest/m2/audit-quests.md new file mode 100644 index 00000000000..0781b510253 --- /dev/null +++ b/quest/m2/audit-quests.md @@ -0,0 +1,73 @@ +# [M] Quest tree audit + +## Goal + +The quest tree agrees with itself and with `main`: done, stale, +conflicting, and misranked quests are fixed. + +## Plan + +Recurs once per major release (decided 2026-10-19). The PR that finishes +this run also adds the next one with the same file name at the end of the next +milestone's `Required` (m0 to m1, m1 to m2). The successor keeps the Goal +and this paragraph; the rest of its Plan is rewritten with what this run +learned: baselines, results, and what to check first. A successor placed in m2 +also lists the [release cut](/quest/m2/release/cut.md) under `Required`, so it +waits for the release in flight to ship. Only `/quest-delete` ends the +recurrence. Fixes land in the run's PR, one commit each, rather than as follow-ups. +Only a change that needs a maintainer decision (public API, scope) or is +independently landable and too large to review alongside the rest becomes a +follow-up through `/quest-plan`. + +Run `/quest-audit` after the release cut. Read every outstanding quest with +parallel auditors, then verify source claims, active PR ownership, Required +ordering, and the latest maintainer decisions before changing plans. + +Baseline from the m1 run, 2026-10-22 UTC, against `main` at `bce217e063`: + +- Read all 463 quest documents across m0-m3 and the root with parallel + read-only support. Checked 315 referenced GitHub items and the open-PR + inventory. Source checks were targeted to the factual claims; hardware + and deployment acceptance was not inferred from old inventory text. +- Fixed timestamp provenance's rank before its IETF passthrough consumer, + the generated-C exception for dynamic range fills, discovery's fixed 2s + linger, and replacement linger's existing-reader semantics. +- Carried m1's settled compression migration into deferred plans: one + compressed catalog/stats track, ordinary tracks for opaque bytes, no + moq-flate or `moq-mux::binary` helper, authenticated logical compression + in the e2ee wrapper, and bounded prefix reconstruction for front eviction. +- Refreshed partly landed benchmark/report baselines and explicit + prerequisites for the JS encrypted-wrapper mirror and fMP4 ambisonics. +- The JS allocation replacement passed all 2,493 js/net tests under load. + The OBS drain failure reproduced on unchanged main and passed with the + existing close-tail PR; its quest keeps the remaining merged-result proof. +- No m2 implementation quest was started, no external-organization report + was posted, and ambiguous remote claim branches were left intact. + +Check first next run: + +- A moved quest can still be owned by a PR under its old branch name. The + redundant failover quest moved to m0 while + [moq-dev/moq#6113](https://github.com/moq-dev/moq/pull/6113) retained its + m1 branch. Search PR titles, bodies, and source scope as well as exact + branch names before taking a claim. Do not infer abandonment from age. +- Refresh all linked open PRs before changing ownership or deleting a + quest. At this baseline, the TRACK_STATUS retirement, silent-peer + retirement, audio conformance, CI audit, and local gate each had owners; + an overlapping cleanup should finish through that PR. +- Confirm the first scheduled size report after the Linux release-link + fix, the required count of post-change audio-budget nights, shared FFI + publication, and release-gate availability. Partial evidence does not + clear an external-condition quest. Safari WebKit bug 319818 was still + NEW with no fixed shipping version established. +- Recheck local gate and binding-cost plans together: Bun `--no-orphans` + reaps newly spawned local descendants even after successful completion, + while the CI bypass preserves persistent queue daemons. A warm local + daemon policy needs an explicit choice; no dependency edge was invented. +- Re-run the transitive Required rank check, including prerequisites added + within an epic, and compare plans against replaced designs before looking + for new implementation work. + +## Required + +- [Release cut](/quest/m2/release/cut.md) - the release in flight ships before this run starts diff --git a/quest/m2/audit-test-cost.md b/quest/m2/audit-test-cost.md index 7c04af09962..1c8c6beb698 100644 --- a/quest/m2/audit-test-cost.md +++ b/quest/m2/audit-test-cost.md @@ -56,19 +56,22 @@ Check first: 105 to 113 s at 8 threads (about 185% CPU), 60 s at 16 (315%), 47 s at 24 (420%), and 41 s at 32 (500%): the suite needs about 200 CPU-seconds, and most slots wait on sockets, subprocesses, and wall-clock timeouts. - Oversubscribing the queue job is a maintainer decision, since it loads - every timing-sensitive test and a flake ejects a queue entry. Only the - known redundant-importer flake failed, once, at 16 threads. -- moq-gst: about ten tests per run each pay 3 s, at random. `stop` closes the - client, which waits out the draining period (three PTOs at the 333 ms - initial RTT) of a dial to the tests' unreachable relay that never got an - answer. A user stopping a pipeline whose relay is down waits the same. Ask - whether moq-quic may skip draining for a connection that never heard from - its peer. + The maintainer selected 24 threads for the queue in + [CI housekeeping](/quest/m1/ci-housekeeping.md), which owns the loaded + proof before applying it. Only the known redundant-importer flake failed, + once, at 16 threads in this baseline. +- moq-gst's unanswered-dial close wait was fixed by + [moq-dev/moq#6201](https://github.com/moq-dev/moq/pull/6201): the close + stops counting an unanswered handshake as active immediately while the + closing period still answers late packets. Do not repeat the old request + to skip draining. [moq-dev/moq#6240](https://github.com/moq-dev/moq/pull/6240) + proposes retiring the silent-peer quest as complete. - moq-uring: three endpoint tests wait out moq-quic's fixed 10 s handshake idle timeout (30 s together). Neither moq-uring's `Transport` nor - `--quic-idle-timeout` sets it; ask whether the configured idle timeout - should bound the handshake too (public API). + `--quic-idle-timeout` sets it. #6201 does not change that timeout. The + [retirement proposal](https://github.com/moq-dev/moq/pull/6240) records + keeping it separate with no new knob; follow its maintainer decision + rather than independently selecting another API in a cost audit. - CPU-bound simulations in a debug build: five TS export timing cases (3 to 11 s each) and the jitter buffer's day of drift (6 to 13 s), whose `Steer` rebuilds the hull and median over its whole window on every step. diff --git a/quest/m2/bench-sources.md b/quest/m2/bench-sources.md index 414e66dac24..466dbd0bddd 100644 --- a/quest/m2/bench-sources.md +++ b/quest/m2/bench-sources.md @@ -14,9 +14,10 @@ benchmark's JSON and the "Rust benchmark tests", "Rust bench targets" and "JS benchmarks" nightly jobs, converted to the history input format where they don't already emit one. -- Most Rust Criterion targets run with `-- --test`, which measures nothing. - Switch the charted targets to a measuring mode (or add a measurement pass), - weighing the added nightly runtime. +- Criterion targets now measure through `just gh criterion` in + `sh/gh/nightly.sh` (`rust-bench`, `rust-extra`, `rust-uring`), and the + comparison harness uses quick mode. Check their published histories + rather than converting them again; the unreported sources below remain. - The "Rust benchmark tests" job is not recorded yet: its nextest benchmarks print no structured measurements. - Check each JS bench reports a measurement before recording it. diff --git a/quest/m2/carla-bridge.md b/quest/m2/carla-bridge.md index 87d55eaff81..e40d3255027 100644 --- a/quest/m2/carla-bridge.md +++ b/quest/m2/carla-bridge.md @@ -59,4 +59,4 @@ probe opens the camera's own backend with a CPU picture. ## Related -- [GPU CI](/quest/m2/gpu-ci.md) - runs the NVIDIA half nightly +- [GPU CI](/quest/m2/gpu-ci.md) - gates NVIDIA correctness on hardware in the merge queue diff --git a/quest/m2/e2ee/README.md b/quest/m2/e2ee/README.md index 656365acc0f..25b8bcecb71 100644 --- a/quest/m2/e2ee/README.md +++ b/quest/m2/e2ee/README.md @@ -35,7 +35,7 @@ The Rust and TypeScript cores expose the same surface, and nothing else: - A core produces only under an epoch it minted itself (decided 2026-10-08). Only `credential.produce()` mints a producing generation, and it takes no epoch: it mints a fresh UUIDv7 and returns a `generation::Producer` owning `epoch()` for the route and `name(semantic)` for opaque track names. `credential.consume(epoch)` binds a discovered epoch as a consume-only `generation::Consumer` with `name(semantic)`. The two are separate types, so producing under a discovered or shared epoch does not compile (names decided 2026-10-11 in [#5313](https://github.com/moq-dev/moq/pull/5313)). Clones of a producing generation share publisher claims so reopening a track cannot reset its nonce counters. - Applications only handle semantic track names (maintainer, 2026-10-17). `broadcast::Producer` wraps a `moq-net` broadcast under a producing generation and `broadcast::Consumer` wraps one under a consuming generation; each derives the physical name, so only the CDN sees physical names. `generation` no longer opens tracks itself. The broadcast wrappers merged in [#5876](https://github.com/moq-dev/moq/pull/5876). - The wrappers implement the [moq-net traits](/quest/m2/net-wrap/README.md) at the broadcast, track, group, and frame levels, datagrams included (decided 2026-10-20, maintainer, because one encrypted broadcast then works with every writer and reader). moq-mux, moq-json, hang, and the CLI publish and consume an encrypted broadcast unchanged, under semantic names, and every AEAD call still has the canonical physical name and transport identity. The e2ee mux bridge ([#5822](https://github.com/moq-dev/moq/pull/5822)) is closed and superseded. -- Errors are the draft's typed codes plus the transport's. Nothing catalog-, hang-, or MSF-shaped lives here: a catalog is a track under a derived name, and compression is the catalog owner's job. +- Errors are the draft's typed codes plus the transport's. Nothing catalog-, hang-, or MSF-shaped lives here: a catalog is a track under a derived name. The catalog owner sets logical `track::Info.compress`; the [e2ee wrapper](/quest/m2/net-wrap/e2ee.md) compresses before AEAD and authenticates the logical compression metadata. - Stateless `seal`/`open` primitives with caller-chosen identities, HKDF labels and info builders, raw key bytes, and process-global claims are not public. The vectors are tested inside each core. ### Application and platform shape diff --git a/quest/m2/e2ee/rust-publish.md b/quest/m2/e2ee/rust-publish.md index 3c8e7581b28..e0ac5e3fadd 100644 --- a/quest/m2/e2ee/rust-publish.md +++ b/quest/m2/e2ee/rust-publish.md @@ -27,9 +27,11 @@ in advance, so it does not wait on the - Catalog naming: derive the protected catalog name from its well-known logical role, then put media roles, codecs, quality, timelines, and custom-track mappings only inside the encrypted catalog. -- Encrypt both Hang catalog representations and encrypt or suppress the MSF - catalog. Compress protected catalog bodies before encryption and retain - ordinary plaintext publication unchanged outside E2EE mode. +- Encrypt the single Hang `catalog.json` left by the + [m1 compression migration](/quest/m1/compress/migrate.md), and encrypt or + suppress the MSF catalog. Set logical `compress` on protected catalog + tracks; the [e2ee wrapper](/quest/m2/net-wrap/e2ee.md) compresses before + encryption. Retain ordinary plaintext publication unchanged outside E2EE mode. - Cover every current Rust importer and capture path so a convenience API cannot emit a plaintext semantic catalog. - Refuse a re-created track (decided 2026-10-17, maintainer): moq-e2ee diff --git a/quest/m2/ffi-bytes.md b/quest/m2/ffi-bytes.md index 0c2629c4452..971d12eac46 100644 --- a/quest/m2/ffi-bytes.md +++ b/quest/m2/ffi-bytes.md @@ -31,7 +31,9 @@ Decided with the maintainer on 2026-10-13: #2946 already removed the per-byte copy on the Python side. - **`&[u8]` arguments only if the numbers say so.** UniFFI 0.32 makes `&[u8]` arguments zero-copy, but only for sync calls that take bytes - directly: flate `update`/`append` and the three `write(payload)` methods. + directly, such as the `write(payload)` methods. The + [m1 compression migration](/quest/m1/compress/migrate.md) deletes the FFI + flate namespace, so its `update`/`append` calls are no longer candidates. It cannot be used in records, async calls, or callback interfaces. Adopting it means fixing the Go and C++/C generators (both lower to `RustBuffer` where the declaration expects `ForeignBytes`, so they would not compile) diff --git a/quest/m2/keyed-prefix-polling.md b/quest/m2/keyed-prefix-polling.md index b9cea725a43..cb5a3f61455 100644 --- a/quest/m2/keyed-prefix-polling.md +++ b/quest/m2/keyed-prefix-polling.md @@ -11,8 +11,9 @@ prefixes. Or a benchmark shows the cost is flat and this quest is deleted. From [moq-dev/moq#6165](https://github.com/moq-dev/moq/pull/6165). Decided 2026-10-21 with the maintainer: gated on a measurement. -- First add or extend a bench (`rs/moq-net/benches/interests.rs` is the - nearest) that sweeps open prefixes per session against wakes. If the +- First add a prefix-machine bench or extend + `rs/moq-net/benches/session.rs`, sweeping open prefixes per session + against wakes. If the per-wake cost does not grow with the prefix table, close the quest with the numbers. - Otherwise key polling by prefix and show the slope flatten. diff --git a/quest/m2/mux-vr-fields.md b/quest/m2/mux-vr-fields.md index 84cfaaf65ca..296ec358771 100644 --- a/quest/m2/mux-vr-fields.md +++ b/quest/m2/mux-vr-fields.md @@ -49,7 +49,10 @@ with non-diegetic stereo, and a malformed one are refused. Public API: none beyond the catalog fields #5543 adds. Wire: none. +## Required + +- [CMAF surround Opus](/quest/m2/cmaf-opus-surround.md) - the `dOps` mapping table an ambisonic fMP4 track needs + ## Related - [WebXR playback](/quest/m3/watch-webxr.md) - `` renders these fields -- [CMAF surround Opus](/quest/m2/cmaf-opus-surround.md) - the `dOps` mapping table an ambisonic fMP4 track needs diff --git a/quest/m2/net-wrap/README.md b/quest/m2/net-wrap/README.md index a96b8941d86..b28d4afecbc 100644 --- a/quest/m2/net-wrap/README.md +++ b/quest/m2/net-wrap/README.md @@ -69,7 +69,7 @@ above. - [moq-net traits](/quest/m2/net-wrap/traits.md) - moq-net exports producer and consumer traits at every level, implemented by its own types - [moq-e2ee implements the traits](/quest/m2/net-wrap/e2ee.md) - the e2ee broadcast, track, and group wrappers implement the traits, proving them before the adopters land - [moq-json, moq-stats, and hang take the traits](/quest/m2/net-wrap/json.md) - json snapshots, streams, windows, the stats producer, and hang's tracks write and read through the traits -- [moq-mux takes the traits](/quest/m2/net-wrap/mux.md) - importers, catalog, container, timeline, json and binary tracks, `Source`, TS export, and the moq-video and moq-audio encoders are generic over the traits +- [moq-mux takes the traits](/quest/m2/net-wrap/mux.md) - importers, catalog, container, timeline, json tracks, `Source`, TS export, and the moq-video and moq-audio encoders are generic over the traits - [CLI paths take the traits](/quest/m2/net-wrap/cli.md) - the CLI's publish and play paths hand moq-mux any broadcast that implements them - [JS mirror](/quest/m2/net-wrap/js.md) - `@moq/net` exports the same interfaces, taken by `@moq/hang`, `@moq/publish`, and `@moq/watch`, and implemented by `@moq/e2ee` diff --git a/quest/m2/net-wrap/js.md b/quest/m2/net-wrap/js.md index ee020adc72d..f256a2d09d3 100644 --- a/quest/m2/net-wrap/js.md +++ b/quest/m2/net-wrap/js.md @@ -34,3 +34,5 @@ Wire: the `draft-lcurley-moq-e2ee.md` compress flag from ## Required - [moq-net traits](/quest/m2/net-wrap/traits.md) - the names and methods this mirrors + +- [moq-e2ee implements the traits](/quest/m2/net-wrap/e2ee.md) - owns the authenticated logical compression encoding this mirrors diff --git a/quest/m2/net-wrap/mux.md b/quest/m2/net-wrap/mux.md index 5028ee22b59..6a6b0e3ce1d 100644 --- a/quest/m2/net-wrap/mux.md +++ b/quest/m2/net-wrap/mux.md @@ -5,7 +5,7 @@ moq-mux writes and reads through the [moq-net traits](/quest/m2/net-wrap/traits.md), defaulting to moq-net's types: the importers, catalog, container producers and consumers, timeline, -json and binary tracks, `Source`, and TS export. The moq-video and moq-audio +json tracks, `Source`, and TS export. The moq-video and moq-audio encode producers built on moq-mux take them too. Handed an encrypted broadcast, every importer and capture encoder publishes it, and every exporter reads one, without knowing. @@ -14,9 +14,12 @@ exporter reads one, without knowing. - Entry points include `container::Producer::new(track::Producer)`, the importers' `broadcast::Producer` (`create_track` call sites throughout - `import/`), `catalog/`, `timeline.rs`, `json.rs`, `binary.rs`, + `import/`), `catalog/`, `timeline.rs`, `json.rs`, `source.rs`, and the TS exporter under `container/ts`. About 250 type references across these modules. +- The [m1 compression migration](/quest/m1/compress/migrate.md) deletes + `moq-mux::binary`; opaque bytes use plain tracks, so there is no binary + helper to convert here. - Capture: `moq_video::encode::Producer::new` takes a concrete `moq_net::broadcast::Producer` and `moq_audio::encode::Producer::new` a `&mut` one (`rs/moq-video/src/encode/producer.rs`, diff --git a/quest/m2/perf/uring-quiescence.md b/quest/m2/perf/uring-quiescence.md index 2b9fe9bdf5e..a4692956ad1 100644 --- a/quest/m2/perf/uring-quiescence.md +++ b/quest/m2/perf/uring-quiescence.md @@ -44,5 +44,9 @@ must not starve the socket. Acceptance: turns and enters per received datagram on the chat shape (request-reply is the worst case), CPU per Gbps and p99 latency on the fanout -shape, via `just bench BASE` on Linux. The existing starvation test keeps its -meaning with a budget of 1 and gains a sibling proving the budget bound. +shape, on Linux with the io_uring workers at both base and current. Use +`just bench-runtime` at each revision with the same worker count, or extend +the existing harness to compare those io_uring runs: `just bench BASE` uses +the default Tokio runtime and cannot prove this change. The existing +starvation test keeps its meaning with a budget of 1 and gains a sibling +proving the budget bound. diff --git a/quest/m2/release/migrate-audit.md b/quest/m2/release/migrate-audit.md index b2eef6250d8..3c0e33cf0bc 100644 --- a/quest/m2/release/migrate-audit.md +++ b/quest/m2/release/migrate-audit.md @@ -39,9 +39,12 @@ Decided 2026-10-16 (maintainer interview): checks are out of scope until a missed break shows they are needed. - For this cut, fill every gap the report and the manual pass show in the matching `MIGRATE.md`. Known gaps: breaking releases cut after the - 2026-09-23 train have no transition section yet (moq-json 0.4 -> 0.5, - moq-flate 0.1 -> 0.2, and possibly moq-audio and moq-video), because their - breaks predate the backfill's merge base. + 2026-09-23 train have no transition section yet (moq-json 0.4 -> 0.5 + and possibly moq-audio and moq-video), because their breaks predate the + backfill's merge base. The [compression migration](/quest/m1/compress/migrate.md) + deletes moq-flate before this cut: audit the migration from its published + API to ordinary tracks with `compress`, rather than promising a new + moq-flate transition release. - Compile-check the code in every `MIGRATE.md` section the cut ships against the candidate. Nothing else builds it. - Required by the cut, after m1's breaking work has landed. diff --git a/quest/m2/stats/README.md b/quest/m2/stats/README.md index f3fb1b3b6fa..b018002765c 100644 --- a/quest/m2/stats/README.md +++ b/quest/m2/stats/README.md @@ -85,8 +85,9 @@ kind. browser has only PROBE rtt until [#2733](https://github.com/moq-dev/moq/issues/2733)-style counters land. - **Encoding**: cumulative counters about once a second through - `moq_json::snapshot`, with the `.z` merge-patch sibling, produced whenever - stats are enabled. An unsubscribed stats track never leaves the process. + `moq_json::snapshot` on one track with `compress: true`, produced whenever + stats are enabled. The [m1 compression migration](/quest/m1/compress/migrate.md) + removes `.z` siblings; follow the delta policy it retains on the single track. An unsubscribed stats track never leaves the process. Gauges are carried but never summed. - **On main.** Every change is additive: optional sections on `#[non_exhaustive]` catalog types, and new types. The line left the diff --git a/quest/m2/stats/js.md b/quest/m2/stats/js.md index d64cd020dd7..a9ba86c21d0 100644 --- a/quest/m2/stats/js.md +++ b/quest/m2/stats/js.md @@ -12,8 +12,9 @@ echo path of a catalog soliciting feedback. Both use the `@moq/hang` schemas. - The encoder `Stats` signals are already per rendition (`frames`, `bytes`, `keyframes`). Add drops and the target bitrate. - Fold them into the stats snapshot keyed by rendition ID, and write it - through the `moq-json` snapshot producer with its `.z` sibling. A `stats` - attribute enables it. + through the `@moq/json` snapshot producer on one track with + `compress: true`, matching the [m1 compression migration](/quest/m1/compress/migrate.md). + A `stats` attribute enables it. - `transport` carries PROBE rtt only, because `WebTransport.getStats()` returns nothing useful in Chromium or Firefox today. - `js/watch`: diff --git a/quest/m2/unbounded-groups/README.md b/quest/m2/unbounded-groups/README.md index 1086db9fd01..82945721aa5 100644 --- a/quest/m2/unbounded-groups/README.md +++ b/quest/m2/unbounded-groups/README.md @@ -66,8 +66,9 @@ Decided 2026-10-16 (maintainer interview): not lite-07. Frame-boundary holes already refill over lite-07's frame-precise ranges. - JS is a separate quest. Docs change inline: the lite draft, `doc/concept`, - the relay cache docs, the json/flate docs, and the e2ee draft's 32 MiB - interop cap. There is no new page. + the relay cache docs, the JSON and moq-net compression docs, and the e2ee + draft's 32 MiB interop cap. The + [m1 compression migration](/quest/m1/compress/migrate.md) deletes the flate packages. There is no new page. The refill API is the [Dynamic range requests](/quest/m1/subscribe-ranges/dynamic.md) diff --git a/quest/m2/unbounded-groups/front-eviction.md b/quest/m2/unbounded-groups/front-eviction.md index 803cbb5b0e8..48249a15988 100644 --- a/quest/m2/unbounded-groups/front-eviction.md +++ b/quest/m2/unbounded-groups/front-eviction.md @@ -40,8 +40,18 @@ See the [epic](/quest/m2/unbounded-groups/README.md) for the decisions. moq-transport, a hole that covers whole objects refills; one inside an object is `Evicted`. - Downstream encoders that roll groups by the removed constants (moq-json, - moq-flate, moq-mux TS, moq-stats) keep their own local roll triggers if - they still need one. + moq-mux TS, moq-stats) keep their own local roll triggers if they still + need one. The [m1 compression migration](/quest/m1/compress/migrate.md) + deletes moq-flate; recheck the surviving JSON stream budget and track + compression paths instead of retaining a deleted helper's cap. +- Compressed groups keep the existing prefix-before-inflate contract + ([compressed tracks](/quest/m1/compress/README.md)). Today + `GroupState::inflate` refuses a nonzero cached offset. Front eviction must + refill the needed compressed prefix before inflation or retain equivalent + decoder state, with compressed storage, the shared inflated copy, and + codec state all bounded by the pool. Never pin a whole growing prefix to + make a late plain reader work. Test a long compressed group through a + small pool with a late plain reader and legacy-wire egress. - Benchmarks: keep `group.rs` flat. Add a case swept over frames held and runs evicted, and one over concurrent readers refilling a hole. diff --git a/quest/m2/unbounded-groups/js.md b/quest/m2/unbounded-groups/js.md index 5ff6e690844..56a6deb7d5b 100644 --- a/quest/m2/unbounded-groups/js.md +++ b/quest/m2/unbounded-groups/js.md @@ -23,8 +23,9 @@ See the [epic](/quest/m2/unbounded-groups/README.md) for the decisions. stays near one window, and a reader that falls behind gets refill or `Evicted`. - Mirror the Rust names for the streaming frame read. -- Update `js/json`, `js/flate`, and their tests, which lean on the removed - constants. +- Update `js/json` and its tests, which lean on the removed constants, and + the compression paths now in `js/net`. The + [m1 compression migration](/quest/m1/compress/migrate.md) deletes `js/flate`. - If [Rust-backed @moq/net](/quest/m2/rs2ts/README.md) is adopted first, this shrinks to exposing the streaming read. diff --git a/quest/m3/ladder/fetch.md b/quest/m3/ladder/fetch.md index 2e14f7d5f88..36a1faf8b0e 100644 --- a/quest/m3/ladder/fetch.md +++ b/quest/m3/ladder/fetch.md @@ -19,9 +19,11 @@ still burns full-rate encodes on demand. Make it read the controller's applied target and participate in the same allocation. A disabled rung stays manually fetchable, and cache hits are untouched. -Catalog mutations publish full HANG, HANGZ, and MSF snapshots today -(`rs/moq-mux/src/catalog/producer.rs`). Coalesce every rung state -change from one controller iteration into a single publication, and make a +Catalog mutations publish full snapshots +(`rs/moq-mux/src/catalog/producer.rs`). The +[compression migration](/quest/m1/compress/migrate.md) removes the HANGZ +sibling before this quest; coalesce every rung state change from one +controller iteration into a single publication of each supported catalog, and make a later source catalog snapshot compose with current generated-rung state rather than overwrite it. diff --git a/quest/m3/safari-webtransport.md b/quest/m3/safari-webtransport.md index b8fb1a63fa9..131d88a2765 100644 --- a/quest/m3/safari-webtransport.md +++ b/quest/m3/safari-webtransport.md @@ -13,7 +13,9 @@ this. - Name the exact Safari and iOS or iPadOS releases that ship the fix in the quest and in the `browser.ts` comment, then gate on them for Safari and for the iOS WebKit browsers, keeping older versions on the fallback. As of - 2026-09-30 the bug is still NEW with no fix released. + 2026-10-22 UTC, [WebKit bug 319818](https://bugs.webkit.org/show_bug.cgi?id=319818) + is still NEW with no resolution; its 2026-10-18 comment reproduces the + failure on a newer Safari. No fixed shipping version is established. - Before flipping, rerun the raw WebTransport reproduction from #2388 (about 7,600 eleven-byte unidirectional streams, and about 16 MiB of data) on the fixed Safari, then a watch longer than two minutes in the QA harness on diff --git a/quest/m3/teleop-mavlink.md b/quest/m3/teleop-mavlink.md index 1ba75a4346f..ce0a1be51f0 100644 --- a/quest/m3/teleop-mavlink.md +++ b/quest/m3/teleop-mavlink.md @@ -47,9 +47,8 @@ because the newest group wins regardless of which message it holds. Putting them all in one long-lived group has the opposite failure: nothing can be skipped and head-of-line blocking is back. -So the lossy class is a latest-value snapshot of opaque bytes: -`moq_flate::snapshot`, with the raw -frame as the value. Every update is a self-contained group, so a newer value +So the lossy class is a plain track carrying the latest opaque frame, with +one self-contained group per update, so a newer value never waits behind an older one. One detail decides whether it actually delivers latest-value: @@ -58,8 +57,7 @@ delivers latest-value: under msgid 0; keying on msgid alone lets them overwrite each other. Decide explicitly what to do about instances distinguished only inside a payload, which the msgid-only rule cannot see. -- **One snapshot track per key.** A `moq_flate::snapshot` track holds one - latest value, so per-key latest-value means a track per +- **One latest-value track per key.** Per-key latest-value means a track per `(sysid, compid, msgid)`, named from the key and advertised in the catalog as it appears. That state grows with whatever the flight-controller link emits, so bound it: cap the number of keys (or derive the set from the @@ -70,13 +68,17 @@ Not `moq_json::snapshot`: a MAVLink frame is not JSON, and its default batches up to `MAX_DELTA_FRAMES` merge patches into one ordered group, so an earlier 50 Hz attitude delta would head-of-line block a later heartbeat. -The reliable class is the append-log shape (the binary `stream` mode): commands, +The reliable class is one bounded ordered group on a plain track: commands, ACKs, mission, parameter and file transfer are stop-and-wait exchanges carried in one ordered group. Note the scope in [robot](/quest/m3/teleop-robot.md): that is gap-free for a live reader, not recoverable after a lag or a reconnect, so these MAVLink services keep relying on their own retransmission across a link drop. +The [compression migration](/quest/m1/compress/migrate.md) deletes the +moq-flate snapshot and stream helpers. Keep these framing rules on plain +tracks, setting `compress` when useful, rather than depending on those helpers. + ### Deliberately out of scope Advertising the stream in-band. No `VIDEO_STREAM_TYPE` value can describe a diff --git a/quest/m3/teleop-robot.md b/quest/m3/teleop-robot.md index 9244529adb6..144b43eaa13 100644 --- a/quest/m3/teleop-robot.md +++ b/quest/m3/teleop-robot.md @@ -39,9 +39,12 @@ it are ordered and delivered exactly once. That guarantee is scoped, and the crate must say so rather than promise losslessness. A group holds at most `MAX_CACHE_BYTES` and `MAX_GROUP_FRAMES` -(`rs/moq-net/src/model/group.rs`), and a write past either aborts it with -`Error::GroupTooLarge`; `moq_json::stream` never rolls its one group, so that -bound ends the track, and a link drop or reconnect loses what was in flight. +(`rs/moq-net/src/model/group.rs`). A raw group write past either aborts it +with `Error::GroupTooLarge`, but the JSON stream helper refuses an append +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. 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 @@ -74,9 +77,12 @@ The framing is where the guarantee lives, not the subscription flags: root section through `moq-mux`'s `CatalogExt` and `RenditionConfig`. No hang schema change. - Announce-prefix fan-in, generalised from `rs/moq-boy/src/input.rs`. -- The two delivery classes, as the snapshot and stream modes with the group - structure and `Info::max_age` each one needs: `moq-json`'s for JSON, and the - opaque-bytes ones for binary frames (`moq-flate`). +- The two delivery classes with the group structure and `Info::max_age` each + one needs: `moq-json`'s snapshot and stream modes for JSON; plain tracks + for opaque bytes, one group per latest value or one bounded ordered group + for the append-log. The [compression migration](/quest/m1/compress/migrate.md) + deletes moq-flate's snapshot/stream helpers, so use the track's `compress` + flag when compression is useful, not those helpers. - Per-stage timestamp instrumentation, generalised from moq-boy's `status` track. Check it against the publisher-reported stats track ([media stats](/doc/concept/stats.md#media-reports), moq#2734) before adding a diff --git a/quest/m3/webkit-319818.md b/quest/m3/webkit-319818.md index de6fc2f323f..7f461d07f22 100644 --- a/quest/m3/webkit-319818.md +++ b/quest/m3/webkit-319818.md @@ -11,5 +11,7 @@ this quest and every `Required` entry that links it. ## Plan -As of 2026-09-30 the bug is NEW with no fix. Check the bug and the Safari -release notes. +As of 2026-10-22 UTC the bug is NEW with no resolution. Its 2026-10-18 +comment reproduces the failure on a newer Safari, so the condition remains +uncleared. Check the bug and the Safari release notes for a fixed shipping +version, then verify the reproduction before deleting this condition.