Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions quest/m0/ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ The historical samples locate candidates; they are not controlled benchmarks.
- [Verify the Nix cache](/quest/m0/ci/nix-cache-verify.md) - confirm releases use `nix.moq.dev`, check its bucket sizes, and retire Cachix
- [Unify dependency features](/quest/m0/ci/hakari.md) - align the FFI builds' features and record the hosted platform jobs' hits once the workspace-hack lands
- [Release credentials off main](/quest/m0/ci/publish-release-only.md) - `publish` admits only `release` and release tags once its `workflow_run` publishers run on their tag
- [Binary release publishers run on their tag](/quest/m0/ci/release-tag-publishers.md) - brew, Go and Swift releases stop running through `workflow_run` on main
- [The queue host keeps the queue's disk](/quest/m0/ci/queue-host-disk.md) - agent sessions can't starve the queue runner of disk, and a crashed runner restarts
- [Biome checks every file it can parse](/quest/m0/ci/biome-whole-repo.md) - Biome runs over the whole repository and main is clean under it
- [One nextest pin](/quest/m0/ci/nextest-pin.md) - cargo-nextest's version lives in one place
- [The flake lane skips hosts that can't map user namespaces](/quest/m0/ci/userns-uid-map.md) - `check flake` skips instead of failing where `/proc/self/uid_map` is unwritable
17 changes: 17 additions & 0 deletions quest/m0/ci/release-tag-publishers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# [S] Binary release publishers run on their tag

## Goal

`release-brew`, `release-go` and `release-swift-lib` run as their release tag,
not through `workflow_run` on `main`, like the publishers
[Release credentials off main](/quest/m0/ci/publish-release-only.md) moves.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run), from [moq-dev/moq#7431](https://github.com/moq-dev/moq/pull/7431). They use
the `bot` Environment today, which admits `main`; moving them needs `bot` to
admit the binary release tags, a maintainer action to list in the PR.

## Required

- [Release credentials off main](/quest/m0/ci/publish-release-only.md) - the same move for the `publish` jobs lands first
15 changes: 15 additions & 0 deletions quest/m0/ci/userns-uid-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# [XS] The flake lane skips hosts that can't map user namespaces

## Goal

`check flake` skips with a clear note, instead of failing, on a host whose
sandbox can't write `/proc/self/uid_map`, as it already does when user
namespaces are unavailable.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run), from [moq-dev/moq#7461](https://github.com/moq-dev/moq/pull/7461), whose
local gate failed `check flake` building nixpkgs' `github-runner` with
`unshare: write failed /proc/self/uid_map`. `MOQ_USERNS_UNAVAILABLE` in
`sh/dispatch.sh` does not catch this case; probe the write itself. CI hosts
that can map namespaces must still run the lane.
1 change: 1 addition & 0 deletions quest/m0/test-flakes-2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,4 @@ Public API: none. Wire: none.
- [moq-tokio's close-drain test survives load](/quest/m0/test-flakes-2/tokio-close-drain.md) - `quic_client_close_drains_finished_track` stops failing land batches with "Unroutable"
- [@moq/net's close-drain tests survive load](/quest/m0/test-flakes-2/js-close-drain.md) - the lite close-drain cases pass on every full suite run
- [@moq/net's boundary-sync test survives load](/quest/m0/test-flakes-2/js-boundary-sync.md) - "a version without a boundary syncs" passes under load
- [moq-c's gated callback test frees nothing early](/quest/m0/test-flakes-2/moq-c-gated-callback.md) - the moq-c tests stop aborting with a use-after-free under load
29 changes: 29 additions & 0 deletions quest/m0/test-flakes-2/moq-c-gated-callback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# [XS] moq-c's gated callback test frees nothing early

## Goal

`rs/moq-c/src/test.rs`'s `gated_callback` never touches `user_data` after the
test may have dropped it, so the moq-c tests stop aborting under load with
`corrupted size vs. prev_size` (SIGABRT). The fix is at the cause, never a
retry or a sleep.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run), from the SIGABRT in
[moq-dev/moq#7461](https://github.com/moq-dev/moq/pull/7461)'s Check run
(`moq-c test::follow_delivers_the_instance_again_after_an_end`).

- Cause: `gated_callback` sends `code` and only then locks `gate.hold`.
Cancelling the follow is asynchronous, so after the terminal `0` arrives the
test drops `gate` while the callback thread may still reach the freed
`Box<Gate>`. The API guarantees `user_data` only until the terminal callback
(`rs/moq-c/src/api.rs`, around line 2384). Introduced by
[moq-dev/moq#5886](https://github.com/moq-dev/moq/pull/5886).
- Fix: take `gate.hold` before `gate.tx.send(code)`, so the test cannot free
the gate while the callback still holds it. It is the only test callback that
touches `user_data` after sending.
- Reproduce first: a temporary sleep between the send and the lock makes
valgrind report the invalid write; keep a regression that fails without the
fix if one is practical.

Follow the rules in [More tests under load](/quest/m0/test-flakes-2/README.md).
6 changes: 5 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ per-frame CPU growth since #5926.
- [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 pin bump](/quest/m1/moxygen-pin-bump.md) - waiting on moxygen#264, then the TRACK_STATUS patch is dropped
- [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
- [moq-crypto replaces moq-sign and moq-e2ee](/quest/m1/moq-crypto.md) - one Rust crate and one JS package hold signing and end-to-end encryption, sharing moq-net's timestamp check
- [moq-transport 18, 20, and 22 only](/quest/m1/ietf-drop/README.md) - drafts 14-17, 19, and 21 are deleted from Rust, JS, tests, interop lanes, and docs, removing the legacy control-stream adapter and its request limit
- [A moq-transport request token is one auth per distinct token](/quest/m1/ietf-token-auth.md) - requests naming the same token share one verification and grant, on any request type, ending with the last such request
- [moq-quic's API improves on quinn's](/quest/m1/quic-api/README.md) - moq-quic and both QUIC drivers ship one mirrored API: `send::`/`recv::` namespaces, one error per direction, consuming terminal operations, plain configs, no quinn baggage
Expand All @@ -170,7 +171,7 @@ per-frame CPU growth since #5926.
- [crates.io trusts the workflow](/quest/m1/crates-trusted-publisher.md) - maintainer action: every published crate gets a trusted publisher for `release-rs.yml`
- [Rust releases publish through OIDC](/quest/m1/release-rs-oidc.md) - release-plz publishes with trusted publishing and `CARGO_REGISTRY_TOKEN` is revoked
- [Main is no slower than release](/quest/m1/release-perf/README.md) - every benchmark where main is slower than release is fixed or accepted with a reason, checked by a final paired run before the cut
- [Interop coverage](/quest/m1/interop-coverage/README.md) - the riskiest moq-transport features moq-net exposes get cross-implementation tests over drafts 18 and 22
- [Interop coverage](/quest/m1/interop-coverage/README.md) - the riskiest moq-transport features moq-net exposes get cross-implementation tests over drafts 18, 20, and 22
- [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 and DASH segment conformance](/quest/m1/hls-conformance.md) - nightly ffprobe checks that advertised timing, sync flags, and bytes match the media served
- [Unbounded groups](/quest/m1/unbounded-groups/README.md) - groups and frames lose their size caps; a group keeps a 32 MB tail, and readers behind it replay through paced flights or refresh
Expand All @@ -180,6 +181,9 @@ per-frame CPU growth since #5926.
- [HLS export lists a same-codec reconfigure's first group under the new init](/quest/m1/hls-reinit-same-codec.md) - the hand-over pick, whichever of the catalog and the records arrives first, after the catalog `hls` removal is planned
- [moq-quic deletes its remaining 0-RTT code](/quest/m1/quic-zero-rtt-leftovers.md) - only the code that drops a 0-RTT packet remains, with a test
- [Gate the no-em-dash rule](/quest/m1/em-dash-gate.md) - `just check` fails on an em dash in any tracked text file
- [A resume more than one group behind never hangs](/quest/m1/ietf-resume-behind.md) - a resumed read gets every group or a drop on every wire version
- [moq-quic's idle connections keep no burst-sized state](/quest/m1/quic-readable-dedupe.md) - readable events are deduplicated and a quiet connection keeps no per-peak-stream bytes
- [Stats name the route instance's epoch with a type](/quest/m1/stats-epoch-type.md) - `GroupFrame::epoch` gets a dedicated type and tests stop mislabelling the instance

## Related

Expand Down
6 changes: 5 additions & 1 deletion quest/m1/hls-reinit-same-codec.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ Found by the conformance test in [moq-dev/moq#7387](https://github.com/moq-dev/m

What remains is the hand-over race. The catalog and the records are separate tracks, so the new config's first group can reach the old instance's records watcher before the catalog update. The retiring instance claims it, so it is muxed under the old init and the replacement starts one group late.

Waiting on a plan: the maintainer decided on 2026-11-02 to remove the catalog's `hls` field (`rs/hang/src/catalog/hls.rs` and the JS zod schema), planned separately. That changes how the export finds a rendition's records, so the hand-over pick is designed after that plan, not with a catalog `start` field, a record track per config, or a marker in each record (all three dropped the same day). Once the removal is planned, add it under `Required` here or fold the pick into it.
The maintainer decided on 2026-11-02 to remove the catalog's `hls` field (`rs/hang/src/catalog/hls.rs` and the JS zod schema); that removal is now [HLS export on a declared grid](/quest/m0/hls-media-grid.md). It changes how the export finds a rendition's records, so the hand-over pick is designed after it lands, not with a catalog `start` field, a record track per config, or a marker in each record (all three dropped the same day).

Public API: none expected. Wire: decided by the removal plan.

## Required

- [HLS export on a declared grid](/quest/m0/hls-media-grid.md) - the catalog's `hls` field and record tracks go away first

## Related

- [HLS and DASH segment conformance](/quest/m1/hls-conformance.md) - the test that found it, which waits on this
26 changes: 26 additions & 0 deletions quest/m1/ietf-resume-behind.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# [S] A resume more than one group behind never hangs

## Goal

A resumed read that starts more than one group behind the latest one gets
every group or a drop for it on every wire version, never a hang. The fix is
the simplest one that works; moq-transport FETCH/SUBSCRIBE edge cases are not
worth draft-specific fallbacks.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run), from [moq-dev/moq#7631](https://github.com/moq-dev/moq/pull/7631), which
found it and kept its two direct bounded-resume tests on draft 22 only.

- It hangs on `main` too, even with an open-ended range, over a draft-18
upstream. Two causes: our moq-transport publisher answers only one-group
FETCHes, so the fill for the missing run never arrives (a one-group range
works); and the live join can skip a group that is already cached
(`TrackState::answered` in `rs/moq-net/src/model/track.rs`).
- Also check whether the moq-lite publisher has the same wait when it serves a
bounded SUBSCRIBE from a moq-transport copy that was only fetched.
- Multi-group past reads between our own moq-transport nodes are refused until
hole markers land (decided on
[moq-dev/moq#7625](https://github.com/moq-dev/moq/pull/7625)); a refused run
must come back as dropped, not hang.
- Enable the draft-18 cases of #7631's bounded-resume tests as the regression.
7 changes: 6 additions & 1 deletion quest/m1/interop-coverage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
The moq-transport features moq-net exposes with the most interop bug
history have cross-implementation tests: Rust, JS, and the bindings exchange
hang media and exercise subgroup data, namespace discovery, late joins,
FETCH, GOAWAY, TRACK_STATUS, and datagrams over drafts 18 and 22. Our
FETCH, GOAWAY, TRACK_STATUS, and datagrams over drafts 18, 20, and 22. Our
upstream runner clients implement the runner's existing cases for those
features.

Expand All @@ -26,6 +26,11 @@ Boundaries:

## Plan

Decided 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run): draft 20 joins the covered drafts, since it came back in
[moq-dev/moq#7190](https://github.com/moq-dev/moq/pull/7190) and every published moq-dev client and relay already offers it (verified on
[moq-dev/moq#6972](https://github.com/moq-dev/moq/pull/6972)). Where this Plan says drafts 18 and 22, read 18, 20, and 22.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This note tells the reader to substitute "18, 20, and 22" manually, but line 42 still opens Drafts 18 and 22 only, nightly: and line 43 links moq-transport 18 and 22 only (whose title is now "moq-transport 18, 20, and 22 only"). AGENTS asks stale text be fixed inline, so editing those two spots removes both the contradiction and the override note.



Decided with the maintainer on 2026-10-21, from an inventory of the
coverage on `main` at `3ab6cbf81d`.

Expand Down
38 changes: 38 additions & 0 deletions quest/m1/moq-crypto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# [M] moq-crypto replaces moq-sign and moq-e2ee

## Goal

One crate, `moq-crypto`, and one JS package, `@moq/crypto`, hold MoQ's
content signing and end-to-end encryption, replacing `moq-sign`/`@moq/sign`
and `moq-e2ee`/`@moq/e2ee` before `main` is next cut into `release`. Both
halves share one timestamp check with moq-net, so they cannot drift from it.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run). The follow-up started from
[moq-dev/moq#7614](https://github.com/moq-dev/moq/pull/7614), which made
`moq_net::group::on_track` public; the maintainer asked to combine the two
packages instead of only deduplicating the check.

Decisions:

- ✅ Name it `moq-crypto` (Rust) and `@moq/crypto` (JS). Not chosen:
`moq-secure`; keeping `moq-e2ee` and absorbing signing into it.
- ✅ Merge JS too, for parity. `@moq/sign` and `@moq/e2ee` are private and
unpublished, so the rename costs nothing outside the repository. Not chosen:
Rust only.
- ✅ Plain `sign` and `e2ee` modules, always built. Not chosen: Cargo features
per half.
- ✅ `moq-e2ee` 0.0.19 is already on crates.io: at the cut, publish a final
`moq-e2ee` whose README points at `moq-crypto`. No yank. Not chosen:
leaving it as is; yanking it. Version levels stay with the maintainer.
- Both halves call `moq_net::group::on_track` instead of their own copies
(for example `rs/moq-sign/src/group.rs:48`).

Keep the crate independent of hang and codec-specific publisher policy, as the
[E2EE epic](/quest/m2/e2ee/README.md) requires. Update every crate, package,
doc, binding, and quest that names the old packages, including the m2 E2EE
quests.

Public API: the crate and package names and their import paths change.
Wire: none.
19 changes: 19 additions & 0 deletions quest/m1/quic-readable-dedupe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# [S] moq-quic's idle connections keep no burst-sized state

## Goal

A moq-quic connection's per-stream "readable" event queue stays bounded by the
number of streams with unread data, not by the size of a burst, and a quiet
connection keeps no per-stream bytes for streams it no longer has.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run), from [moq-dev/moq#7528](https://github.com/moq-dev/moq/pull/7528), which
stopped recycling freed receive state.

- Deduplicate the per-stream readable events the connection queues; today the
queue can grow to the size of a burst.
- Trace the roughly 70 to 90 bytes per peak concurrent stream that a quiet
connection still keeps after #7528. The stream maps holding their peak
capacity are the likely part; release or shrink them at rest.
- Measure retained bytes after a burst with #7528's `receive_bursts` bench.
15 changes: 15 additions & 0 deletions quest/m1/stats-epoch-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# [XS] Stats name the route instance's epoch with a type

## Goal

`moq_stats::GroupFrame::epoch` carries a dedicated type rather than a bare

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GroupFrame::epoch is typed moq_net::Instance (rs/moq-stats/src/lib.rs:135), not a bare integer; #7489's suggestion was that it reuses moq_net::Instance for its UUIDv7 text and would read clearer with a type of its own. Rewording to "rather than reusing moq_net::Instance" makes the Goal match the actual starting point.

integer, and the routing contract tests stop labelling the instance's value
`epoch` where they mean the instance, so the public stats API matches the
instance/epoch naming before the cut.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run), leftovers from [moq-dev/moq#7489](https://github.com/moq-dev/moq/pull/7489)
(routes carry an instance and a per-instance epoch).

Public API: the `GroupFrame` field's type changes.
16 changes: 12 additions & 4 deletions quest/m1/unbounded-groups/fastest-reader.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ The paced hops include qmux sessions (WebSocket, `tcp://`, `tls://`,
messages are bounded by the session's receive window and the lowest-priority
holder is evicted when it is stuck, as on native QUIC. The per-session memory
a peer can make us hold is one deliberate, documented number across native
QUIC and qmux. The browser keeps reading unpaced until WebTransport offers a
real receive-credit contract.
QUIC and qmux. The browser and JS keep reading unpaced; their pacing is
[JS fastest-reader pacing](/quest/m2/js-fastest-reader.md), in m2.

## Plan

Expand Down Expand Up @@ -208,5 +208,13 @@ What remains:
added. The cursor's report is one relaxed load per frame or batch, and a
`fetch_max` only for the fastest reader. On the busy host that landed it,
runs swung by up to 50% either way between repeats.
- JS parity, once the browser offers a receive-credit contract. The JS qmux
receiver could pace today but follows the browser.
- A relay-level test that the operator's `[quic]` windows reach WebSocket
sessions end to end through the relay's own `serve_ws` path. Today it is
covered only at `websocket::accept` level, because an accepted session's
window is not visible outside moq-tokio.

Decided 2026-11-02 (maintainer, follow-up planning after the 2026-11-02
/quest-complete run): JS parity moves to
[JS fastest-reader pacing](/quest/m2/js-fastest-reader.md) in m2, which waits
on [browser receive credit](/quest/m2/browser-receive-credit.md), so the m1
cut does not wait on browsers.
5 changes: 5 additions & 0 deletions quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,8 @@ lite-07; bitrate enforcement is not part of this release.
- [The browser bench keeps its page consoles](/quest/m2/browser-bench-consoles.md) - publisher and consumer page logs in the run directory
- [moq-quic's long header type is one variant](/quest/m2/quic-long-type.md) - collapse LongType after the 0-RTT removal
- [One predicate for the lite close wait](/quest/m2/subscriber-fin-fold.md) - fold waits_for_subscriber_fin into has_track_stream
- [Browsers expose WebTransport receive credit](/quest/m2/browser-receive-credit.md) - condition: the page can tell how much credit an unread stream holds
- [JS fastest-reader pacing](/quest/m2/js-fastest-reader.md) - `@moq/net` paces upstream groups by the fastest reader, once browsers allow it
- [fMP4 import at 1-byte chunks is no slower than before](/quest/m2/fmp4-byte-chunk-perf.md) - bisect and fix or accept the ~19% slowdown at 1-byte chunks
- [The relay bench reports io_uring pool size and RSS](/quest/m2/bench-uring-pool.md) - pool growth regressions show up in normal bench runs
- [MKV imports ffmpeg's multichannel FLAC](/quest/m2/mkv-flac-channel-mask.md) - a channel-mask-only Vorbis comment is accepted, so default ffmpeg multichannel FLAC needs no remux
13 changes: 13 additions & 0 deletions quest/m2/bench-uring-pool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# [XS] The relay bench reports io_uring pool size and RSS

## Goal

The `bench/` relay summary reports each run's io_uring buffer pool gauges
(receive and send, total and in use) and the relay's RSS, so a regression in
pool growth shows up in normal bench runs.

## Plan

Planned 2026-11-02 (maintainer, follow-up planning after the 2026-11-02 /quest-complete run), from [moq-dev/moq#7233](https://github.com/moq-dev/moq/pull/7233), which
added the gauges to `/metrics` and measured them with a throwaway script.
Read them from the relay's `/metrics` at the end of each workload.
Loading
Loading