From ea9d7256c8202d4d68738cfb7b445ffc19e30ead Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 14:46:42 -0700 Subject: [PATCH 1/6] quest: plan follow-ups from the 2026-10-25 merge wave Co-Authored-By: Claude Opus 5.5 --- quest/m0/nightly/feature-shapes.md | 4 +++- quest/m1/README.md | 2 ++ quest/m1/api-audit/README.md | 1 + quest/m1/api-audit/encoded-read-bindings.md | 19 ++++++++++++++++ quest/m1/hls-log-redaction.md | 17 +++++++++++++++ quest/m1/moxygen-pin-bump.md | 24 +++++++++++++++++++++ quest/m1/ts-reliability/README.md | 1 + quest/m1/ts-reliability/export-si-order.md | 21 ++++++++++++++++++ quest/m2/README.md | 2 ++ quest/m2/hls-export-kio.md | 17 +++++++++++++++ quest/m2/reinit-retire.md | 15 +++++++++++++ quest/m2/uniffi-fork.md | 4 ++++ 12 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 quest/m1/api-audit/encoded-read-bindings.md create mode 100644 quest/m1/hls-log-redaction.md create mode 100644 quest/m1/moxygen-pin-bump.md create mode 100644 quest/m1/ts-reliability/export-si-order.md create mode 100644 quest/m2/hls-export-kio.md create mode 100644 quest/m2/reinit-retire.md diff --git a/quest/m0/nightly/feature-shapes.md b/quest/m0/nightly/feature-shapes.md index 62acbcebd97..185fee1d7e6 100644 --- a/quest/m0/nightly/feature-shapes.md +++ b/quest/m0/nightly/feature-shapes.md @@ -16,7 +16,9 @@ and now `Connection::open_request` `#[cfg(feature = "net")]`; only `quic/web/session.rs` uses it. Reproduce: `cargo clippy -p moq-tokio --all-targets --no-default-features --features driver,aws-lc-rs -- -D warnings`. -- Fix `open_request`'s gating. +- Fix `open_request`'s gating, and moq-hls `Broadcaster::poll_closed` + (`rs/moq-hls/src/export/mod.rs`), which is dead under + `--no-default-features` (found 2026-10-25). - Add the feature and profile variant check to the PR gate, scoped to the crates a branch changes the way `just check` selects them. Measure its cost in the PR. Nightly keeps the full matrix. diff --git a/quest/m1/README.md b/quest/m1/README.md index f4f9a24c5b0..ac1b44a8314 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -116,6 +116,7 @@ Catalog HLS field. - [Compressed tracks](/quest/m1/compress/README.md) - a track flagged `compress` is DEFLATEd per group by moq-net, forwarded compressed, and inflated once on the relay for peers that cannot signal it; `catalog.json.z` and moq-flate go away - [Finalize moq-lite-07](/quest/m1/lite07-finalize.md) - when the maintainer cuts it, lite-07 negotiates as `moq-lite-07` and the next release ships it - [Moxygen minimal interop](/quest/m1/smoke-moxygen.md) - waiting on Moxygen to send a registered filter type, then the smoke lane stops hiding its failure +- [Moxygen pin bump](/quest/m1/moxygen-pin-bump.md) - waiting on moxygen#264, then the TRACK_STATUS patch is dropped - [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 - [Broadcast lifecycle](/quest/m1/broadcast-lifecycle/README.md) - broadcasts are online or offline with no finished state in moq-net, finished-broadcast retention is a fixed moq-mux policy, and each linger timer has one meaning - [A smaller, safer API than release](/quest/m1/api-audit/README.md) - every surface added since release has a consumer or is gone, overlapping operations are collapsed, names mirror across Rust, JS, and the bindings, and every break says how to migrate @@ -147,6 +148,7 @@ Catalog HLS field. - [Calibrate the paired nightly benchmarks](/quest/m1/bench-ci.md) - A/A and deliberately slowed Nightly runs set the paired comparison's threshold, so its regression alerts can be trusted - [HLS takeover leak](/quest/m1/hls-takeover-leak.md) - a replaced instance's recording cursor never yields the replacement's media, and ends or fails instead of stalling - [HLS and DASH segment conformance](/quest/m1/hls-conformance.md) - nightly ffprobe checks that advertised timing, sync flags, and bytes match the media served +- [HLS import log redaction](/quest/m1/hls-log-redaction.md) - no HLS import log line carries an unredacted playlist URL - [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 ## Related diff --git a/quest/m1/api-audit/README.md b/quest/m1/api-audit/README.md index f16910977f4..5ace5b56cfe 100644 --- a/quest/m1/api-audit/README.md +++ b/quest/m1/api-audit/README.md @@ -82,6 +82,7 @@ Rejected in planning: - [moq-net exports with a consumer](/quest/m1/api-audit/net-exports.md) - the dead and test-only moq-net, `@moq/net`, and moq-ffi items the follow-up audit found go private or away - [Bindings read gaps and ends](/quest/m1/api-audit/decode-read-bindings.md) - moq-ffi and every wrapper surface `Gap` and `End` instead of discarding them - [Session-only items stay private](/quest/m1/api-audit/model-private.md) - model items only the built-in sessions use are private +- [Encoded consumers read gaps and ends](/quest/m1/api-audit/encoded-read-bindings.md) - moq-ffi, moq-c, and every wrapper read encoded media with the tagged-record shape the decoded consumers use - [One lifecycle vocabulary](/quest/m1/api-audit/lifecycle.md) - finish, abort, closed, and close mean one thing on every handle, and Rust and JS observers fire alike - [moq-net names say one thing](/quest/m1/api-audit/net-names.md) - demand says `wanted`, colliding stats and transport names are renamed, and Rust and JS info lookups mirror - [Request handlers are named requests](/quest/m1/api-audit/requests.md) - `dynamic()` and `Dynamic` become `requests()` and `Requests` at every layer diff --git a/quest/m1/api-audit/encoded-read-bindings.md b/quest/m1/api-audit/encoded-read-bindings.md new file mode 100644 index 00000000000..54bf2739c26 --- /dev/null +++ b/quest/m1/api-audit/encoded-read-bindings.md @@ -0,0 +1,19 @@ +# [M] Encoded consumers read gaps and ends + +## Goal + +The encoded media consumers in moq-ffi (`MoqMediaTrackConsumer`), moq-c's +`moq_consume_*` reads, and their wrappers surface `Gap` and `End` with the same +tagged-record read shape the decoded consumers got in +[moq-dev/moq#6745](https://github.com/moq-dev/moq/pull/6745), instead of +discarding them. + +## Plan + +Decided 2026-10-25 (maintainer, on #6745): the decoded consumers keep the +tagged-record shape as landed, and the encoded consumers follow in their own +quest. Mirror #6745 exactly: the same record names, the same end semantics, +and the same wrapper idioms in py, swift, kt, go, dart, cpp, and cpp/obs. +Update `doc/lib/*` and run `just test interop --all`. + +Public API: breaking in moq-ffi, moq-c, and every wrapper. Wire: none. diff --git a/quest/m1/hls-log-redaction.md b/quest/m1/hls-log-redaction.md new file mode 100644 index 00000000000..fea54606d17 --- /dev/null +++ b/quest/m1/hls-log-redaction.md @@ -0,0 +1,17 @@ +# [XS] HLS import logs redact URLs + +## Goal + +No HLS import log line carries an unredacted playlist or segment URL. The +"selected master playlist renditions" info line (`rs/moq-hls/src/import.rs`) +prints the audio playlist URL as given, so a signed query string reaches the +logs. [moq-dev/moq#6767](https://github.com/moq-dev/moq/pull/6767) redacted the +error paths only. + +## Plan + +Route every URL the import logs through the redaction #6767 added, and sweep +moq-hls for other `tracing` calls that format a URL. A test captures the log +line and asserts the query string is gone. + +Public API: none. Wire: none. diff --git a/quest/m1/moxygen-pin-bump.md b/quest/m1/moxygen-pin-bump.md new file mode 100644 index 00000000000..9bd2773f2e1 --- /dev/null +++ b/quest/m1/moxygen-pin-bump.md @@ -0,0 +1,24 @@ +# [XS] Moxygen pins without the TRACK_STATUS patch + +## Goal + +Waiting on upstream Moxygen. Once +[facebookexperimental/moxygen#264](https://github.com/facebookexperimental/moxygen/pull/264) +merges, `nix/moxygen.nix` pins a Moxygen that includes it, +`nix/moxygen-track-status.patch` is deleted, and the Moxygen interop and +conformance lanes still pass. + +Check moxygen#264's state. Delete this quest once the patch is gone. + +## Plan + +[moq-dev/moq#6729](https://github.com/moq-dev/moq/pull/6729) carries the patch +until upstream lands it. Upstream's client has moved to draft-20 Location +Filters, so the profile patch the pin also applies needs rebasing in the same +bump. Run `just test interop --all` and the Moxygen smoke lane. + +Public API: none. Wire: none. + +## Related + +- [Moxygen minimal interop](/quest/m1/smoke-moxygen.md) - the other upstream Moxygen fix the smoke lane waits on diff --git a/quest/m1/ts-reliability/README.md b/quest/m1/ts-reliability/README.md index 827648225b0..5c315ed61c2 100644 --- a/quest/m1/ts-reliability/README.md +++ b/quest/m1/ts-reliability/README.md @@ -100,6 +100,7 @@ catalog linger (#5305). - [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 +- [Export SI order](/quest/m1/ts-reliability/export-si-order.md) - a TS export sends SI after its PMT and a PCR interval, so a hop keeps first emissions ## Related diff --git a/quest/m1/ts-reliability/export-si-order.md b/quest/m1/ts-reliability/export-si-order.md new file mode 100644 index 00000000000..d96a2b8be04 --- /dev/null +++ b/quest/m1/ts-reliability/export-si-order.md @@ -0,0 +1,21 @@ +# [S] TS export sends SI after its PMT and PCR + +## Goal + +A TS export holds its first SI tables until the PMT and one PCR interval are +out, so an export-to-import hop keeps each table's first emission instead of +dropping it until the table repeats. + +## Plan + +Since [moq-dev/moq#6757](https://github.com/moq-dev/moq/pull/6757), TS import +admits SI only once a valid program-clock interval exists. The export writes +its first SI ahead of its PMT and PCRs, so the importer drops it. Order the +export's first output as PAT, PMT, a PCR interval, then SI. Test it with an +export-to-import round trip that sees every SI table's first emission. + +Not planned (2026-10-25, maintainer): bounding SI aging against a source that +claims a huge mux rate through valid PCR steps. That needs a program-clock +floor per input byte, a new contract. + +Public API: none. Wire: none. diff --git a/quest/m2/README.md b/quest/m2/README.md index 980e0a6e1f6..dd2b07b9830 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -31,6 +31,8 @@ lite-07; bitrate enforcement is not part of this release. - [QoS](/quest/m2/qos/README.md) - the relay's egress `lag` histogram and `dropped` counters on the stats totals and prefix tracks - [Lazy retained HLS instances](/quest/m2/hls-lazy-instances.md) - a replaced HLS instance starts its watchers only when a request reaches it - [HLS and DASH browser playback](/quest/m2/hls-player-test.md) - hls.js and dash.js play, reload, switch, and survive reconfiguration nightly +- [moq-hls export on kio](/quest/m2/hls-export-kio.md) - export watchers and the init build are owned kio tasks instead of tokio::spawn +- [Re-init retires timelines](/quest/m2/reinit-retire.md) - fMP4 and MKV re-inits retire the old timeline, so import state stays bounded - [Broadcast fairness](/quest/m2/broadcast-fairness.md) - broadcasts share a cluster link fairly, so one tenant's priority never starves another's - [Peer grant bound](/quest/m2/peer-grant-bound.md) - a peer's AUTH_OK costs near-linear time in its bytes on every input shape, in Rust and in a browser - [Plan: watch worker](/quest/m2/plan-watch-worker.md) - prototype an invisible page worker against app-spawned workers, and land the jank harness that decides diff --git a/quest/m2/hls-export-kio.md b/quest/m2/hls-export-kio.md new file mode 100644 index 00000000000..1e6b5143bf4 --- /dev/null +++ b/quest/m2/hls-export-kio.md @@ -0,0 +1,17 @@ +# [M] moq-hls export runs on kio + +## Goal + +moq-hls export's background work (the catalog, timeline, and spans watchers in +`rs/moq-hls/src/export/{mod,rendition}.rs`, and the init build) runs as +poll-driven `kio` tasks the export owns, not on `tokio::spawn`, as +`rs/AGENTS.md` prefers. + +## Plan + +Do it crate-wide in one PR. Tasks end with their owner instead of being +detached, which also removes the abort handles kept for them today. Tests +keep their own spawns where they drive a runtime. Measure export throughput +before and after with the existing moq-hls benchmarks. + +Public API: none expected. Wire: none. diff --git a/quest/m2/reinit-retire.md b/quest/m2/reinit-retire.md new file mode 100644 index 00000000000..92fa20c741d --- /dev/null +++ b/quest/m2/reinit-retire.md @@ -0,0 +1,15 @@ +# [S] fMP4 and MKV re-init retire old timelines + +## Goal + +When an fMP4 or MKV import re-initializes (a new init segment or EBML header +mid-stream), the old timeline is retired the way +[moq-dev/moq#6757](https://github.com/moq-dev/moq/pull/6757) retires an ended +TS route, so import state stays bounded across repeated re-inits. + +## Plan + +Reuse the retirement #6757 added to `rs/moq-mux/src/timeline.rs`. Test a +stream that re-inits many times and assert the import's state does not grow. + +Public API: none. Wire: none. diff --git a/quest/m2/uniffi-fork.md b/quest/m2/uniffi-fork.md index 6565f21ae2b..725d0afb4a0 100644 --- a/quest/m2/uniffi-fork.md +++ b/quest/m2/uniffi-fork.md @@ -51,6 +51,10 @@ which publishes `rust2-uniffi`, `rust2-uniffi-core`, `rust2-uniffi-macros`, and Delete `rs/uniffi-bindgen`, the "five places" comments in `flake.nix`, and the `nix/uniffi-dart-*` lockfile and patch. The `sh/{kt,swift,dart,cpp}` packaging scripts stay: they package moq. +- Negative durations (2026-10-25, maintainer): the Dart negative-duration + patch moq carries goes upstream into the fork's Dart generator, and the Go + generator stops panicking on a negative `time.Duration` (the Go wrapper + guards it today; delete the guard once the generator is fixed). - Update the quests that name a `kixelated/uniffi-*` fork ([Generated C bindings](/quest/m1/c/README.md)) to point at rust2, then archive the three forks. From e8a6f158eb74139787441ec07df1f8d64174980e Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 15:03:46 -0700 Subject: [PATCH 2/6] quest: plan the unowned 2026-10-25 Nightly failures Co-Authored-By: Claude Opus 5.5 --- quest/m0/nightly/README.md | 2 ++ quest/m0/nightly/obs-audio-candidate.md | 21 +++++++++++++++++++++ quest/m0/nightly/windows-relay-expect.md | 23 +++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 quest/m0/nightly/obs-audio-candidate.md create mode 100644 quest/m0/nightly/windows-relay-expect.md diff --git a/quest/m0/nightly/README.md b/quest/m0/nightly/README.md index cdb184f46b3..d9a938ac5ef 100644 --- a/quest/m0/nightly/README.md +++ b/quest/m0/nightly/README.md @@ -35,3 +35,5 @@ Public API: none. Wire: none. - [Feature shapes in the gate](/quest/m0/nightly/feature-shapes.md) - feature-gated dead code fails the PR that adds it, not the next Nightly - [Nightly's base in a shallow checkout](/quest/m0/nightly/shallow-base.md) - `sh/gh/nightly.test.py` passes in Nightly's depth-1 checkout +- [Windows builds moq-relay tests](/quest/m0/nightly/windows-relay-expect.md) - an unfulfilled lint expectation stops failing the Windows build +- [OBS audio-candidate test](/quest/m0/nightly/obs-audio-candidate.md) - the TSan test waits for pending_audio to clear instead of racing it diff --git a/quest/m0/nightly/obs-audio-candidate.md b/quest/m0/nightly/obs-audio-candidate.md new file mode 100644 index 00000000000..a77b268f8db --- /dev/null +++ b/quest/m0/nightly/obs-audio-candidate.md @@ -0,0 +1,21 @@ +# [XS] OBS audio-candidate test waits for its condition + +## Goal + +`cpp/obs/test/moq-source-test.cpp`'s "failed audio candidate preserves +playback" passes under OBS TSan every night. On 2026-10-25 its check +`ctx->connection->audio && !ctx->connection->pending_audio` failed with no +TSan report. + +## Plan + +The test returns once the failure counter increments, but `moq-source.cpp` +clears `pending_audio` later, so the check races the clear. Make the test +wait on the event that clears `pending_audio` (or on a "candidate dropped" +signal) instead of the counter. Do not add a retry or a sleep. Before +changing anything, rerun the TSan job once to confirm it is this race. + +Planned 2026-10-25 (maintainer) from the triage of Nightly run +[40192013303](https://github.com/moq-dev/moq/actions/runs/40192013303). + +Public API: none. Wire: none. diff --git a/quest/m0/nightly/windows-relay-expect.md b/quest/m0/nightly/windows-relay-expect.md new file mode 100644 index 00000000000..43d2ed3611d --- /dev/null +++ b/quest/m0/nightly/windows-relay-expect.md @@ -0,0 +1,23 @@ +# [XS] Windows builds moq-relay's tests + +## Goal + +Nightly's Windows job builds and runs the test suite again. Since 2026-10-25, +`cargo test --no-run` fails there with "this lint expectation is unfulfilled" +at `rs/moq-relay/src/relay.rs:871`. + +## Plan + +The module-level `#[expect(clippy::disallowed_methods)]` on moq-relay's +`mod tests` only hits on Unix, because the host-clock tests are `cfg(unix)`. +`build.warnings=deny` makes the unfulfilled expectation an error. Scope the +`expect` to the Unix-only tests, or use `cfg_attr(unix, expect(...))`. + +In the same PR, gate or remove the two moq-video items that are dead on +Windows (`pump.rs` `Read::Idle` and `from_bgra`). They warn today and will +fail the build the same way. + +Planned 2026-10-25 (maintainer) from the triage of Nightly run +[40192013303](https://github.com/moq-dev/moq/actions/runs/40192013303). + +Public API: none. Wire: none. From 3e9891997ab0d45673cfed7ea9a179270dec5fe6 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 15:16:04 -0700 Subject: [PATCH 3/6] quest: address review on the 2026-10-25 follow-ups Co-Authored-By: Claude Opus 5.5 --- quest/m1/hls-log-redaction.md | 12 +++++++----- quest/m1/moxygen-pin-bump.md | 8 +++++--- quest/m1/ts-reliability/export-si-order.md | 4 +++- quest/m2/hls-export-kio.md | 6 +++++- quest/m2/reinit-retire.md | 7 +++++-- quest/m2/uniffi-fork.md | 3 ++- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/quest/m1/hls-log-redaction.md b/quest/m1/hls-log-redaction.md index fea54606d17..b1a700b9335 100644 --- a/quest/m1/hls-log-redaction.md +++ b/quest/m1/hls-log-redaction.md @@ -2,14 +2,16 @@ ## Goal -No HLS import log line carries an unredacted playlist or segment URL. The -"selected master playlist renditions" info line (`rs/moq-hls/src/import.rs`) -prints the audio playlist URL as given, so a signed query string reaches the -logs. [moq-dev/moq#6767](https://github.com/moq-dev/moq/pull/6767) redacted the -error paths only. +No HLS import log line carries an unredacted playlist or segment URL, so a +signed query string never reaches the logs. ## Plan +The "selected master playlist renditions" info line +(`rs/moq-hls/src/import.rs`) prints the audio playlist URL as given. +[moq-dev/moq#6767](https://github.com/moq-dev/moq/pull/6767) redacted the +error paths only. + Route every URL the import logs through the redaction #6767 added, and sweep moq-hls for other `tracing` calls that format a URL. A test captures the log line and asserts the query string is gone. diff --git a/quest/m1/moxygen-pin-bump.md b/quest/m1/moxygen-pin-bump.md index 9bd2773f2e1..f229aae2654 100644 --- a/quest/m1/moxygen-pin-bump.md +++ b/quest/m1/moxygen-pin-bump.md @@ -8,12 +8,14 @@ merges, `nix/moxygen.nix` pins a Moxygen that includes it, `nix/moxygen-track-status.patch` is deleted, and the Moxygen interop and conformance lanes still pass. -Check moxygen#264's state. Delete this quest once the patch is gone. +Check moxygen#264's state. Delete this quest once the patch is gone, or if +moxygen#264 lands before the patch reaches `main`. ## Plan -[moq-dev/moq#6729](https://github.com/moq-dev/moq/pull/6729) carries the patch -until upstream lands it. Upstream's client has moved to draft-20 Location +The patch is not on `main` yet: +[moq-dev/moq#6729](https://github.com/moq-dev/moq/pull/6729), still open, adds +it to `nix/moxygen.nix`'s `patches` and carries it until upstream lands it. Upstream's client has moved to draft-20 Location Filters, so the profile patch the pin also applies needs rebasing in the same bump. Run `just test interop --all` and the Moxygen smoke lane. diff --git a/quest/m1/ts-reliability/export-si-order.md b/quest/m1/ts-reliability/export-si-order.md index d96a2b8be04..2c952959ee9 100644 --- a/quest/m1/ts-reliability/export-si-order.md +++ b/quest/m1/ts-reliability/export-si-order.md @@ -11,7 +11,9 @@ dropping it until the table repeats. Since [moq-dev/moq#6757](https://github.com/moq-dev/moq/pull/6757), TS import admits SI only once a valid program-clock interval exists. The export writes its first SI ahead of its PMT and PCRs, so the importer drops it. Order the -export's first output as PAT, PMT, a PCR interval, then SI. Test it with an +export's first output as PAT, PMT, a PCR interval, then SI. A PCR interval +here is what `si.rs` needs to place a section: one forward PCR step of at most +`MAX_INTERVAL`, not the importer's two-second catalog window. Test it with an export-to-import round trip that sees every SI table's first emission. Not planned (2026-10-25, maintainer): bounding SI aging against a source that diff --git a/quest/m2/hls-export-kio.md b/quest/m2/hls-export-kio.md index 1e6b5143bf4..7b02ad30530 100644 --- a/quest/m2/hls-export-kio.md +++ b/quest/m2/hls-export-kio.md @@ -10,7 +10,11 @@ poll-driven `kio` tasks the export owns, not on `tokio::spawn`, as ## Plan Do it crate-wide in one PR. Tasks end with their owner instead of being -detached, which also removes the abort handles kept for them today. Tests +detached, which also removes the abort handles kept for them today. Keep the +timeline watcher's two lifetime rules: a new reference timeline replaces the +old watcher, and a recording cursor that outlives the `Broadcaster` keeps the +watcher running until the timeline ends (see `Broadcaster`'s `Drop`). Test +both. Tests keep their own spawns where they drive a runtime. Measure export throughput before and after with the existing moq-hls benchmarks. diff --git a/quest/m2/reinit-retire.md b/quest/m2/reinit-retire.md index 92fa20c741d..6fe97d085d0 100644 --- a/quest/m2/reinit-retire.md +++ b/quest/m2/reinit-retire.md @@ -9,7 +9,10 @@ TS route, so import state stays bounded across repeated re-inits. ## Plan -Reuse the retirement #6757 added to `rs/moq-mux/src/timeline.rs`. Test a -stream that re-inits many times and assert the import's state does not grow. +Reuse the retirement #6757 added to `rs/moq-mux/src/timeline.rs`. +`Timelines::retire` refuses a timeline whose recorder is still live, so each +re-init finishes and drops the old recorder before retiring, as the TS route +end does. Test a stream that re-inits many times and assert the import's state +does not grow. Public API: none. Wire: none. diff --git a/quest/m2/uniffi-fork.md b/quest/m2/uniffi-fork.md index 725d0afb4a0..50de6b6bc0f 100644 --- a/quest/m2/uniffi-fork.md +++ b/quest/m2/uniffi-fork.md @@ -54,7 +54,8 @@ which publishes `rust2-uniffi`, `rust2-uniffi-core`, `rust2-uniffi-macros`, and - Negative durations (2026-10-25, maintainer): the Dart negative-duration patch moq carries goes upstream into the fork's Dart generator, and the Go generator stops panicking on a negative `time.Duration` (the Go wrapper - guards it today; delete the guard once the generator is fixed). + guards it today; delete the guard in the PR that pins a generator with the + fix, with a test passing a negative duration through the Go binding). - Update the quests that name a `kixelated/uniffi-*` fork ([Generated C bindings](/quest/m1/c/README.md)) to point at rust2, then archive the three forks. From 690fd718b16320bf6755c8c622e4e9461f82b4c2 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 15:45:03 -0700 Subject: [PATCH 4/6] quest: OBS audio-candidate quest starts from a reproduction Co-Authored-By: Claude Opus 5.5 --- quest/m0/nightly/README.md | 2 +- quest/m0/nightly/obs-audio-candidate.md | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/quest/m0/nightly/README.md b/quest/m0/nightly/README.md index c29d815a912..98b54f7ec72 100644 --- a/quest/m0/nightly/README.md +++ b/quest/m0/nightly/README.md @@ -35,5 +35,5 @@ Public API: none. Wire: none. - [Nightly's base in a shallow checkout](/quest/m0/nightly/shallow-base.md) - `sh/gh/nightly.test.py` passes in Nightly's depth-1 checkout - [Windows builds moq-relay tests](/quest/m0/nightly/windows-relay-expect.md) - an unfulfilled lint expectation stops failing the Windows build -- [OBS audio-candidate test](/quest/m0/nightly/obs-audio-candidate.md) - the TSan test waits for pending_audio to clear instead of racing it +- [OBS audio-candidate test](/quest/m0/nightly/obs-audio-candidate.md) - the failed audio candidate check passes under TSan, fixed at its reproduced cause - [moq-hls without default features](/quest/m0/nightly/hls-poll-closed.md) - `Broadcaster::poll_closed` is gated with its only caller, so the no-default-features build stops warning diff --git a/quest/m0/nightly/obs-audio-candidate.md b/quest/m0/nightly/obs-audio-candidate.md index a77b268f8db..ff694d1ef69 100644 --- a/quest/m0/nightly/obs-audio-candidate.md +++ b/quest/m0/nightly/obs-audio-candidate.md @@ -1,4 +1,4 @@ -# [XS] OBS audio-candidate test waits for its condition +# [S] OBS audio-candidate test passes under TSan ## Goal @@ -9,11 +9,14 @@ TSan report. ## Plan -The test returns once the failure counter increments, but `moq-source.cpp` -clears `pending_audio` later, so the check races the clear. Make the test -wait on the event that clears `pending_audio` (or on a "candidate dropped" -signal) instead of the counter. Do not add a retry or a sleep. Before -changing anything, rerun the TSan job once to confirm it is this race. +The cause is not known yet. It is not the counter racing the clear: the +"Audio track error" log that bumps `g_candidate_failures` and the +`pending_audio` clear both run under `ctx->mutex`, which the check then takes. +But the counter is global, also bumped by any "Failed to resolve" or "Failed +to subscribe", and the check also needs the active `audio` to survive. +Reproduce under TSan first, find which conjunct fails and which track and +error bumped the counter, then fix that cause. If the wait is too broad, make +it wait on the replacement's own failure. Do not add a retry or a sleep. Planned 2026-10-25 (maintainer) from the triage of Nightly run [40192013303](https://github.com/moq-dev/moq/actions/runs/40192013303). From ecbfb19f3812cf31e2666b2166fd049ba028e8a3 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 15:46:21 -0700 Subject: [PATCH 5/6] quest: fold the duplicate OBS audio-candidate quest into m0/nightly Co-Authored-By: Claude Opus 5.5 --- quest/m0/nightly/README.md | 2 +- quest/m0/nightly/obs-audio-candidate.md | 15 +++++++++------ quest/m1/test-flakes-2/README.md | 1 - quest/m1/test-flakes-2/obs-audio-candidate.md | 16 ---------------- 4 files changed, 10 insertions(+), 24 deletions(-) delete mode 100644 quest/m1/test-flakes-2/obs-audio-candidate.md diff --git a/quest/m0/nightly/README.md b/quest/m0/nightly/README.md index 98b54f7ec72..fabf039aaef 100644 --- a/quest/m0/nightly/README.md +++ b/quest/m0/nightly/README.md @@ -35,5 +35,5 @@ Public API: none. Wire: none. - [Nightly's base in a shallow checkout](/quest/m0/nightly/shallow-base.md) - `sh/gh/nightly.test.py` passes in Nightly's depth-1 checkout - [Windows builds moq-relay tests](/quest/m0/nightly/windows-relay-expect.md) - an unfulfilled lint expectation stops failing the Windows build -- [OBS audio-candidate test](/quest/m0/nightly/obs-audio-candidate.md) - the failed audio candidate check passes under TSan, fixed at its reproduced cause +- [OBS audio-candidate test](/quest/m0/nightly/obs-audio-candidate.md) - the failed audio candidate check passes under TSan and load, fixed at its reproduced cause - [moq-hls without default features](/quest/m0/nightly/hls-poll-closed.md) - `Broadcaster::poll_closed` is gated with its only caller, so the no-default-features build stops warning diff --git a/quest/m0/nightly/obs-audio-candidate.md b/quest/m0/nightly/obs-audio-candidate.md index ff694d1ef69..4ec248b3176 100644 --- a/quest/m0/nightly/obs-audio-candidate.md +++ b/quest/m0/nightly/obs-audio-candidate.md @@ -1,11 +1,12 @@ -# [S] OBS audio-candidate test passes under TSan +# [S] OBS audio-candidate test passes under TSan and load ## Goal `cpp/obs/test/moq-source-test.cpp`'s "failed audio candidate preserves -playback" passes under OBS TSan every night. On 2026-10-25 its check +playback" passes under OBS TSan every night and under load. On 2026-10-25 its check `ctx->connection->audio && !ctx->connection->pending_audio` failed with no -TSan report. +TSan report. [moq-dev/moq#6711](https://github.com/moq-dev/moq/pull/6711) also +saw it fail intermittently under load, on its base commit too. ## Plan @@ -14,9 +15,11 @@ The cause is not known yet. It is not the counter racing the clear: the `pending_audio` clear both run under `ctx->mutex`, which the check then takes. But the counter is global, also bumped by any "Failed to resolve" or "Failed to subscribe", and the check also needs the active `audio` to survive. -Reproduce under TSan first, find which conjunct fails and which track and -error bumped the counter, then fix that cause. If the wait is too broad, make -it wait on the replacement's own failure. Do not add a retry or a sleep. +Reproduce first, under TSan or under CPU pressure or `SIGSTOP`/`SIGCONT` +pauses as [moq-dev/moq#6737](https://github.com/moq-dev/moq/pull/6737) did. +Find which conjunct fails and which track and error bumped the counter, then +fix that cause. If the wait is too broad, make it wait on the replacement's +own failure. Do not add a retry or a sleep. Planned 2026-10-25 (maintainer) from the triage of Nightly run [40192013303](https://github.com/moq-dev/moq/actions/runs/40192013303). diff --git a/quest/m1/test-flakes-2/README.md b/quest/m1/test-flakes-2/README.md index 6d602c79883..56635bcb105 100644 --- a/quest/m1/test-flakes-2/README.md +++ b/quest/m1/test-flakes-2/README.md @@ -43,4 +43,3 @@ Public API: none. Wire: none. - [Media resource instrumentation](/quest/m1/test-flakes-2/resource-instrumentation.md) - the media test stops seeing a playing player report nothing to release - [IETF22 fallback](/quest/m1/test-flakes-2/ietf22-fallback.md) - an IETF22 browser viewer follows a fallback within the media lane's bound, keeping its session and its audio - [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 deleted file mode 100644 index 2d2b681aea9..00000000000 --- a/quest/m1/test-flakes-2/obs-audio-candidate.md +++ /dev/null @@ -1,16 +0,0 @@ -# [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. From c8063ec04ffe68662e9a33e60f1eb0bd78839152 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 15:52:33 -0700 Subject: [PATCH 6/6] quest: poll_closed quest also checks feature shapes per crate Co-Authored-By: Claude Opus 5.5 --- quest/m0/nightly/README.md | 2 +- quest/m0/nightly/hls-poll-closed-gate.md | 24 ++++++++++++++++++++++++ quest/m0/nightly/hls-poll-closed.md | 17 ----------------- 3 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 quest/m0/nightly/hls-poll-closed-gate.md delete mode 100644 quest/m0/nightly/hls-poll-closed.md diff --git a/quest/m0/nightly/README.md b/quest/m0/nightly/README.md index fabf039aaef..7d92e95af8b 100644 --- a/quest/m0/nightly/README.md +++ b/quest/m0/nightly/README.md @@ -36,4 +36,4 @@ Public API: none. Wire: none. - [Nightly's base in a shallow checkout](/quest/m0/nightly/shallow-base.md) - `sh/gh/nightly.test.py` passes in Nightly's depth-1 checkout - [Windows builds moq-relay tests](/quest/m0/nightly/windows-relay-expect.md) - an unfulfilled lint expectation stops failing the Windows build - [OBS audio-candidate test](/quest/m0/nightly/obs-audio-candidate.md) - the failed audio candidate check passes under TSan and load, fixed at its reproduced cause -- [moq-hls without default features](/quest/m0/nightly/hls-poll-closed.md) - `Broadcaster::poll_closed` is gated with its only caller, so the no-default-features build stops warning +- [Feature shapes per crate](/quest/m0/nightly/hls-poll-closed-gate.md) - moq-hls `Broadcaster::poll_closed` is gated on `server`, and the gate checks each crate's feature shapes in isolation diff --git a/quest/m0/nightly/hls-poll-closed-gate.md b/quest/m0/nightly/hls-poll-closed-gate.md new file mode 100644 index 00000000000..3da81666b7e --- /dev/null +++ b/quest/m0/nightly/hls-poll-closed-gate.md @@ -0,0 +1,24 @@ +# [XS] Feature shapes are checked per crate + +## Goal + +`cargo check -p moq-hls --no-default-features --all-targets` passes with +warnings denied, and the PR gate checks each selected crate's feature shapes +in isolation, so dead code behind a feature fails the PR that adds it. + +## Plan + +moq-hls `Broadcaster::poll_closed` (`rs/moq-hls/src/export/mod.rs:164`) is +dead under `--no-default-features`: its only caller is the `server` feature's +eviction loop. Gate it with `#[cfg(feature = "server")]`. + +Neither the gate from +[moq-dev/moq#6703](https://github.com/moq-dev/moq/pull/6703) nor Nightly +catches it: workspace feature unification turns `server` on, because moq-cli +depends on moq-hls with it. Only an isolated moq-hls build shows the warning. +Make the gate build each selected crate's feature shapes on its own (`-p` per +crate, not one unified build), and measure the added cost in the PR. + +Found 2026-10-25 for the feature-shapes quest, which #6703 finished first. + +Public API: none. Wire: none. diff --git a/quest/m0/nightly/hls-poll-closed.md b/quest/m0/nightly/hls-poll-closed.md deleted file mode 100644 index 7f76d5c04c5..00000000000 --- a/quest/m0/nightly/hls-poll-closed.md +++ /dev/null @@ -1,17 +0,0 @@ -# [XS] moq-hls builds without default features - -## Goal - -`cargo check -p moq-hls --no-default-features --all-targets` passes with -warnings denied. Today moq-hls `Broadcaster::poll_closed` -(`rs/moq-hls/src/export/mod.rs`) is dead under `--no-default-features`: its -only caller is the `server` feature's eviction loop. - -## Plan - -Gate `poll_closed` on the `server` feature, or move it next to its caller. -Found 2026-10-25 for the feature-shapes quest, which -[moq-dev/moq#6703](https://github.com/moq-dev/moq/pull/6703) finished before it -could carry this fix. - -Public API: none. Wire: none.