diff --git a/quest/m0/nightly/README.md b/quest/m0/nightly/README.md index 01e0d4c9971..058fab6dc8c 100644 --- a/quest/m0/nightly/README.md +++ b/quest/m0/nightly/README.md @@ -38,3 +38,4 @@ Public API: none. Wire: none. - [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 - [moq-relay tests build without default features](/quest/m0/nightly/relay-tests-features.md) - the integration tests gate their websocket and unix-socket fields on the features that define them - [qmux builds clean for iOS](/quest/m0/nightly/qmux-ios-dead-code.md) - `TcpStats` is gated to the platforms that implement it, so the iOS simulator build has no dead code +- [Probe against Cubic](/quest/m0/nightly/competing-cubic.md) - the `competing_cubic` probe test stops resending a stream after its reset diff --git a/quest/m0/nightly/competing-cubic.md b/quest/m0/nightly/competing-cubic.md new file mode 100644 index 00000000000..d1dea8a1a24 --- /dev/null +++ b/quest/m0/nightly/competing-cubic.md @@ -0,0 +1,17 @@ +# [S] Probe against Cubic passes + +## Goal + +`tests::probe::competing_cubic` in `rs/moq-quic/src/tests/probe.rs`, run by +Nightly through `just rs quic-sim`, passes on `main`, fixed at its cause. + +## Plan + +[moq-dev/moq#6719](https://github.com/moq-dev/moq/pull/6719) found it failing +the same way on `main` and on its branch: a probe resends a stream after that +stream was reset. A reset stream's data is never retransmitted, so find which +path still queues it (probe padding, a loss-recovery retransmit, or a stale +send queue entry) and stop it there. The other probe tests in the release +suite pass, so the fix must keep them passing. + +Public API: none. Wire: none. diff --git a/quest/m1/api-audit/README.md b/quest/m1/api-audit/README.md index f1e5976e555..70464eaa864 100644 --- a/quest/m1/api-audit/README.md +++ b/quest/m1/api-audit/README.md @@ -80,6 +80,7 @@ Rejected in planning: - [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 +- [One meaning for Credential](/quest/m1/api-audit/dial-credential.md) - the internal dial type gets its own name in JS and moq-tokio, and the `Presented` alias goes ## Related diff --git a/quest/m1/api-audit/dial-credential.md b/quest/m1/api-audit/dial-credential.md new file mode 100644 index 00000000000..13bb972b7fc --- /dev/null +++ b/quest/m1/api-audit/dial-credential.md @@ -0,0 +1,17 @@ +# [XS] One meaning for Credential + +## Goal + +`Credential` means only the public `auth::Credential`. The internal type +for what one dial presents, in `js/net/src/connection/tokens.ts` and moq-tokio's +`connect/token.rs`, gets its own name, and the `Presented` import alias in +`tokens.ts` goes away. + +## Plan + +[moq-dev/moq#6751](https://github.com/moq-dev/moq/pull/6751) renamed the +public `Auth` to `Credential`, which collides with these internal types. +Pick a name by role (such as `Presentation`) and use it in both languages. +Both types are internal, so nothing public changes. + +Public API: none. Wire: none. diff --git a/quest/m1/drop-set.md b/quest/m1/drop-set.md index b09654ef7f0..7f185afe8d1 100644 --- a/quest/m1/drop-set.md +++ b/quest/m1/drop-set.md @@ -264,6 +264,15 @@ run array once for the track and once per sink (`track.ts:914`). The replacement keeps the per-cursor walk incremental in both languages, with a benchmark swept over runs and readers. +### Idle START unreport test + +[moq-dev/moq#6717](https://github.com/moq-dev/moq/pull/6717) made the JS lite +publisher unreport stale skips below an idle SUBSCRIBE_START, so a later +widening can re-offer them as Rust does, but landed it without a test: the +case needs an update to arrive between START and the first group. Cover it +deterministically, through the track hooks rather than wire timing, when the +drop runs are reworked here. + ## Related - [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - fills the cache miss an evicted run leaves diff --git a/quest/m1/js-api-reference.md b/quest/m1/js-api-reference.md index 3f1643554e8..6dda392612e 100644 --- a/quest/m1/js-api-reference.md +++ b/quest/m1/js-api-reference.md @@ -23,6 +23,10 @@ Decided 2026-10-23 (maintainer interview): matches the guides beside it. Nothing generated is committed. - JSR keeps publishing its own reference; this does not replace it. - Rust is a non-goal: docs.rs covers it. +- The link resolver (`nameableReference` from + [moq-dev/moq#6794](https://github.com/moq-dev/moq/pull/6794)) gets fixtures + for a hidden and an exported declaration sharing a name, and for chains of + aliases. ## Required diff --git a/quest/m1/pure-crypto/README.md b/quest/m1/pure-crypto/README.md index de948835495..a730ed081c1 100644 --- a/quest/m1/pure-crypto/README.md +++ b/quest/m1/pure-crypto/README.md @@ -38,3 +38,4 @@ picks a random one, and jsonwebtoken 11 already takes a custom - [ACME on graviola](/quest/m1/pure-crypto/acme-upstream.md) - graviola builds turn ACME back on once rustls-acme gains a provider hook or instant-acme 0.9 is released - [rustls-graviola's QUIC keys](/quest/m1/pure-crypto/graviola-quic.md) - a rustls-graviola release ships QUIC keys, and moq-quic's adapter is deleted - [The next graviola release](/quest/m1/pure-crypto/graviola-release.md) - moq pins a graviola with ECDSA key generation and faster ChaCha20-Poly1305, drops RustCrypto's `p256`, and re-measures the ChaCha20 gap +- [graviola's own CPU check](/quest/m1/pure-crypto/graviola-cpu-check.md) - waiting on ctz/graviola#227; the relay then calls graviola's check instead of mirroring its list diff --git a/quest/m1/pure-crypto/graviola-cpu-check.md b/quest/m1/pure-crypto/graviola-cpu-check.md new file mode 100644 index 00000000000..54f1f5865c0 --- /dev/null +++ b/quest/m1/pure-crypto/graviola-cpu-check.md @@ -0,0 +1,18 @@ +# [XS] graviola's own CPU check + +## Goal + +Once a graviola release ships a public CPU feature check +([ctz/graviola#227](https://github.com/ctz/graviola/issues/227)), moq-relay +calls it at startup instead of mirroring graviola's mandatory feature list. +Check the issue and graviola's changelog; until it ships, this quest waits. +The startup error still names the missing feature, as relay-graviola +decided, so a check that answers only yes or no does not replace the mirror. + +## Plan + +[moq-relay on graviola](/quest/m1/pure-crypto/relay-graviola.md) mirrors the +list because no public check exists. If the check ships before that quest +lands, that quest uses it and this one is deleted. + +Public API: none. Wire: none. diff --git a/quest/m1/test-flakes-2/README.md b/quest/m1/test-flakes-2/README.md index 54ca836172f..0d3337fff4b 100644 --- a/quest/m1/test-flakes-2/README.md +++ b/quest/m1/test-flakes-2/README.md @@ -47,3 +47,5 @@ Public API: none. Wire: none. - [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 - [Stuck-window eviction test on macOS](/quest/m1/test-flakes-2/stuck-window-evicts.md) - the evicted writer reliably sees its stop on macOS, fixed at the race +- [Swapped Rust to JS Opus](/quest/m1/test-flakes-2/swapped-js-opus.md) - the `rust-swapped -> js` interop cell stops timing out under load +- [Interop loads moq-gst](/quest/m1/test-flakes-2/gst-plugin-load.md) - the interop gst cells always find the local plugin diff --git a/quest/m1/test-flakes-2/gst-plugin-load.md b/quest/m1/test-flakes-2/gst-plugin-load.md new file mode 100644 index 00000000000..a5d6fb382bb --- /dev/null +++ b/quest/m1/test-flakes-2/gst-plugin-load.md @@ -0,0 +1,17 @@ +# [S] Interop loads the local moq-gst plugin + +## Goal + +The interop `gst` cells find the locally built moq-gst plugin on every run, +instead of sometimes failing with "moqsrc not exposed" (the check near +`test/interop/interop.sh:780`), fixed at its cause. + +## Plan + +Seen in [moq-dev/moq#6745](https://github.com/moq-dev/moq/pull/6745)'s +`just test interop --all` runs: one of two runs failed to load the plugin, and +the other passed. Find whether the plugin build, the registry cache +(`GST_REGISTRY`), or `GST_PLUGIN_PATH` races between cells, and make the +harness load the plugin deterministically. + +Public API: none. Wire: none. diff --git a/quest/m1/test-flakes-2/swapped-js-opus.md b/quest/m1/test-flakes-2/swapped-js-opus.md new file mode 100644 index 00000000000..ef0eb042a2c --- /dev/null +++ b/quest/m1/test-flakes-2/swapped-js-opus.md @@ -0,0 +1,16 @@ +# [S] Swapped Rust publisher to JS Opus in interop + +## Goal + +The `rust-swapped -> js` interop cell stops timing out on its Opus check +under local load, fixed at its cause. + +## Plan + +Seen in [moq-dev/moq#6745](https://github.com/moq-dev/moq/pull/6745)'s +`just test interop --all` runs: one of two runs timed out on this cell, and +the other passed. Reproduce under a loaded machine and find whether the JS +subscriber never receives the Opus track, receives it late, or decodes it and +misses the check. + +Public API: none. Wire: none. diff --git a/quest/m1/ts-reliability/README.md b/quest/m1/ts-reliability/README.md index 09f5351f16c..e57b61e455f 100644 --- a/quest/m1/ts-reliability/README.md +++ b/quest/m1/ts-reliability/README.md @@ -100,7 +100,7 @@ catalog linger (#5305). - [PAT changes](/quest/m1/ts-reliability/pat-lifecycle.md) - a revised PAT never leaves a broadcast meaning another program - [TS workflow passes](/quest/m1/ts-reliability/validation-green.md) - the scheduled TS lanes pass on main again, with no lane loosened -- [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 +- [Export SI order](/quest/m1/ts-reliability/export-si-order.md) - a TS export sends SI and media 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 index 2c952959ee9..a5a2026e83f 100644 --- a/quest/m1/ts-reliability/export-si-order.md +++ b/quest/m1/ts-reliability/export-si-order.md @@ -1,9 +1,9 @@ -# [S] TS export sends SI after its PMT and PCR +# [S] TS export leads with 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 +A TS export holds its first SI tables and media 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 @@ -16,6 +16,10 @@ 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. +The first media PES also waits for that PCR, so a reader of our own export +never sees media it cannot place. The round trip also checks that the first +PES follows the PCR and is imported. + 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. diff --git a/quest/m1/unbounded-groups/byte-holes.md b/quest/m1/unbounded-groups/byte-holes.md index 4dce6b4d1bd..7042a6563d1 100644 --- a/quest/m1/unbounded-groups/byte-holes.md +++ b/quest/m1/unbounded-groups/byte-holes.md @@ -39,10 +39,15 @@ See the [epic](/quest/m1/unbounded-groups/README.md) for the decisions. - Update `drafts/draft-lcurley-moq-lite.md` and run `just drafts check`. Also drop the 32 MiB interop cap in `drafts/draft-lcurley-moq-e2ee.md` if it no longer follows from a model limit. +- Rust readers get a chunked payload read, so a frame larger than memory + never has to be collected whole. [moq-dev/moq#6628](https://github.com/moq-dev/moq/pull/6628) + kept its segments internal; the JS half is in + [JS](/quest/m1/unbounded-groups/js.md). - Test a frame several times the pool size through a relay chain: a late joiner reads it whole, and memory stays near the pool size. -Public API: `Position` gains a byte field, and `MAX_CACHE_BYTES` is removed. +Public API: `Position` gains a byte field, frames gain a chunked read, and +`MAX_CACHE_BYTES` is removed. Wire: a byte offset on the next lite version's range ends and group header. ## Required diff --git a/quest/m2/README.md b/quest/m2/README.md index d6056522bbe..3442614afba 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -240,3 +240,4 @@ lite-07; bitrate enforcement is not part of this release. - [No MOQ_* knobs outside the binaries](/quest/m2/env-knobs.md) - test, bench, and library knobs leave the `MOQ_*` prefix - [Clean ALSA playback onset](/quest/m2/audio-alsa-onset.md) - no onset restarts or clicks over PulseAudio - [Interop audit](/quest/m2/audit-interop.md) - our interop runner entries match what we ship, and every red interop cell with a moq.dev side is fixed, reported, or noted as down or unsupported +- [Open-GOP MPEG-2 export](/quest/m2/mpeg2-open-gop-export.md) - a TS export resuming in an open GOP trims the B-pictures that reference the previous one diff --git a/quest/m2/e2ee/README.md b/quest/m2/e2ee/README.md index 0ca06bc4194..6fa23b6d5ae 100644 --- a/quest/m2/e2ee/README.md +++ b/quest/m2/e2ee/README.md @@ -57,6 +57,10 @@ Rejected: The broadcast wrappers merged in [#5876](https://github.com/moq-dev/moq/pull/5876) with `reserve_track`, which still serves declared names; [rust-publish](/quest/m2/e2ee/rust-publish.md) needs nothing more (maintainer, 2026-10-19). +Before `@moq/e2ee` is first published, add its entrypoints to the API +Extractor declaration checks, which analyze only published packages since +[moq-dev/moq#6794](https://github.com/moq-dev/moq/pull/6794). + ## Required - [Undeclared track names](/quest/m2/e2ee/undeclared-names.md) - an encrypted diff --git a/quest/m2/mpeg2-open-gop-export.md b/quest/m2/mpeg2-open-gop-export.md new file mode 100644 index 00000000000..30a2f12fc35 --- /dev/null +++ b/quest/m2/mpeg2-open-gop-export.md @@ -0,0 +1,21 @@ +# [S] Open-GOP MPEG-2 export trims leading B-pictures + +## Goal + +When a TS export starts or resumes at an MPEG-2 sequence header in an open +GOP, it drops the leading B-pictures that reference the previous GOP and +counts them as `trimmed` or `dropped`, as it already does for codecs whose +frames carry presentation time. + +## Plan + +Found while landing [moq-dev/moq#6252](https://github.com/moq-dev/moq/pull/6252): +whole-PES MPEG-2 frames carry their placement time, not their presentation +time, so the leading-picture check cannot apply. A GOP header with +`closed_gop` unset marks an open GOP; its leading pictures are the B-pictures +(picture coding type) whose temporal reference precedes the I-picture's. +`broken_link` is the encoder's own flag for an edited stream, not the trigger. +Cover it with an MPEG-2 open-GOP arm in `recovery_test.rs`, graded like the +H.264 `Open` arm. Low priority: decoders usually skip these B-pictures. + +Public API: none. Wire: none. diff --git a/quest/m2/p2p/README.md b/quest/m2/p2p/README.md index fcd23b43442..66e17539243 100644 --- a/quest/m2/p2p/README.md +++ b/quest/m2/p2p/README.md @@ -150,6 +150,10 @@ Backend choice does not change the policy that watching tabs never re-serve. - Symmetric NATs on both ends fail ICE without TURN. By design the relay keeps serving. +Before `@moq/p2p` is first published, add its entrypoints to the API +Extractor declaration checks, which analyze only published packages since +[moq-dev/moq#6794](https://github.com/moq-dev/moq/pull/6794). + ## Required - [Peer grants](/quest/m2/p2p/peer-grant.md) - the relay issues a key-bound, asymmetrically signed grant a browser can verify; HS256 keys issue none diff --git a/quest/m2/release/c-retire.md b/quest/m2/release/c-retire.md index 1c02587a92f..e1c4ae19573 100644 --- a/quest/m2/release/c-retire.md +++ b/quest/m2/release/c-retire.md @@ -13,6 +13,11 @@ served it are deleted once the generated `moq-c` publishes. The generated - Decided 2026-10-20 (maintainer): no final hand-written notice release, because the hand-written `moq-c` never published to a registry; the generated package is the first `moq-c` users install. +- `rs/moq-c/native-libs/` serves the generated package too, and + `cpp/moq/cmake/moq-ffi.cmake` serves both C++ and C. Move them to a neutral + home shared by both packages before deleting the crate, update every + reader of either path (`rg 'moq-c/native-libs|moq-ffi\.cmake'`), and check + that the installed C and C++ CMake configs still link the native libraries. - The code-free `rs/libmoq` stub left under the old name is [Retire the libmoq stub](/quest/m2/release/libmoq-retire.md)'s, separately.