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
6 changes: 6 additions & 0 deletions quest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ The [release execution](/quest/m2/release/README.md) starts after m1 is ready.
It publishes artifacts before downstream adoption and rollout can complete.
Critical fixes continue to reach the existing release through backports.

Test flakes join m0 without asking (decided 2026-11-05, maintainer): a test
that fails intermittently in CI, Nightly, or the merge queue becomes a child
of m0's [test flakes](/quest/m0/test-flakes-2/README.md) epic. Skills that plan
follow-ups plan a reported flake there without asking whether or where; the
planning PR's review is the check.

## Required

- [m0: immediate priorities](/quest/m0/README.md) - urgent correctness fixes and maintenance of the current release
Expand Down
11 changes: 10 additions & 1 deletion quest/m0/ci/nix-builder-userns.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# [S] The desktop host's Nix builders may map user namespaces
# [XS] The desktop host's Nix builders may map user namespaces

## Goal

Expand Down Expand Up @@ -28,3 +28,12 @@ As of 2026-11-05 the probe fails on the desktop host (Ubuntu 26.04, where
AppArmor's restriction for Nix builds there, persistently and as narrowly as
works, apply it when no gate is running, and check that the probe succeeds and
`just ci` passes `check flake`.

Decided 2026-11-05 (maintainer, /quest-plan): flip the sysctl host-wide rather than a narrow AppArmor
profile for the Nix builders. Not chosen: a narrow profile; declining and
deleting the quest. Applied the same day:
`/etc/sysctl.d/99-userns.conf` sets
`kernel.apparmor_restrict_unprivileged_userns = 0` (it loads after Ubuntu's
`/usr/lib/sysctl.d/10-apparmor.conf`), `unshare --map-root-user true`
succeeds, and `nix/runner/userns-probe.nix` builds. What remains: run
`just ci` on the desktop and confirm `check flake` passes.
9 changes: 9 additions & 0 deletions quest/m0/ci/queue-concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,12 @@ maintainer's actions (ruleset 2420853); the quest names the setting and
reports the numbers. The host runner must handle two builds at once without
the shared mbx cache or `quest gate` admission erasing the gain, so record
host load during the trial.

The trial started early (decided 2026-11-05, maintainer, /quest-plan): the
second queue runner `nixos-moq-ci2` landed in
[kixelated/nixos#24](https://github.com/kixelated/nixos/pull/24), and ruleset
2420853 went to `max_entries_to_build: 2` at 2026-11-05T15:49:30Z. A scheduled
task sets it back to 1 at 2026-11-07T08:00Z. Measure the setting-2 window
against a comparable setting-1 window before it, such as
2026-11-03 06:47Z to 2026-11-04 06:47Z, and check the ruleset reads 1 again
before recording the result.
1 change: 1 addition & 0 deletions quest/m0/nightly/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ Public API: none. Wire: none.
- [moq-net's ingest fuzz target finds no stall](/quest/m0/nightly/ingest-fuzz.md) - the 13-byte stream that stalls ingest is fixed at its cause and kept as a regression test
- [Nightly's shipping-size check passes](/quest/m0/nightly/shipping-size.md) - js/net, js/watch, and moq-relay growth over 5% is traced to its commits, then shrunk or accepted
- [Nightly's Miri job stays inside its time budget](/quest/m0/nightly/miri.md) - both Miri passes go green, with ARM timings inside the 60-minute job and 15-minute-per-test budgets
- [Nightly's macOS platform job passes](/quest/m0/nightly/macos.md) - `moq-audio`'s tests compile on macOS again and the websocket version test's timeout is fixed if it recurs
34 changes: 34 additions & 0 deletions quest/m0/nightly/macos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# [S] Nightly's macOS platform job passes

## Goal

The scheduled Nightly's `platform / macOS` job on `main` passes: `moq-audio`'s
tests compile on macOS again, and
`moq-tokio::integration broadcast::broadcast_websocket_uses_newest_version`,
which timed out at 120 s in an earlier scheduled run, is fixed at its cause if
it still fails once the job reaches it.

## Plan

Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the
2026-11-05 /quest-complete run), from
[moq-dev/moq#7653](https://github.com/moq-dev/moq/pull/7653), which saw the
timeout. Milestone: ✅ m0.

Since 2026-11-04 the job fails before any test runs
([run 41979277343](https://github.com/moq-dev/moq/actions/runs/41979277343),
`just rs macos-test`): the test `an_empty_gap_buffer_marks_the_next_samples`
(`rs/moq-audio/src/capture.rs:859`) hands `tokio::spawn` a
`capture::Producer::run()` future that is not `Send` on macOS, because
`Producer` holds the ScreenCaptureKit `SCStream` across an await. It came with
[moq-dev/moq#7706](https://github.com/moq-dev/moq/pull/7706). Decide from the
type whether `Producer` should be `Send` (fix the field) or the test should
drive it without spawning; don't paper over it in the test if real callers
spawn it too. Check why the PR gate didn't catch a macOS-only test build
error, and close that gap if it is cheap.

Then read the job's next run for the websocket timeout. Reproduce it on macOS
before fixing; if it never recurs across a week of scheduled runs, record that
and finish.

Public API: none. Wire: none.
2 changes: 2 additions & 0 deletions quest/m0/test-flakes-2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,5 @@ Public API: none. Wire: none.
- [dispatch-query's terminate test survives load](/quest/m0/test-flakes-2/dispatch-query-terminate.md) - `test_terminating_the_run_stops_the_running_phase` passes reliably under host load, re-enabled once fixed
- [release.test.ts never reaches the network](/quest/m0/test-flakes-2/release-test-offline.md) - the JSR release test fakes its registry lookup and passes offline
- [moq-ffi's datagram tests don't hinge on one datagram](/quest/m0/test-flakes-2/ffi-datagram-roundtrip.md) - the default-connection datagram tests pass under CI load
- [Test PulseAudio servers stay off the desktop's D-Bus](/quest/m0/test-flakes-2/pulse-dbus.md) - concurrent media runs on one desktop never collide on `org.PulseAudio1`
- [The open-GOP browser fixture fails loudly](/quest/m0/test-flakes-2/open-gop-fixture.md) - its broadcast stub matches current stats dependencies and an effect exception fails the test
20 changes: 20 additions & 0 deletions quest/m0/test-flakes-2/open-gop-fixture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# [XS] The open-GOP browser fixture fails loudly

## Goal

The open-GOP browser test (`test/interop/clients/js/open-gop.browser.ts`)
exercises current `@moq/watch` code: its broadcast stub satisfies the stats
dependencies the player now reads, and an exception inside the fixture's
effect fails the test directly instead of being swallowed.

## Plan

Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the
2026-11-05 /quest-complete run), from
[moq-dev/moq#7716](https://github.com/moq-dev/moq/pull/7716). Milestone: ✅ m0.

The stub lives in `test/interop/clients/js/open-gop/main.ts`. Prefer building
the stub from the real types so the next dependency change fails to compile
rather than at runtime.

Public API: none. Wire: none.
23 changes: 23 additions & 0 deletions quest/m0/test-flakes-2/pulse-dbus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# [S] Test PulseAudio servers stay off the desktop's D-Bus

## Goal

Every private PulseAudio server the test suites start stays off the session
bus, so two media runs on one desktop never collide on the
`org.PulseAudio1` name. Concurrent `just test media` runs on a desktop host
pass where today one can fail with `D-Bus name org.PulseAudio1 already taken`.

## Plan

Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the
2026-11-05 /quest-complete run), from
[moq-dev/moq#7716](https://github.com/moq-dev/moq/pull/7716). Milestone: ✅ m0.

`test/lib/pulse.py` already drops `DBUS_SESSION_BUS_ADDRESS` from its own
daemon's environment, so another launch path still reaches the bus: find it
(the Playwright media runner, `test/native-play`, `test/audio-quality`, or a
module PulseAudio loads by default) and close it at the source, for example by
starting the daemon without its D-Bus modules. Reproduce with two overlapping
media runs first.

Public API: none. Wire: none.
2 changes: 2 additions & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ their end report, so an embedder's drain alert pages on real cuts.
- [A job's exact route continues its claim's readers](/quest/m1/announce-takeover.md) - a job's route inherits its claim's instance, replacing the ANNOUNCE_TAKEOVER predecessor design
- [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - a lite-07 SUBSCRIBE asks for past and live ranges with absolute or relative ends, in either order, and replaces FETCH; merged ranges never starve a subscriber; relays fill misses by range, including over moq-transport
- [Drop set](/quest/m1/drop-set.md) - each cursor judges missing groups against its own budget, so a narrow reader drops promptly and a widening re-offers groups already reported dropped on lite-07
- [A reader on a failed copy continues on the held re-offer](/quest/m1/copy-recover.md) - a live reader keeps a group whose copy fails by continuing on the same track's re-offer at the same frame
- [Group errors are cached by kind](/quest/m1/group-error-cache.md) - permanent group errors bind every reader, retryable ones are kept only for a bounded time, and a live SUBSCRIBE_DROP or FETCH answered `Old` no longer caches it for good
- [A group a subscriber gives up on is always reported](/quest/m1/group-drops.md) - the wire names every abandoned group and the drop signal is public, so readers count losses instead of stalling
- [The overcommitted receive-window cells run again](/quest/m1/receive-windows-evicted.md) - `benchmark_receive_windows` measures its 256-stream and 4 MiB-frame cells again, reporting delivered frames and evictions instead of stalling
Expand All @@ -172,6 +173,7 @@ their end report, so an embedder's drain alert pages on real cuts.
- [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
- [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
- [moq-json's table/deltas bench measures the same work every iteration](/quest/m1/bench-json-deltas.md) - the `table/deltas/1%` cases stop flipping between snapshot and delta timings, so their trend history is usable
- [moq-net's benches run to completion](/quest/m1/bench-test-mode.md) - the `origin`, `session` and `memory` benches stop panicking in test mode and Nightly's measured run, and the maintainer picks where CI catches the next break
- [Publish moq-bench to crates.io](/quest/m1/bench-publish.md) - `cargo install moq-bench` installs one binary, with the host sampler as `moq-bench host`, first as 0.1.0
- [Catalog contributions become includes on the root's timeline](/quest/m1/catalog-include.md) - rename the unreleased `contributions` map before the cut and state that included broadcasts share the root's timeline
Expand Down
24 changes: 24 additions & 0 deletions quest/m1/bench-json-deltas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# [XS] moq-json's table/deltas bench measures the same work every iteration

## Goal

`moq-json`'s `table/deltas/1%/{10000,20000}` cases report a stable time, so
their Nightly trend history is usable. Today each iteration ticks one
long-lived encoder, so a short run either catches a forced snapshot or misses
it: 4.9 vs 35.7 ms, and 71 vs 10 ms, in
[moq-dev/moq#7928](https://github.com/moq-dev/moq/pull/7928)'s quick screen.

## Plan

Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the
2026-11-05 /quest-complete run), from #7928. Milestone: ✅ m1.

Make each iteration do the same work: measure deltas and forced snapshots as
separate cases, or give every iteration the same snapshot cadence. Check the
fix with repeated quick screens of both cases on one host.

Public API: none. Wire: none.

## Related

- [Calibrate the paired nightly benchmarks](/quest/m1/bench-ci.md) - its rounds rejected these cases as outliers
31 changes: 31 additions & 0 deletions quest/m1/copy-recover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# [M] A reader on a failed copy continues on the held re-offer

## Goal

A live reader already handed a copy of a group that then fails keeps the
group: its `group::Consumer` continues on the successor copy the held
re-offer carries in the same track, at the same frame, instead of surfacing
the failure. Rust and `js/net` behave the same.

## Waiting

- moq-dev/moq: [moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670)
merges. It adds the held re-offer (its decision 24) this builds on. Check
that it is merged into `main`.

## Plan

Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the
2026-11-05 /quest-complete run), from #7670. Milestone: ✅ m1.

`with_recover` already continues a reader across a front's routes; reuse it
or its mechanism for the same-track successor rather than adding a parallel
path. A successor that diverges from what the reader already consumed fails
the reader, as a route switch does. Test on mock time: a reader mid-group on a
copy that fails continues on the re-offer with no duplicate or missing frame.

Public API: none expected. Wire: none.

## Related

- [Drop set](/quest/m1/drop-set.md) - reworks the re-offer path this reads from
7 changes: 7 additions & 0 deletions quest/m1/fuzz-findings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ input committed before the fix would fail the merge gate. Every known finding
is now fixed: run every target nightly for a few sessions; a new finding
becomes a child here.

Decided 2026-11-05 (maintainer, /quest-plan): keep this epic as an `[S]` watcher after
[moq-dev/moq#7690](https://github.com/moq-dev/moq/pull/7690) removed its last
child, since Fuzz (annexb), (fmp4), (ts), and (ingest) were still red on
2026-11-05. An agent triages each red target into a child quest (an
intermittent failure joins m0's test flakes instead), and the epic is deleted
once every target runs green. Not chosen: deleting it now.

For the crates outside the `kixelated` and `moq-dev` orgs, moq-mux fixes
the bug on its own side and the bug is reported upstream (decided
2026-10-30, maintainer): [austinleroy/webm-iterable#11](https://github.com/austinleroy/webm-iterable/issues/11),
Expand Down
2 changes: 1 addition & 1 deletion quest/m1/lite07-finalize.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ timestamp bound in [#6168](https://github.com/moq-dev/moq/pull/6168).
- [Lite-07 by start](/quest/m1/time-addressing/lite07.md) - lite-07 carries group starts, previous-start links, GROUP_END, and time bounds instead of sequence numbers
- [@moq/net by start](/quest/m1/time-addressing/js.md) - JS speaks the same lite-07 wire
- [A job's exact route continues its claim's readers](/quest/m1/announce-takeover.md) - the job's route inherits the claim's instance, with no new wire message
- [A higher-priority group makes room](/quest/m1/stream-credit/make-room.md) - lite-07 lets a group stream take over for another group
- [Takeover](/quest/m1/stream-credit/takeover.md) - lite-07 lets a group stream take over for another group
- [Datagram tracks](/quest/m1/datagram-tracks/README.md) - lite-07 subscribes to datagram tracks through their own request, and datagrams carry their own sequence

## Related
Expand Down
1 change: 1 addition & 0 deletions quest/m1/push-to-talk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ catches this. A complete set of runs finishes this epic.
## Required

- [Push-to-talk suppresses silence instead of toggling the catalog](/quest/m1/push-to-talk/dtx.md) - replaces hold with DTX
- [Native playback fills declared silence with comfort noise](/quest/m1/push-to-talk/native-comfort-noise.md) - `moq play` plays comfort noise over declared silence and counts no underrun, matching the browser

## Closes

Expand Down
37 changes: 37 additions & 0 deletions quest/m1/push-to-talk/native-comfort-noise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# [M] Native playback fills declared silence with comfort noise

## Goal

`rs/moq-audio` playback, as used by `moq play`, treats a publisher's declared
silence the way `@moq/watch` does: when the ring runs dry at a declared end it
plays level-matched comfort noise instead of plain silence, counts no underrun
or stall, and keeps that silence through the next utterance's refill. A
push-to-talk listener on `moq play` then matches the browser.

## Waiting

- moq-dev/moq: [moq-dev/moq#7942](https://github.com/moq-dev/moq/pull/7942)
merges. It defines how a suppressed span is declared and already gives
`moq-audio`'s jitter estimator the declared-silence exception. Check that
it is merged and `quest/m1/push-to-talk/dtx.md` is gone from `main`.

## Plan

Planned 2026-11-05 (maintainer, /quest-plan of the follow-ups from the
2026-11-05 /quest-complete run), from #7942, whose agent left native playback
with the estimator exception but no comfort noise because its ring has no
notion of a declared end. Milestone: ✅ m1.

Follow the browser's choices in #7942 unless measurement argues otherwise: the
decoder hands the ring each declared end less the Opus pre-skip, and comfort
noise is white noise matched to the quietest 20 ms block played, capped at
-60 dBFS (`js/watch/src/audio/comfort.ts`). Share the level rule with the
browser through `doc/concept/audio-jitter.md` and a corpus case rather than
two descriptions. Cover it in `test/audio-quality`'s native rows or
`just test push-to-talk` if that can drive `moq play`.

Coordinate with [moq play reaches zero steady-state underruns by
time-stretching](/quest/m1/audio-jitter-target/native-stretch.md), which edits
the same playback ring: whichever lands second rebases onto the other.

Public API: none expected. Wire: none.
21 changes: 13 additions & 8 deletions quest/m1/stream-credit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ which JS cannot raise; Chrome stalled at 103, Firefox at 100):
- ✅ Make room by taking over, else cancelling. Rejected: cancelling only
(each reset frees credit only after the peer's MAX_STREAMS, a round trip
later), and ordering waiting opens without making room.
- ✅ Transports report the peer's stream credit and blocked state
(decided 2026-11-04, maintainer): moq-quic, Rust qmux and `@moq/qmux`
expose it, and the Rust entry point reads it through
`poll::Session::stream_credit`. Rejected: treating any waiting open as the
signal, since an open also waits on things other than credit. Browsers
report nothing and keep `createUnidirectionalStream()` pending without
credit, so there a waiting open stays the only signal.
- ~~Transports report the peer's stream credit and blocked state~~,
reversed the same day (maintainer, on
[moq-dev/moq#7894](https://github.com/moq-dev/moq/pull/7894)): the signal
is the open line's waiting state (the head of the line is pending), with
no transport credit or blocked API.
- Decided 2026-11-05 (maintainer, /quest-plan): "make room" splits into open
streams (ready now), reset fallback, and takeover (after
[moq-dev/moq#7670](https://github.com/moq-dev/moq/pull/7670)), and the
browser test stays this README's own work. Not chosen: holding the whole
quest until #7670 merges.

This epic owns the end-to-end test: a browser reader and a Rust relay over
WebTransport, 300 live tracks of mixed priority, the highest-priority ones
Expand All @@ -40,4 +43,6 @@ receiving every group, and nothing hanging.
## Required

- [A departed subscription releases its streams](/quest/m1/stream-credit/release-on-leave.md) - on lite-07 a subscription whose reader left frees its upstream streams, so 3 slots serve the next one
- [A higher-priority group makes room](/quest/m1/stream-credit/make-room.md) - it takes over a lower-priority stream, or one is reset, without over-cancelling
- [Open streams](/quest/m1/stream-credit/open-streams.md) - each session lists its open streams and, where the transport can tell, which are fully acknowledged
- [Reset fallback](/quest/m1/stream-credit/reset-fallback.md) - a waiting higher-priority open resets the lowest-priority stream, one reset in flight per waiting open
- [Takeover](/quest/m1/stream-credit/takeover.md) - on lite-07 a higher-priority group takes over an acknowledged stream, and a group that lost its stream resumes
Loading