From 551585ce485d0c839248d26a1ec4301ba2011c2e Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 07:44:50 -0700 Subject: [PATCH 1/3] quest: record pre-cut follow-ups from the quest-spawn run Twelve quests for breaks on main and gaps found while landing the 2026-10-24 quest-spawn PRs: the loom build, `just check` without user namespaces, the red TS workflow, OBS dropping groups, a slow moq-cli test, range-count cost, the superlinear fill path, a possible js/net close race, relay demand gaps, fMP4 boundary sync, moq-c decode start, and one moq-ffi build definition. bench-ci gains the malloc-pin question. Co-Authored-By: Claude Opus 5.5 --- quest/m0/ci/README.md | 2 ++ quest/m0/ci/check-without-userns.md | 24 ++++++++++++++++ quest/m0/ci/loom-build.md | 23 +++++++++++++++ quest/m1/README.md | 4 +++ quest/m1/bench-ci.md | 4 +++ quest/m1/broadcast-lifecycle/README.md | 1 + quest/m1/broadcast-lifecycle/js-close-fin.md | 18 ++++++++++++ quest/m1/c/README.md | 1 + quest/m1/c/decode-start.md | 16 +++++++++++ quest/m1/ffi-build-flags.md | 18 ++++++++++++ quest/m1/fmp4-boundary-sync.md | 16 +++++++++++ quest/m1/obs-data-decode.md | 22 ++++++++++++++ quest/m1/relay-demand-gaps.md | 23 +++++++++++++++ quest/m1/subscribe-ranges/README.md | 2 ++ quest/m1/subscribe-ranges/fill-linear.md | 21 ++++++++++++++ quest/m1/subscribe-ranges/range-cost.md | 22 ++++++++++++++ quest/m1/test-flakes-2/README.md | 1 + quest/m1/test-flakes-2/export-echo-time.md | 16 +++++++++++ quest/m1/ts-reliability/README.md | 1 + quest/m1/ts-reliability/validation-green.md | 30 ++++++++++++++++++++ 20 files changed, 265 insertions(+) create mode 100644 quest/m0/ci/check-without-userns.md create mode 100644 quest/m0/ci/loom-build.md create mode 100644 quest/m1/broadcast-lifecycle/js-close-fin.md create mode 100644 quest/m1/c/decode-start.md create mode 100644 quest/m1/ffi-build-flags.md create mode 100644 quest/m1/fmp4-boundary-sync.md create mode 100644 quest/m1/obs-data-decode.md create mode 100644 quest/m1/relay-demand-gaps.md create mode 100644 quest/m1/subscribe-ranges/fill-linear.md create mode 100644 quest/m1/subscribe-ranges/range-cost.md create mode 100644 quest/m1/test-flakes-2/export-echo-time.md create mode 100644 quest/m1/ts-reliability/validation-green.md diff --git a/quest/m0/ci/README.md b/quest/m0/ci/README.md index 2f0da3af34e..d44af7bbe27 100644 --- a/quest/m0/ci/README.md +++ b/quest/m0/ci/README.md @@ -97,3 +97,5 @@ The historical samples locate candidates; they are not controlled benchmarks. - [mbx on a full disk](/quest/m0/ci/mbx-low-disk.md) - gc never evicts a live build's trees, and the Dart check names the real cause - [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 +- [Loom tests compile](/quest/m0/ci/loom-build.md) - `just rs loom` builds on main and a `--cfg loom` break fails its PR +- [just check without user namespaces](/quest/m0/ci/check-without-userns.md) - a host that refuses `unshare` reports the flake module as not run instead of cancelling other lanes diff --git a/quest/m0/ci/check-without-userns.md b/quest/m0/ci/check-without-userns.md new file mode 100644 index 00000000000..af39d878807 --- /dev/null +++ b/quest/m0/ci/check-without-userns.md @@ -0,0 +1,24 @@ +# [S] just check finishes on a host without user namespaces + +## Goal + +On a host that refuses unprivileged user namespaces, `just check` runs every +other module to completion and reports the flake module as not run, with the +reason, instead of failing it and cancelling the lanes behind it. The merge +queue still runs the flake check in full. + +## Plan + +Seen 2026-10-24/25 in every quest-spawn agent: `check:flake` (`sh/dispatch.sh`) +runs `nix flake check`, whose github-runner VM test (`nix/runner/test.nix`) +fails with `unshare ... uid_map: Operation not permitted`. That failure cancels +other lanes (kt, js, rs tests), so agents fell back to partial checks and +reported them as `just check`. + +- Probe for user namespaces once, up front, and report the flake module as + skipped with that reason; never as passed. +- Alternatively split the VM test out of the default flake check and run it + only where it can; pick whichever keeps `just ci` in the queue unchanged. +- One module failing must not cancel unrelated lanes either way. + +Public API: none. Wire: none. diff --git a/quest/m0/ci/loom-build.md b/quest/m0/ci/loom-build.md new file mode 100644 index 00000000000..9326b296fa0 --- /dev/null +++ b/quest/m0/ci/loom-build.md @@ -0,0 +1,23 @@ +# [S] Loom tests compile, and the gate proves it + +## Goal + +`just rs loom` builds and runs on `main`, and a PR that breaks the `--cfg loom` +build fails its own gate instead of the next Nightly. + +## Plan + +Found 2026-10-25: `RUSTFLAGS="--cfg loom" cargo test -p moq-net --test loom +--no-run` fails on main with E0599 at `rs/moq-net/tests/loom.rs:621`: +`Subscription::with_groups` was replaced by `with_range` in +[moq-dev/moq#6138](https://github.com/moq-dev/moq/pull/6138), which missed the +loom test because nothing on the PR gate builds with `--cfg loom`. + +- Port the call to `with_range`, then run the full `just rs loom`. +- Add a compile-only `--cfg loom` step (`--no-run`) to the changed-Rust check + when `kio` or `moq-net` changes, so the build break fails the PR. +- The Loom models that exceed their branch limit or run past the job timeout + are tracked in [CI audit](/quest/m2/audit-ci.md); this quest only restores + the build. + +Public API: none. Wire: none. diff --git a/quest/m1/README.md b/quest/m1/README.md index 9ad0bfc1971..4bd807effe5 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -171,6 +171,10 @@ Catalog HLS field. - [Unbounded groups](/quest/m1/unbounded-groups/README.md) - groups and frames lose their size caps; the cache sheds parts of a group under pressure and refills the holes in place - [Clean close reason](/quest/m1/clean-close-reason.md) - a session that closes on its own is never recorded as `Unauthorized` because its in-band credentials closed with it - [Metric-safe tiers](/quest/m1/metric-tier.md) - tiers are `[A-Za-z0-9._-]` paths refused where they are set, and every metric label value is escaped +- [Bindings decode media as media](/quest/m1/obs-data-decode.md) - moq-ffi decodes a media rendition with its kind, so OBS stops losing every other group +- [Relay demand gaps](/quest/m1/relay-demand-gaps.md) - pre-07 backlog, IETF warm-relay newcomer, and double upstream pulls are fixed or ruled out +- [fMP4 boundary sync](/quest/m1/fmp4-boundary-sync.md) - a declared fMP4 boundary opens a passthrough group only on a sync sample +- [One moq-ffi build definition](/quest/m1/ffi-build-flags.md) - every binding takes moq-ffi's default features from one place ## Related diff --git a/quest/m1/bench-ci.md b/quest/m1/bench-ci.md index c40eaa0d119..0282796188d 100644 --- a/quest/m1/bench-ci.md +++ b/quest/m1/bench-ci.md @@ -29,6 +29,10 @@ lands; agents never dispatch Nightly. on the mbx cache for the previous night's artifacts, and a cold one roughly doubles each leg's build time. +- Decide whether `bench/run.sh` pins glibc's malloc thresholds for every + Criterion target, as [moq-dev/moq#6727](https://github.com/moq-dev/moq/pull/6727) + did for `ts_schedule`: some small paired deltas may be the same heap mode flip. + Decided 2026-10-23 (maintainer), when the paired mode landed: - The gate fails Nightly from day one rather than reporting only until A/A diff --git a/quest/m1/broadcast-lifecycle/README.md b/quest/m1/broadcast-lifecycle/README.md index d9ae3b463ca..9115bf2bf31 100644 --- a/quest/m1/broadcast-lifecycle/README.md +++ b/quest/m1/broadcast-lifecycle/README.md @@ -48,6 +48,7 @@ timer on main at 1582fdc07d: - [Closing a binding broadcast ends its media](/quest/m1/broadcast-lifecycle/ffi-close.md) - moq-ffi and moq-c media handles end with a cause on close or drop, never a cause-less drop - [lite-03/04 close FIN](/quest/m1/broadcast-lifecycle/lite-close-fin.md) - a graceful relay close delivers pending SUBSCRIBE FINs on lite-03 and lite-04 +- [js/net close FIN](/quest/m1/broadcast-lifecycle/js-close-fin.md) - js/net finishes tracks whose FIN arrives with a graceful close ## Related diff --git a/quest/m1/broadcast-lifecycle/js-close-fin.md b/quest/m1/broadcast-lifecycle/js-close-fin.md new file mode 100644 index 00000000000..19ea400ce0e --- /dev/null +++ b/quest/m1/broadcast-lifecycle/js-close-fin.md @@ -0,0 +1,18 @@ +# [S] js/net finishes tracks whose FIN arrives with the close + +## Goal + +When a peer closes a session gracefully right after finishing its tracks, a +js/net relay or subscriber finishes those tracks instead of aborting them, on +every lite version, as Rust does since +[moq-dev/moq#6741](https://github.com/moq-dev/moq/pull/6741). + +## Plan + +In Rust the close could reach the subscriber before it read an already +buffered SUBSCRIBE FIN, so the track ended `Unroutable`. The fix polls the +sources once after the closed transport's group streams drain. Check whether +js/net has the same ordering; if so, reproduce with a two-`Connection` test and +mirror the fix. If not, delete this quest with the evidence. + +Public API: none. Wire: none. diff --git a/quest/m1/c/README.md b/quest/m1/c/README.md index 00986136419..9ec319a17eb 100644 --- a/quest/m1/c/README.md +++ b/quest/m1/c/README.md @@ -70,3 +70,4 @@ requests internally and keeps its ABI. - [C consumers](/quest/m1/c/consumers.md) - the C interop client and `doc/lib/c` samples move onto the generated API - [Async failure contract](/quest/m1/c/async-failure-contract.md) - a generated async call that fails early fires no callback, and one that started always delivers its terminal callback - [Refuse only waiting readers](/quest/m1/c/request-refuse.md) - freeing or aborting a group request refuses its readers instead of dropping the group for everyone +- [moq-c decode start](/quest/m1/c/decode-start.md) - a moq-c decoder can read a finished track from its start diff --git a/quest/m1/c/decode-start.md b/quest/m1/c/decode-start.md new file mode 100644 index 00000000000..e6d8b0766cd --- /dev/null +++ b/quest/m1/c/decode-start.md @@ -0,0 +1,16 @@ +# [XS] moq-c decoders choose where to start + +## Goal + +A moq-c decoder can read a finished track from its start: decoding a finished +Opus track yields its frames instead of none. + +## Plan + +Found by [moq-dev/moq#6745](https://github.com/moq-dev/moq/pull/6745): +`rs/moq-c/src/video.rs:953` and `rs/moq-c/src/audio.rs:503` hardcode +`Start::Latest`. Confirm whether that was intended for live playback; if a +caller needs the other start, expose it the way moq-ffi does, else document +why moq-c only plays live. + +Public API: maybe a start option on the decode config. Wire: none. diff --git a/quest/m1/ffi-build-flags.md b/quest/m1/ffi-build-flags.md new file mode 100644 index 00000000000..19cbb364be8 --- /dev/null +++ b/quest/m1/ffi-build-flags.md @@ -0,0 +1,18 @@ +# [S] One definition of moq-ffi's default build flags + +## Goal + +Every binding that builds moq-ffi into the shared target directory takes its +features from one place, so a binding whose features drift cannot silently +overwrite `libmoq_ffi.so` for the others again. + +## Plan + +[moq-dev/moq#6716](https://github.com/moq-dev/moq/pull/6716) found that a +cdylib's file name carries no feature hash, so builds with different features +overwrite each other. Today the flags are repeated: `sh/kt/generate.sh`, +`sh/swift/check.sh`, `sh/go/stage.sh`, `sh/dart/generate.sh`, and +`cpp/moq/CMakeLists.txt` each pass `--features openh264`. Define them once, +and make a build that differs use its own target directory or fail loudly. + +Public API: none. Wire: none. diff --git a/quest/m1/fmp4-boundary-sync.md b/quest/m1/fmp4-boundary-sync.md new file mode 100644 index 00000000000..2866924caf7 --- /dev/null +++ b/quest/m1/fmp4-boundary-sync.md @@ -0,0 +1,16 @@ +# [S] A declared fMP4 boundary opens a group only on a sync sample + +## Goal + +When a passthrough fMP4 import sees a declared segment boundary (`styp` or +`cut()`) whose fragment does not start with a sync sample, it does not open a +new group on the non-sync samples. Passthrough and unwrapped mode agree. + +## Plan + +Found by [moq-dev/moq#6743](https://github.com/moq-dev/moq/pull/6743): +unwrapped mode keeps those samples in the previous group, while passthrough +opens a new group a decoder cannot start from. Reproduce with a fixture, then +share one rule between both modes. + +Public API: none. Wire: none. diff --git a/quest/m1/obs-data-decode.md b/quest/m1/obs-data-decode.md new file mode 100644 index 00000000000..8e69c0f4729 --- /dev/null +++ b/quest/m1/obs-data-decode.md @@ -0,0 +1,22 @@ +# [S] Bindings decode media tracks as media + +## Goal + +moq-ffi's `MoqMediaTrackConsumer` decodes a video or audio rendition with its +own kind, so the empty marker that ends a video group never reaches a binding +as an empty frame, and OBS plays every group. + +## Plan + +Found by the OBS decode-timing quest +([moq-dev/moq#6711](https://github.com/moq-dev/moq/pull/6711)), not yet +reproduced: `rs/moq-ffi/src/media.rs:1253` builds every container with +`container::Kind::Data`. FFmpeg treats an empty packet as end of stream, so OBS +likely drops every other group on streams without B-frames. + +- Reproduce in an OBS source test or a moq-ffi test that reads two video + groups through the consumer. +- Pass the rendition's video or audio kind into `media_container`. +- Run `just test interop --all`. + +Public API: none expected. Wire: none. diff --git a/quest/m1/relay-demand-gaps.md b/quest/m1/relay-demand-gaps.md new file mode 100644 index 00000000000..6cd6a955cfe --- /dev/null +++ b/quest/m1/relay-demand-gaps.md @@ -0,0 +1,23 @@ +# [M] Relay demand gaps left by the widened-age re-offer + +## Goal + +Three gaps found by [moq-dev/moq#6717](https://github.com/moq-dev/moq/pull/6717) +are fixed or ruled out, each with a test: + +- On lite before 07, a reader with a narrow max age receives the whole backlog. +- On moq-transport, a newcomer on a warm relay gets only the newest group. +- A relay newcomer may pull one group upstream twice: once from its range fill + and once from the publisher's re-offer. + +## Plan + +Reproduce each through a relay first. The third is wasted upstream bandwidth +per newcomer, so it scales with subscribers; cover it with a benchmark if it +reproduces. + +Public API: none expected. Wire: none expected. + +## Related + +- [A widened max age re-offers cached groups](/quest/m1/resolved-demand.md) diff --git a/quest/m1/subscribe-ranges/README.md b/quest/m1/subscribe-ranges/README.md index fcd21b4bbc1..e398ef20c0d 100644 --- a/quest/m1/subscribe-ranges/README.md +++ b/quest/m1/subscribe-ranges/README.md @@ -99,6 +99,8 @@ every sequence delivered or dropped. - [Lite-07 ranges](/quest/m1/subscribe-ranges/lite.md) - the lite-07 wire, Rust publisher and subscriber, and the draft - [moq-transport ranges](/quest/m1/subscribe-ranges/ietf.md) - range FETCH upstream per missing run, and non-blocking FETCH served downstream - [JS ranges](/quest/m1/subscribe-ranges/js.md) - `@moq/net` model and lite-07 parity +- [Range count cost](/quest/m1/subscribe-ranges/range-cost.md) - a subscription's range count cannot multiply per-group cost +- [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md) - filling stays flat as range count and span grow ## Related diff --git a/quest/m1/subscribe-ranges/fill-linear.md b/quest/m1/subscribe-ranges/fill-linear.md new file mode 100644 index 00000000000..3b87b9f8e3c --- /dev/null +++ b/quest/m1/subscribe-ranges/fill-linear.md @@ -0,0 +1,21 @@ +# [M] The fill path is linear in range count and span + +## Goal + +`track_range_filling` (`rs/moq-net/benches/track.rs`) holds roughly flat +groups/s as range count and span grow. + +## Plan + +Measured in [moq-dev/moq#6722](https://github.com/moq-dev/moq/pull/6722): 234K +groups/s at 1 range × 1 span falls to 1.9K at 256 ranges × 64 span. Each poll's +drift edge (`live_edge`) and each candidate's successor search +(`arrival`/`successor`) walk `lookup` across all of a reader's runs, and a +filled group is never marked shown, so every scan passes it again. +`Misses::retain` also rescans every filled group per poll. + +That PR recommends landing this before +[FETCH as a range](/quest/m1/subscribe-ranges/fetch-range.md), since one-range +reads would put every past read on this path. + +Public API: none. Wire: none. diff --git a/quest/m1/subscribe-ranges/range-cost.md b/quest/m1/subscribe-ranges/range-cost.md new file mode 100644 index 00000000000..a8e0f36dde1 --- /dev/null +++ b/quest/m1/subscribe-ranges/range-cost.md @@ -0,0 +1,22 @@ +# [M] A subscription's range count cannot multiply per-group cost + +## Goal + +The model's cost per group no longer grows with the number of ranges in a +subscription, or that number is bounded by the design (flow control or an +owned budget), not by a refusal constant. A benchmark sweeps range count and +subscriber count, so a slope shows up. + +## Plan + +From [moq-dev/moq#6715](https://github.com/moq-dev/moq/pull/6715): lite-07 +SUBSCRIBE carries a list of ranges, a peer can send as many as fit in one +message, and the model's per-group cost grows with that count. A hostile peer +can multiply the CPU a relay spends on every group of a track. + +- Measure first: extend `rs/moq-net/benches/track.rs` with ranges × subscribers. +- Prefer merging overlapping or adjacent ranges at decode, and a lookup that + touches only the ranges around a group. +- Shares code with [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md). + +Public API: none expected. Wire: none expected. diff --git a/quest/m1/test-flakes-2/README.md b/quest/m1/test-flakes-2/README.md index 677caa4e7fe..67a51cc1116 100644 --- a/quest/m1/test-flakes-2/README.md +++ b/quest/m1/test-flakes-2/README.md @@ -48,3 +48,4 @@ Public API: none. Wire: none. - [moq-gst sibling resume](/quest/m1/test-flakes-2/gst-sibling-resume.md) - an idle pad reads its named epoch again after a sibling restart, a likely liveness bug fixed before the test - [moq-gst pinned replay](/quest/m1/test-flakes-2/gst-pinned-replay.md) - the pinned-instance finish test waits on events instead of sleep loops - [Dart leak RSS](/quest/m1/test-flakes-2/dart-leak-rss.md) - the leak tests measure what moq owns, not process RSS +- [Echo report test on mocked time](/quest/m1/test-flakes-2/export-echo-time.md) - the moq-cli echo report test stops taking 35 s of wall time diff --git a/quest/m1/test-flakes-2/export-echo-time.md b/quest/m1/test-flakes-2/export-echo-time.md new file mode 100644 index 00000000000..89722c58f49 --- /dev/null +++ b/quest/m1/test-flakes-2/export-echo-time.md @@ -0,0 +1,16 @@ +# [S] The moq-cli echo report test runs on mocked time + +## Goal + +`report::export_echo_reports_where_the_import_solicits` +(`rs/moq-cli/tests/integration/report.rs:384`) finishes in well under a second +of wall time, so it stops being flagged SLOW in every `just check`. + +## Plan + +Six quest-spawn agents on 2026-10-25 saw it take about 35 s under load and +flagged it as SLOW. Find what it waits on in wall time and drive that from a +mocked clock or an event, per the root rule that unit tests mock time. If part +of it must stay real-time, move that part to Nightly. + +Public API: none. Wire: none. diff --git a/quest/m1/ts-reliability/README.md b/quest/m1/ts-reliability/README.md index 0952ea7bad8..76227439aeb 100644 --- a/quest/m1/ts-reliability/README.md +++ b/quest/m1/ts-reliability/README.md @@ -101,6 +101,7 @@ catalog linger (#5305). - [State bound](/quest/m1/ts-reliability/state-bound.md) - SI and revision state retire with what the source stops repeating - [PAT changes](/quest/m1/ts-reliability/pat-lifecycle.md) - a revised PAT never leaves a broadcast meaning another program - [Stream routes](/quest/m1/ts-reliability/stream-routes.md) - every PID gets a declared route, and what is not carried is counted +- [TS workflow passes](/quest/m1/ts-reliability/validation-green.md) - the scheduled TS lanes pass on main again, with no lane loosened ## Related diff --git a/quest/m1/ts-reliability/validation-green.md b/quest/m1/ts-reliability/validation-green.md new file mode 100644 index 00000000000..96c2b63bf5d --- /dev/null +++ b/quest/m1/ts-reliability/validation-green.md @@ -0,0 +1,30 @@ +# [M] The TS workflow passes on main + +## Goal + +The scheduled TS workflow (`.github/workflows/ts.yml`) passes on `main`, with +no lane loosened. + +## Plan + +Two breaks, seen in run +[40195146593](https://github.com/moq-dev/moq/actions/runs/40195146593) +(`66af72315b`, 2026-10-25). Last green run: 2026-10-20 at `f13283b302`. + +- **New on 2026-10-25:** private PES, broadcast-sized CPB, full leak, full + multiplex, and headroom each lose 18 or 28 video frames at a regular + interval (`FAIL PID 0x100 h264: 475 frames of 40.00 ms, 18 holes, 1440 ms + missing`). Green on 2026-10-24 at `ea09d025a2`. Bisect + `ea09d025a2..66af72315b`; candidates include + [moq-dev/moq#6534](https://github.com/moq-dev/moq/pull/6534) (assemble TS + video across PES boundaries) and + [moq-dev/moq#6656](https://github.com/moq-dev/moq/pull/6656) (export + follows by cause). +- **Since 2026-10-21:** the congested path (`--headroom --rate 7000000`) + captures only the last second of its 120 s run, and the overflowing path + (`--queue 250ms`, CUBIC) starts 49 s late. Bisect + `f13283b302..dbf06bdcb3`. +- Fix each at its cause; the congestion lanes must keep their bufferbloat + shape and their assertions. + +Public API: none expected. Wire: none. From b014ddd94db69c4c6dff3ffb340c29a71b43b424 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 08:01:34 -0700 Subject: [PATCH 2/3] quest: record the remaining pre-cut follow-ups Adds quests for reported-drop parity between Rust and JS, the flaky OBS audio-candidate test, and upstream bug reports (faad, retina, mr-boxington). The release cut gains the moq-cli/moq-gst MIGRATE entries and the wrapper moq-ffi floors; the interop and dead-code audits gain the imquic announce timeout, a dead RecvBandwidth branch, and leftover `dynamic` names. Co-Authored-By: Claude Opus 5.5 --- quest/m1/README.md | 1 + quest/m1/resume-drop-final.md | 21 +++++++++++++++++ quest/m1/test-flakes-2/README.md | 1 + quest/m1/test-flakes-2/obs-audio-candidate.md | 16 +++++++++++++ quest/m2/README.md | 1 + quest/m2/audit-dead-code.md | 8 +++++++ quest/m2/audit-interop.md | 4 ++++ quest/m2/release/cut.md | 8 +++++++ quest/m2/upstream-reports.md | 23 +++++++++++++++++++ 9 files changed, 83 insertions(+) create mode 100644 quest/m1/resume-drop-final.md create mode 100644 quest/m1/test-flakes-2/obs-audio-candidate.md create mode 100644 quest/m2/upstream-reports.md diff --git a/quest/m1/README.md b/quest/m1/README.md index 4bd807effe5..8c8d479be51 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -175,6 +175,7 @@ Catalog HLS field. - [Relay demand gaps](/quest/m1/relay-demand-gaps.md) - pre-07 backlog, IETF warm-relay newcomer, and double upstream pulls are fixed or ruled out - [fMP4 boundary sync](/quest/m1/fmp4-boundary-sync.md) - a declared fMP4 boundary opens a passthrough group only on a sync sample - [One moq-ffi build definition](/quest/m1/ffi-build-flags.md) - every binding takes moq-ffi's default features from one place +- [A reported drop means the same everywhere](/quest/m1/resume-drop-final.md) - Rust and JS agree whether a group reported dropped can still be served ## Related diff --git a/quest/m1/resume-drop-final.md b/quest/m1/resume-drop-final.md new file mode 100644 index 00000000000..faf0374b3b2 --- /dev/null +++ b/quest/m1/resume-drop-final.md @@ -0,0 +1,21 @@ +# [M] A reported drop means the same in Rust and JS + +## Goal + +Rust and JS agree on whether a group reported as dropped can still be served +later, on the plain cursor and the resumed (routed) path alike. + +## Plan + +Found by [moq-dev/moq#6758](https://github.com/moq-dev/moq/pull/6758). JS +records a reported drop as delivered, so no copy serves that group later. In +Rust a plain cursor reports a fill it gave up on as `NotFound`, and the group +can still arrive and be served. Making Rust's drops final broke +`rejoin::rejoined_quiet_catalog_survives_cache_expiry`: a late reader never got +the catalog's group 0. + +Decide (maintainer) whether a reported drop is final. Then change the side that +differs, the plain cursor and the resume path together, with tests in both +languages. + +Public API: none expected. Wire: none. diff --git a/quest/m1/test-flakes-2/README.md b/quest/m1/test-flakes-2/README.md index 67a51cc1116..d63387e0ddb 100644 --- a/quest/m1/test-flakes-2/README.md +++ b/quest/m1/test-flakes-2/README.md @@ -49,3 +49,4 @@ Public API: none. Wire: none. - [moq-gst pinned replay](/quest/m1/test-flakes-2/gst-pinned-replay.md) - the pinned-instance finish test waits on events instead of sleep loops - [Dart leak RSS](/quest/m1/test-flakes-2/dart-leak-rss.md) - the leak tests measure what moq owns, not process RSS - [Echo report test on mocked time](/quest/m1/test-flakes-2/export-echo-time.md) - the moq-cli echo report test stops taking 35 s of wall time +- [OBS failed audio candidate](/quest/m1/test-flakes-2/obs-audio-candidate.md) - the OBS failed-audio-candidate test passes under load diff --git a/quest/m1/test-flakes-2/obs-audio-candidate.md b/quest/m1/test-flakes-2/obs-audio-candidate.md new file mode 100644 index 00000000000..2d2b681aea9 --- /dev/null +++ b/quest/m1/test-flakes-2/obs-audio-candidate.md @@ -0,0 +1,16 @@ +# [S] The OBS failed-audio-candidate test passes under load + +## Goal + +The OBS test "failed audio candidate preserves playback" passes under load, +fixed at its cause. + +## Plan + +Seen by [moq-dev/moq#6711](https://github.com/moq-dev/moq/pull/6711): it fails +intermittently under load on the base commit too. Reproduce it under CPU +pressure or `SIGSTOP`/`SIGCONT` pauses, the way +[moq-dev/moq#6737](https://github.com/moq-dev/moq/pull/6737) did, then fix the +race. + +Public API: none. Wire: none. diff --git a/quest/m2/README.md b/quest/m2/README.md index b72f8e9b5cf..06cf4706911 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -38,6 +38,7 @@ lite-07; bitrate enforcement is not part of this release. - [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 - [VA-API encodes an external Vulkan image](/quest/m2/vaapi-vulkan-import.md) - an explicit-sync DMA-BUF reaches Intel's encoder, proven on Arrow Lake - [C++ FFI reuse](/quest/m2/cpp-ffi-reuse.md) - C++ packages link the shared default-feature FFI build once it is proven compatible +- [Upstream reports](/quest/m2/upstream-reports.md) - report the faad, retina, and mr-boxington bugs found before the cut - [Native compression flush](/quest/m2/native-compression-flush.md) - report the per-frame nonfinal flush requirement in existing browser discussions - [Native synchronous codecs](/quest/m2/native-compression-sync.md) - report the stateful small-frame synchronous API requirement diff --git a/quest/m2/audit-dead-code.md b/quest/m2/audit-dead-code.md index 3958b821bb0..c15bd8414ce 100644 --- a/quest/m2/audit-dead-code.md +++ b/quest/m2/audit-dead-code.md @@ -74,6 +74,14 @@ No public removal landed in this run itself; the items marked removed above went in a follow-up PR. Propose any public removals separately with their migration and consumer evidence. The public model and performance audits own their API and benchmark decisions. +From the 2026-10-25 run: + +- moq-tokio's `RecvBandwidth::poll` still handles a closed output, but `out` + can no longer close while that call borrows it + ([moq-dev/moq#6744](https://github.com/moq-dev/moq/pull/6744)). +- Locals and fields still named `dynamic` after the `requests()` rename + ([moq-dev/moq#6752](https://github.com/moq-dev/moq/pull/6752)). + ## Required - [Release cut](/quest/m2/release/cut.md) - the release in flight ships before the next audit starts diff --git a/quest/m2/audit-interop.md b/quest/m2/audit-interop.md index 2f6a4150635..132eb6f71ca 100644 --- a/quest/m2/audit-interop.md +++ b/quest/m2/audit-interop.md @@ -147,6 +147,10 @@ and moqtopus and xquic-draft-18 over WebTransport (raw QUIC only). - [Release cut](/quest/m2/release/cut.md) - waits for the release in flight to ship +From the 2026-10-25 run: the runner's moq-dev-js `announce-subscribe` case times +out against imquic on both 0.4.4 and the [moq-dev/moq#6769](https://github.com/moq-dev/moq/pull/6769) +backport, so it predates that fix. Classify it. + ## Related - [Runner client bump](/quest/m2/release/runner-client-bump.md) - the runner's Rust client moves to the cut and its API diff --git a/quest/m2/release/cut.md b/quest/m2/release/cut.md index 2732883498d..3537d7460d4 100644 --- a/quest/m2/release/cut.md +++ b/quest/m2/release/cut.md @@ -36,6 +36,14 @@ release epic in m2. Each keeps its Goal and recurrence paragraph and requires the new `/quest/m1/README.md`, and the cut also requires both reviews. Only `/quest-delete` ends the recurrence. +From the 2026-10-25 pre-cut run: + +- Write the moq-cli and moq-gst `MIGRATE.md` entries from the Impact section of + [moq-dev/moq#6522](https://github.com/moq-dev/moq/pull/6522); that rename list exists nowhere else. +- Raise each wrapper's moq-ffi version floor (for example Kotlin's + `MOQ_FFI_RANGE`) to the release that ships the `implementation` field from + [moq-dev/moq#6775](https://github.com/moq-dev/moq/pull/6775). + ## Required - [Breaking release readiness](/quest/m1/README.md) - code, protocol and package proofs diff --git a/quest/m2/upstream-reports.md b/quest/m2/upstream-reports.md new file mode 100644 index 00000000000..14c2e8bd255 --- /dev/null +++ b/quest/m2/upstream-reports.md @@ -0,0 +1,23 @@ +# [S] Report upstream bugs found during the pre-cut run + +## Goal + +Each bug below is reported upstream, or confirmed already fixed there, and +our workaround links the report. + +## Plan + +Posting outside `moq-dev` and `kixelated` needs maintainer approval for each +report. + +- **GStreamer `faad`:** it drops the first AAC frame and shifts timestamps by + one frame, so the interop AAC phase check skips GStreamer + ([moq-dev/moq#6742](https://github.com/moq-dev/moq/pull/6742)). Remove the + skip once it's fixed. +- **retina 0.4.21:** when the server sends an RTSP request during playback, + retina logs a warning, returns `Pending`, and goes idle until something else + wakes it ([moq-dev/moq#6736](https://github.com/moq-dev/moq/pull/6736)). +- **mr-boxington:** the eviction found while landing + [moq-dev/moq#6709](https://github.com/moq-dev/moq/pull/6709). + +Public API: none. Wire: none. From 24a7ee94c6c3e96c1ad2123e481f080fb9f38db3 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 09:25:24 -0700 Subject: [PATCH 3/3] quest: rank the linear fill path above fetch-range, which now requires it Per #6722's decision that fetch-range waits on a linear fill path. Co-Authored-By: Claude Opus 5.5 --- quest/m1/subscribe-ranges/README.md | 2 +- quest/m1/subscribe-ranges/fetch-range.md | 10 ++++++---- quest/m1/subscribe-ranges/fill-linear.md | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/quest/m1/subscribe-ranges/README.md b/quest/m1/subscribe-ranges/README.md index e398ef20c0d..4e3f12c503e 100644 --- a/quest/m1/subscribe-ranges/README.md +++ b/quest/m1/subscribe-ranges/README.md @@ -95,12 +95,12 @@ every sequence delivered or dropped. ## Required +- [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md) - filling stays flat as range count and span grow - [Fetch as a range](/quest/m1/subscribe-ranges/fetch-range.md) - `fetch_group` becomes a one-range subscription that ends once its range is accounted for - [Lite-07 ranges](/quest/m1/subscribe-ranges/lite.md) - the lite-07 wire, Rust publisher and subscriber, and the draft - [moq-transport ranges](/quest/m1/subscribe-ranges/ietf.md) - range FETCH upstream per missing run, and non-blocking FETCH served downstream - [JS ranges](/quest/m1/subscribe-ranges/js.md) - `@moq/net` model and lite-07 parity - [Range count cost](/quest/m1/subscribe-ranges/range-cost.md) - a subscription's range count cannot multiply per-group cost -- [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md) - filling stays flat as range count and span grow ## Related diff --git a/quest/m1/subscribe-ranges/fetch-range.md b/quest/m1/subscribe-ranges/fetch-range.md index d8b0715fc9d..eb7cee90047 100644 --- a/quest/m1/subscribe-ranges/fetch-range.md +++ b/quest/m1/subscribe-ranges/fetch-range.md @@ -80,7 +80,9 @@ the questions decided below and landed only the `track_range_filling` benchmark. - **The fill path goes linear first** (maintainer, 2026-10-25). One-range reads put every past read on the fill path, which `track_range_filling` measures as superlinear in range count and span: at span 64, 215K groups/s - over 1 range, 69K over 16, and 1.9K over 256. This quest waits on the - linear fill path quest (`quest/m1/subscribe-ranges/fill-linear.md`, planned - in [moq-dev/moq#6790](https://github.com/moq-dev/moq/pull/6790)); once it is - on main, list it under Required here. + over 1 range, 69K over 16, and 1.9K over 256, so this quest waits on the + linear fill path. + +## Required + +- [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md) - filling stays flat as range count and span grow diff --git a/quest/m1/subscribe-ranges/fill-linear.md b/quest/m1/subscribe-ranges/fill-linear.md index 3b87b9f8e3c..44bb220be11 100644 --- a/quest/m1/subscribe-ranges/fill-linear.md +++ b/quest/m1/subscribe-ranges/fill-linear.md @@ -14,8 +14,8 @@ drift edge (`live_edge`) and each candidate's successor search filled group is never marked shown, so every scan passes it again. `Misses::retain` also rescans every filled group per poll. -That PR recommends landing this before -[FETCH as a range](/quest/m1/subscribe-ranges/fetch-range.md), since one-range -reads would put every past read on this path. +[FETCH as a range](/quest/m1/subscribe-ranges/fetch-range.md) waits on this +(maintainer, 2026-10-25, on #6722), since one-range reads would put every +past read on this path. Public API: none. Wire: none.