diff --git a/quest/m1/README.md b/quest/m1/README.md index e49a32b3ab..7517558bcd 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -78,6 +78,7 @@ above them, since the epoch anchor requires it. - [Live TS clock validation](/quest/m1/ts-live-clock.md) - resolve the local PCR-rate failure with reproducible timing evidence and CI controls - [Slow source fails](/quest/m1/slow-source.md) - an export whose source runs further off real time than the output may follow fails promptly naming the rate, instead of dropping frames for hours - [Same-instance TS resume](/quest/m1/ts-same-instance-resume.md) - prove valid continuation and fix the unexpected final exporter failure without weakening identity +- [Wire compat media](/quest/m1/wire-compat-media.md) - wire-compat always runs same-version media cells through the compat reader, so planned breaks can't hide its regressions - [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 - [Plan: a public model](/quest/m1/model-public-surface.md) - every crate-private model item is made public or unnecessary, so a custom publisher or subscriber builds from the public model alone - [Lazy discovery](/quest/m1/lazy-discovery/README.md) - a `consume` session requests announcements only for prefixes the origin is watching, in JS then Rust; `follow`, `broadcasts`, and the `discovery` option go away diff --git a/quest/m1/audio-jitter-target/README.md b/quest/m1/audio-jitter-target/README.md index 120f4e041a..0b9033d89f 100644 --- a/quest/m1/audio-jitter-target/README.md +++ b/quest/m1/audio-jitter-target/README.md @@ -36,6 +36,8 @@ the native decode path too, asserting the same target series the browser's ## Required +- [AAC bursty re-stall](/quest/m1/audio-jitter-target/aac-bursty-restall.md) - AAC under bursty delivery plays without a re-stall loop +- [Opus isolated-ring target](/quest/m1/audio-jitter-target/opus-isolated-target.md) - the isolated ring holds the target at near-zero jitter - [Watch](/quest/m1/audio-jitter-target/watch.md) - the browser's measured target, proven on Chrome and Safari against the public relay ## Closes diff --git a/quest/m1/audio-jitter-target/aac-bursty-restall.md b/quest/m1/audio-jitter-target/aac-bursty-restall.md new file mode 100644 index 0000000000..0c4905a0af --- /dev/null +++ b/quest/m1/audio-jitter-target/aac-bursty-restall.md @@ -0,0 +1,46 @@ +# [M] AAC under bursty delivery plays without a re-stall loop + +## Goal + +The browser player plays AAC under the `bursty` network profile without +repeatedly running dry and refilling: the nightly audio-quality rows' +`stalled_share`, skip-aheads, and discarded audio fall to what the Opus rows +on the same profile show, on both the isolated and the postMessage ring paths. + +## Plan + +Measured by [#5442](https://github.com/moq-dev/moq/pull/5442) over the 7 +scheduled nightlies of 2026-10-07 to 2026-10-13: both AAC bursty rows stalled +19 to 43% of the window every night, with about 17 skip-aheads a minute and +about 2 s a minute of audio discarded. AAC wide stalled 6 to 12%. The +budgets carry these numbers as measured so the job is green; this quest fixes +the player and tightens them. + +Start after #5442 merges: it uploads the nightly artifacts and carries the +measured budgets this quest tightens. + +Decided 2026-10-13 (maintainer): a child of the audio jitter target line, +reproducible from the harness now, so Watch's manual proof runs after it. + +Reproduce before fixing. Start from the nightly's `audio-quality-run` +artifacts (uploaded every run since #5442), then capture the case as a +replay trace so the failure runs deterministically under +`js/watch/src/audio/replay.ts` on a simulated clock. AAC's 1024-sample frames +(23.2 ms at 44.1 kHz) against Opus's 20 ms are the first suspect: the +estimator's frame term, the ring sizing, and the skip-ahead threshold each +see frame duration. Watch already records that a ring running dry re-stalls +and refills to the target; find why AAC under bursts keeps re-entering that +loop. Fix the layer that is wrong, including `doc/concept/audio-jitter.md` +and its conformance corpus if the estimator itself is at fault, mirrored in +`rs/moq-audio`. + +Tighten the replay budget for the new trace and the AAC browser ceilings in +`test/audio-quality/budgets.json` from re-measured nightly runs, with the +reason in review. + +Public API: none expected. Wire: none. + +## Related + +- [Watch](/quest/m1/audio-jitter-target/watch.md) - the manual browser proof that follows this fix +- [Opus isolated-ring target](/quest/m1/audio-jitter-target/opus-isolated-target.md) - the other defect the same measurement found diff --git a/quest/m1/audio-jitter-target/opus-isolated-target.md b/quest/m1/audio-jitter-target/opus-isolated-target.md new file mode 100644 index 0000000000..0172fb5da8 --- /dev/null +++ b/quest/m1/audio-jitter-target/opus-isolated-target.md @@ -0,0 +1,41 @@ +# [S] The isolated ring holds the target at near-zero jitter + +## Goal + +On the `near-zero` network profile, Opus on the isolated (SharedArrayBuffer) +ring settles at the same playout target as the postMessage ring, with no +underrun episodes, in the nightly audio-quality rows. + +## Plan + +Measured by [#5442](https://github.com/moq-dev/moq/pull/5442) over the 7 +scheduled nightlies of 2026-10-07 to 2026-10-13: Opus near-zero on the +isolated ring reached a `target_ms_p95` of 100 to 800 ms with underrun +episodes of about 1 s, while the postMessage ring on the same profile held at +60 ms. A network with almost no jitter should not grow the target, so the +first suspect is the isolated page's path rather than the estimator. + +Start after #5442 merges: it uploads the nightly artifacts and carries the +measured budgets this quest tightens. + +Decided 2026-10-13 (maintainer): a child of the audio jitter target line, +reproducible from the harness now, so Watch's manual proof runs after it. + +Reproduce it first, from the nightly artifacts and then in +`js/watch/src/audio/replay.ts` or a ring-level test on a simulated clock. +The target and the underruns may have separate causes. The target follows +`consumer.spread`, which `js/hang/src/container/consumer.ts` records from +transport arrivals before the ring, so a ring defect cannot inflate it: +compare the captured arrivals and configuration of the two rows first, for +something on the cross-origin isolated page that delays when frames are +observed. A ring that under-reports its fill, reads the worklet's position +late, or misses a resize explains underruns only. Fix each at the source with +a regression that fails without it, then tighten the isolated near-zero +ceilings in `test/audio-quality/budgets.json` from re-measured nightly runs. + +Public API: none expected. Wire: none. + +## Related + +- [Watch](/quest/m1/audio-jitter-target/watch.md) - the manual browser proof that follows this fix +- [AAC bursty re-stall](/quest/m1/audio-jitter-target/aac-bursty-restall.md) - the other defect the same measurement found diff --git a/quest/m1/audio-jitter-target/watch.md b/quest/m1/audio-jitter-target/watch.md index fe80fac882..e0ec630572 100644 --- a/quest/m1/audio-jitter-target/watch.md +++ b/quest/m1/audio-jitter-target/watch.md @@ -56,6 +56,11 @@ Decided 2026-10-08: moves to m1 with the rest of the line. The estimator defaults on and only this manual proof is left, so it no longer gates a release. +## Required + +- [AAC bursty re-stall](/quest/m1/audio-jitter-target/aac-bursty-restall.md) - AAC under bursty delivery plays without a re-stall loop +- [Opus isolated-ring target](/quest/m1/audio-jitter-target/opus-isolated-target.md) - the isolated ring holds the target at near-zero jitter + ## Related - [A/V clock](/quest/m1/av-clock.md) - reshapes `SyncInput` around the per-track target this line produces diff --git a/quest/m1/wire-compat-media.md b/quest/m1/wire-compat-media.md new file mode 100644 index 0000000000..5eab97c4eb --- /dev/null +++ b/quest/m1/wire-compat-media.md @@ -0,0 +1,39 @@ +# [S] Wire compatibility always exercises the compat reader's media path + +## Goal + +`just test wire-compat` runs at least one current-to-current and one +released-to-released media cell through the compat reader +(`test/interop/compat/client.ts`, selected by `INTEROP_COMPAT_CLIENT`), so a +regression in that reader's media path fails the nightly even while planned +breaks skip every cross-version media cell. + +## Plan + +Found on [#5444](https://github.com/moq-dev/moq/pull/5444): the +`catalog-archive` planned break skips all 24 media cells until a release +carries #4034, so the new reader's media path ran only by hand. A planned +break is about a version pairing, so same-version cells are never covered by +one and stay meaningful. + +Start after #5444 merges: it adds the reader's `subscribe` command and the +`INTEROP_COMPAT_CLIENT` selector this quest relies on. + +Decided 2026-10-13 (maintainer): m1. Add the two control cells to the +matrix in `test/interop/compat.sh` and `resolve.ts`, reusing the existing +lanes rather than a new harness. Pick the lite version the released packages +and binaries both negotiate. Prove each cell fails when the reader's media +path is broken (for example, a reader that never decodes a frame), then +restore it. Runs in the nightly Interop's wire-compat step; never dispatch the +nightly on a branch. + +Rejected 2026-10-13: a separate tsc pass of the compat reader. `just js check` +already typechecks `test/interop/compat/*.ts` against the checkout's packages +through `test/tsconfig.json`, and running a released lane catches API the +released packages lack. + +Public API: none. Wire: none. + +## Related + +- [#5444](https://github.com/moq-dev/moq/pull/5444) - the compat reader and the re-measured planned breaks