From c8e3ea1a0e23afbba8ebb5370e62a95304933579 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 13 Oct 2026 12:38:16 -0700 Subject: [PATCH 1/3] quest(m1): plan the audio-quality and wire-compat follow-ups Co-Authored-By: Claude Opus 5.5 --- quest/m1/README.md | 1 + quest/m1/audio-jitter-target/README.md | 2 + .../audio-jitter-target/aac-bursty-restall.md | 43 +++++++++++++++++++ .../opus-isolated-target.md | 35 +++++++++++++++ quest/m1/audio-jitter-target/watch.md | 5 +++ quest/m1/wire-compat-media.md | 36 ++++++++++++++++ 6 files changed, 122 insertions(+) create mode 100644 quest/m1/audio-jitter-target/aac-bursty-restall.md create mode 100644 quest/m1/audio-jitter-target/opus-isolated-target.md create mode 100644 quest/m1/wire-compat-media.md 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..5bfe94a7be --- /dev/null +++ b/quest/m1/audio-jitter-target/aac-bursty-restall.md @@ -0,0 +1,43 @@ +# [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. + +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..cc126d13d7 --- /dev/null +++ b/quest/m1/audio-jitter-target/opus-isolated-target.md @@ -0,0 +1,35 @@ +# [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 +difference points at the isolated ring's path, not the estimator. + +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. +Compare what each ring reports as arrival and consumption to the estimator: +an isolated ring that under-reports its fill, reads the worklet's position +late, or misses a resize would underrun on its own and feed that back as +measured jitter. Fix it 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..ae1ea9a0d9 --- /dev/null +++ b/quest/m1/wire-compat-media.md @@ -0,0 +1,36 @@ +# [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. + +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 From bd3429375dcbef6663a78fdb43dff7d34ef67e63 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 13 Oct 2026 12:42:56 -0700 Subject: [PATCH 2/3] quest(m1): separate the isolated target from its underruns; note the #5442/#5444 starts The playout target follows the container's arrival spread, recorded before the ring, so a ring defect explains underruns but not target growth. Co-Authored-By: Claude Opus 5.5 --- .../audio-jitter-target/aac-bursty-restall.md | 3 +++ .../opus-isolated-target.md | 20 ++++++++++++------- quest/m1/wire-compat-media.md | 3 +++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/quest/m1/audio-jitter-target/aac-bursty-restall.md b/quest/m1/audio-jitter-target/aac-bursty-restall.md index 5bfe94a7be..0c4905a0af 100644 --- a/quest/m1/audio-jitter-target/aac-bursty-restall.md +++ b/quest/m1/audio-jitter-target/aac-bursty-restall.md @@ -16,6 +16,9 @@ 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. diff --git a/quest/m1/audio-jitter-target/opus-isolated-target.md b/quest/m1/audio-jitter-target/opus-isolated-target.md index cc126d13d7..6f3993e839 100644 --- a/quest/m1/audio-jitter-target/opus-isolated-target.md +++ b/quest/m1/audio-jitter-target/opus-isolated-target.md @@ -13,19 +13,25 @@ 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 -difference points at the isolated ring's path, not the estimator. +difference points at the isolated page's path, not 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. -Compare what each ring reports as arrival and consumption to the estimator: -an isolated ring that under-reports its fill, reads the worklet's position -late, or misses a resize would underrun on its own and feed that back as -measured jitter. Fix it 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. +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. diff --git a/quest/m1/wire-compat-media.md b/quest/m1/wire-compat-media.md index ae1ea9a0d9..5eab97c4eb 100644 --- a/quest/m1/wire-compat-media.md +++ b/quest/m1/wire-compat-media.md @@ -16,6 +16,9 @@ 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 From b3e87851299a2ffb4fc6a1109e6e1742c4cbea30 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 13 Oct 2026 12:46:34 -0700 Subject: [PATCH 3/3] quest(m1): the isolated page is a suspect, not a conclusion Co-Authored-By: Claude Opus 5.5 --- quest/m1/audio-jitter-target/opus-isolated-target.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quest/m1/audio-jitter-target/opus-isolated-target.md b/quest/m1/audio-jitter-target/opus-isolated-target.md index 6f3993e839..0172fb5da8 100644 --- a/quest/m1/audio-jitter-target/opus-isolated-target.md +++ b/quest/m1/audio-jitter-target/opus-isolated-target.md @@ -13,7 +13,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 -difference points at the isolated page's path, not the estimator. +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.