Skip to content
Merged
2 changes: 2 additions & 0 deletions quest/m0/ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,5 @@ The historical samples locate candidates; they are not controlled benchmarks.
- [Verify the R2 Rust cache](/quest/m0/ci/mbx-r2-verify.md) - measure the hosted Nightly jobs' hits, restore time, and expiry once the bump lands
- [Verify the Nix cache](/quest/m0/ci/nix-cache-verify.md) - confirm CI and releases use `nix.moq.dev` and retire Cachix
- [First shared FFI release](/quest/m0/ci/nightly-ffi-reuse.md) - condition: the backport merges and the next `moq-ffi-v*` tag runs `Release FFI`; verify the wrappers
- [Loom tests compile](/quest/m0/ci/loom-build.md) - `just rs loom` builds on main and a `--cfg loom` break fails its PR
- [just check without user namespaces](/quest/m0/ci/check-without-userns.md) - a host that refuses `unshare` reports the flake module as not run instead of cancelling other lanes
24 changes: 24 additions & 0 deletions quest/m0/ci/check-without-userns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# [S] just check finishes on a host without user namespaces

## Goal

On a host that refuses unprivileged user namespaces, `just check` runs every
other module to completion and reports the flake module as not run, with the
reason, instead of failing it and cancelling the lanes behind it. The merge
queue still runs the flake check in full.

## Plan

Seen 2026-10-24/25 in every quest-spawn agent: `check:flake` (`sh/dispatch.sh`)
runs `nix flake check`, whose github-runner VM test (`nix/runner/test.nix`)
fails with `unshare ... uid_map: Operation not permitted`. That failure cancels
other lanes (kt, js, rs tests), so agents fell back to partial checks and
reported them as `just check`.

- Probe for user namespaces once, up front, and report the flake module as
skipped with that reason; never as passed.
- Alternatively split the VM test out of the default flake check and run it
only where it can; pick whichever keeps `just ci` in the queue unchanged.
- One module failing must not cancel unrelated lanes either way.

Public API: none. Wire: none.
23 changes: 23 additions & 0 deletions quest/m0/ci/loom-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# [S] Loom tests compile, and the gate proves it

## Goal

`just rs loom` builds and runs on `main`, and a PR that breaks the `--cfg loom`
build fails its own gate instead of the next Nightly.

## Plan

Found 2026-10-25: `RUSTFLAGS="--cfg loom" cargo test -p moq-net --test loom
--no-run` fails on main with E0599 at `rs/moq-net/tests/loom.rs:621`:
`Subscription::with_groups` was replaced by `with_range` in
[moq-dev/moq#6138](https://github.com/moq-dev/moq/pull/6138), which missed the
loom test because nothing on the PR gate builds with `--cfg loom`.

- Port the call to `with_range`, then run the full `just rs loom`.
- Add a compile-only `--cfg loom` step (`--no-run`) to the changed-Rust check
when `kio` or `moq-net` changes, so the build break fails the PR.
- The Loom models that exceed their branch limit or run past the job timeout
are tracked in [CI audit](/quest/m2/audit-ci.md); this quest only restores
the build.

Public API: none. Wire: none.
5 changes: 5 additions & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ Catalog HLS field.
- [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
- [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
- [Bindings decode media as media](/quest/m1/obs-data-decode.md) - moq-ffi decodes a media rendition with its kind, so OBS stops losing every other group
- [Relay demand gaps](/quest/m1/relay-demand-gaps.md) - pre-07 backlog, IETF warm-relay newcomer, and double upstream pulls are fixed or ruled out
- [fMP4 boundary sync](/quest/m1/fmp4-boundary-sync.md) - a declared fMP4 boundary opens a passthrough group only on a sync sample
- [One moq-ffi build definition](/quest/m1/ffi-build-flags.md) - every binding takes moq-ffi's default features from one place
- [A reported drop means the same everywhere](/quest/m1/resume-drop-final.md) - Rust and JS agree whether a group reported dropped can still be served

## Related

Expand Down
4 changes: 4 additions & 0 deletions quest/m1/bench-ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ lands; agents never dispatch Nightly.
on the mbx cache for the previous night's artifacts, and a cold one roughly
doubles each leg's build time.

- Decide whether `bench/run.sh` pins glibc's malloc thresholds for every
Criterion target, as [moq-dev/moq#6727](https://github.com/moq-dev/moq/pull/6727)
did for `ts_schedule`: some small paired deltas may be the same heap mode flip.

Decided 2026-10-23 (maintainer), when the paired mode landed:

- The gate fails Nightly from day one rather than reporting only until A/A
Expand Down
1 change: 1 addition & 0 deletions quest/m1/broadcast-lifecycle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ timer on main at 1582fdc07d:
## Required

- [Closing a binding broadcast ends its media](/quest/m1/broadcast-lifecycle/ffi-close.md) - moq-ffi and moq-c media handles end with a cause on close or drop, never a cause-less drop
- [js/net close FIN](/quest/m1/broadcast-lifecycle/js-close-fin.md) - js/net finishes tracks whose FIN arrives with a graceful close

## Related

Expand Down
18 changes: 18 additions & 0 deletions quest/m1/broadcast-lifecycle/js-close-fin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# [S] js/net finishes tracks whose FIN arrives with the close

## Goal

When a peer closes a session gracefully right after finishing its tracks, a
js/net relay or subscriber finishes those tracks instead of aborting them, on
every lite version, as Rust does since
[moq-dev/moq#6741](https://github.com/moq-dev/moq/pull/6741).

## Plan

In Rust the close could reach the subscriber before it read an already
buffered SUBSCRIBE FIN, so the track ended `Unroutable`. The fix polls the
sources once after the closed transport's group streams drain. Check whether
js/net has the same ordering; if so, reproduce with a two-`Connection` test and
mirror the fix. If not, delete this quest with the evidence.

Public API: none. Wire: none.
1 change: 1 addition & 0 deletions quest/m1/c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ requests internally and keeps its ABI.
- [moq-c package](/quest/m1/c/package.md) - the generated header ships as `moq-c` 0.8.0 with `moq::c`, pkg-config, and a release workflow
- [C consumers](/quest/m1/c/consumers.md) - the C interop client and `doc/lib/c` samples move onto the generated API
- [Async failure contract](/quest/m1/c/async-failure-contract.md) - a generated async call that fails early fires no callback, and one that started always delivers its terminal callback
- [moq-c decode start](/quest/m1/c/decode-start.md) - a moq-c decoder can read a finished track from its start
16 changes: 16 additions & 0 deletions quest/m1/c/decode-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# [XS] moq-c decoders choose where to start

## Goal

A moq-c decoder can read a finished track from its start: decoding a finished
Opus track yields its frames instead of none.

## Plan

Found by [moq-dev/moq#6745](https://github.com/moq-dev/moq/pull/6745):
`rs/moq-c/src/video.rs:953` and `rs/moq-c/src/audio.rs:503` hardcode
`Start::Latest`. Confirm whether that was intended for live playback; if a
caller needs the other start, expose it the way moq-ffi does, else document
why moq-c only plays live.

Public API: maybe a start option on the decode config. Wire: none.
18 changes: 18 additions & 0 deletions quest/m1/ffi-build-flags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# [S] One definition of moq-ffi's default build flags

## Goal

Every binding that builds moq-ffi into the shared target directory takes its
features from one place, so a binding whose features drift cannot silently
overwrite `libmoq_ffi.so` for the others again.

## Plan

[moq-dev/moq#6716](https://github.com/moq-dev/moq/pull/6716) found that a
cdylib's file name carries no feature hash, so builds with different features
overwrite each other. Today the flags are repeated: `sh/kt/generate.sh`,
`sh/swift/check.sh`, `sh/go/stage.sh`, `sh/dart/generate.sh`, and
`cpp/moq/CMakeLists.txt` each pass `--features openh264`. Define them once,
and make a build that differs use its own target directory or fail loudly.

Public API: none. Wire: none.
16 changes: 16 additions & 0 deletions quest/m1/fmp4-boundary-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# [S] A declared fMP4 boundary opens a group only on a sync sample

## Goal

When a passthrough fMP4 import sees a declared segment boundary (`styp` or
`cut()`) whose fragment does not start with a sync sample, it does not open a
new group on the non-sync samples. Passthrough and unwrapped mode agree.

## Plan

Found by [moq-dev/moq#6743](https://github.com/moq-dev/moq/pull/6743):
unwrapped mode keeps those samples in the previous group, while passthrough
opens a new group a decoder cannot start from. Reproduce with a fixture, then
share one rule between both modes.

Public API: none. Wire: none.
22 changes: 22 additions & 0 deletions quest/m1/obs-data-decode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# [S] Bindings decode media tracks as media

## Goal

moq-ffi's `MoqMediaTrackConsumer` decodes a video or audio rendition with its
own kind, so the empty marker that ends a video group never reaches a binding
as an empty frame, and OBS plays every group.

## Plan

Found by the OBS decode-timing quest
([moq-dev/moq#6711](https://github.com/moq-dev/moq/pull/6711)), not yet
reproduced: `rs/moq-ffi/src/media.rs:1253` builds every container with
`container::Kind::Data`. FFmpeg treats an empty packet as end of stream, so OBS
likely drops every other group on streams without B-frames.

- Reproduce in an OBS source test or a moq-ffi test that reads two video
groups through the consumer.
- Pass the rendition's video or audio kind into `media_container`.
- Run `just test interop --all`.

Public API: none expected. Wire: none.
23 changes: 23 additions & 0 deletions quest/m1/relay-demand-gaps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# [M] Relay demand gaps left by the widened-age re-offer

## Goal

Three gaps found by [moq-dev/moq#6717](https://github.com/moq-dev/moq/pull/6717)
are fixed or ruled out, each with a test:

- On lite before 07, a reader with a narrow max age receives the whole backlog.
- On moq-transport, a newcomer on a warm relay gets only the newest group.
- A relay newcomer may pull one group upstream twice: once from its range fill
and once from the publisher's re-offer.

## Plan

Reproduce each through a relay first. The third is wasted upstream bandwidth
per newcomer, so it scales with subscribers; cover it with a benchmark if it
reproduces.

Public API: none expected. Wire: none expected.

## Related

- [A widened max age re-offers cached groups](/quest/m1/resolved-demand.md)
21 changes: 21 additions & 0 deletions quest/m1/resume-drop-final.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# [M] A reported drop means the same in Rust and JS

## Goal

Rust and JS agree on whether a group reported as dropped can still be served
later, on the plain cursor and the resumed (routed) path alike.

## Plan

Found by [moq-dev/moq#6758](https://github.com/moq-dev/moq/pull/6758). JS
records a reported drop as delivered, so no copy serves that group later. In
Rust a plain cursor reports a fill it gave up on as `NotFound`, and the group
can still arrive and be served. Making Rust's drops final broke
`rejoin::rejoined_quiet_catalog_survives_cache_expiry`: a late reader never got
the catalog's group 0.

Decide (maintainer) whether a reported drop is final. Then change the side that
differs, the plain cursor and the resume path together, with tests in both
languages.

Public API: none expected. Wire: none.
2 changes: 2 additions & 0 deletions quest/m1/subscribe-ranges/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,12 @@ every sequence delivered or dropped.

## Required

- [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md) - filling stays flat as range count and span grow
- [Fetch as a range](/quest/m1/subscribe-ranges/fetch-range.md) - `fetch_group` becomes a one-range subscription that ends once its range is accounted for
- [Lite-07 ranges](/quest/m1/subscribe-ranges/lite.md) - the lite-07 wire, Rust publisher and subscriber, and the draft
- [moq-transport range updates](/quest/m1/subscribe-ranges/ietf.md) - widening and narrowing upstream ranges, and `Time` ends
- [JS ranges](/quest/m1/subscribe-ranges/js.md) - `@moq/net` model and lite-07 parity
- [Range count cost](/quest/m1/subscribe-ranges/range-cost.md) - a subscription's range count cannot multiply per-group cost

## Related

Expand Down
10 changes: 6 additions & 4 deletions quest/m1/subscribe-ranges/fetch-range.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ the questions decided below and landed only the `track_range_filling` benchmark.
- **The fill path goes linear first** (maintainer, 2026-10-25). One-range
reads put every past read on the fill path, which `track_range_filling`
measures as superlinear in range count and span: at span 64, 215K groups/s
over 1 range, 69K over 16, and 1.9K over 256. This quest waits on the
linear fill path quest (`quest/m1/subscribe-ranges/fill-linear.md`, planned
in [moq-dev/moq#6790](https://github.com/moq-dev/moq/pull/6790)); once it is
on main, list it under Required here.
over 1 range, 69K over 16, and 1.9K over 256, so this quest waits on the
linear fill path.

## Required

- [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md) - filling stays flat as range count and span grow
21 changes: 21 additions & 0 deletions quest/m1/subscribe-ranges/fill-linear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# [M] The fill path is linear in range count and span

## Goal

`track_range_filling` (`rs/moq-net/benches/track.rs`) holds roughly flat
groups/s as range count and span grow.

## Plan

Measured in [moq-dev/moq#6722](https://github.com/moq-dev/moq/pull/6722): 234K
groups/s at 1 range × 1 span falls to 1.9K at 256 ranges × 64 span. Each poll's
drift edge (`live_edge`) and each candidate's successor search
(`arrival`/`successor`) walk `lookup` across all of a reader's runs, and a
filled group is never marked shown, so every scan passes it again.
`Misses::retain` also rescans every filled group per poll.

[FETCH as a range](/quest/m1/subscribe-ranges/fetch-range.md) waits on this
(maintainer, 2026-10-25, on #6722), since one-range reads would put every
past read on this path.

Public API: none. Wire: none.
22 changes: 22 additions & 0 deletions quest/m1/subscribe-ranges/range-cost.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# [M] A subscription's range count cannot multiply per-group cost

## Goal

The model's cost per group no longer grows with the number of ranges in a
subscription, or that number is bounded by the design (flow control or an
owned budget), not by a refusal constant. A benchmark sweeps range count and
subscriber count, so a slope shows up.

## Plan

From [moq-dev/moq#6715](https://github.com/moq-dev/moq/pull/6715): lite-07
SUBSCRIBE carries a list of ranges, a peer can send as many as fit in one
message, and the model's per-group cost grows with that count. A hostile peer
can multiply the CPU a relay spends on every group of a track.

- Measure first: extend `rs/moq-net/benches/track.rs` with ranges × subscribers.
- Prefer merging overlapping or adjacent ranges at decode, and a lookup that
touches only the ranges around a group.
- Shares code with [Linear fill path](/quest/m1/subscribe-ranges/fill-linear.md).

Public API: none expected. Wire: none expected.
2 changes: 2 additions & 0 deletions quest/m1/test-flakes-2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ 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
16 changes: 16 additions & 0 deletions quest/m1/test-flakes-2/export-echo-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# [S] The moq-cli echo report test runs on mocked time

## Goal

`report::export_echo_reports_where_the_import_solicits`
(`rs/moq-cli/tests/integration/report.rs:384`) finishes in well under a second
of wall time, so it stops being flagged SLOW in every `just check`.

## Plan

Six quest-spawn agents on 2026-10-25 saw it take about 35 s under load and
flagged it as SLOW. Find what it waits on in wall time and drive that from a
mocked clock or an event, per the root rule that unit tests mock time. If part
of it must stay real-time, move that part to Nightly.

Public API: none. Wire: none.
16 changes: 16 additions & 0 deletions quest/m1/test-flakes-2/obs-audio-candidate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# [S] The OBS failed-audio-candidate test passes under load

## Goal

The OBS test "failed audio candidate preserves playback" passes under load,
fixed at its cause.

## Plan

Seen by [moq-dev/moq#6711](https://github.com/moq-dev/moq/pull/6711): it fails
intermittently under load on the base commit too. Reproduce it under CPU
pressure or `SIGSTOP`/`SIGCONT` pauses, the way
[moq-dev/moq#6737](https://github.com/moq-dev/moq/pull/6737) did, then fix the
race.

Public API: none. Wire: none.
1 change: 1 addition & 0 deletions quest/m1/ts-reliability/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
- [TS workflow passes](/quest/m1/ts-reliability/validation-green.md) - the scheduled TS lanes pass on main again, with no lane loosened

## Related

Expand Down
30 changes: 30 additions & 0 deletions quest/m1/ts-reliability/validation-green.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# [M] The TS workflow passes on main

## Goal

The scheduled TS workflow (`.github/workflows/ts.yml`) passes on `main`, with
no lane loosened.

## Plan

Two breaks, seen in run
[40195146593](https://github.com/moq-dev/moq/actions/runs/40195146593)
(`66af72315b`, 2026-10-25). Last green run: 2026-10-20 at `f13283b302`.

- **New on 2026-10-25:** private PES, broadcast-sized CPB, full leak, full
multiplex, and headroom each lose 18 or 28 video frames at a regular
interval (`FAIL PID 0x100 h264: 475 frames of 40.00 ms, 18 holes, 1440 ms
missing`). Green on 2026-10-24 at `ea09d025a2`. Bisect
`ea09d025a2..66af72315b`; candidates include
[moq-dev/moq#6534](https://github.com/moq-dev/moq/pull/6534) (assemble TS
video across PES boundaries) and
[moq-dev/moq#6656](https://github.com/moq-dev/moq/pull/6656) (export
follows by cause).
- **Since 2026-10-21:** the congested path (`--headroom --rate 7000000`)
captures only the last second of its 120 s run, and the overflowing path
(`--queue 250ms`, CUBIC) starts 49 s late. Bisect
`f13283b302..dbf06bdcb3`.
- Fix each at its cause; the congestion lanes must keep their bufferbloat
shape and their assertions.

Public API: none expected. Wire: none.
1 change: 1 addition & 0 deletions quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ lite-07; bitrate enforcement is not part of this release.
- [Vulkan Video encode on AMD](/quest/m2/vulkan-encode.md) - H.264 and H.265 from an external Vulkan image on RADV, hand-rolled on ash, proven on an RX 9070
- [VA-API encodes an external Vulkan image](/quest/m2/vaapi-vulkan-import.md) - an explicit-sync DMA-BUF reaches Intel's encoder, proven on Arrow Lake
- [C++ FFI reuse](/quest/m2/cpp-ffi-reuse.md) - C++ packages link the shared default-feature FFI build once it is proven compatible
- [Upstream reports](/quest/m2/upstream-reports.md) - report the faad, retina, and mr-boxington bugs found before the cut

- [Native compression flush](/quest/m2/native-compression-flush.md) - report the per-frame nonfinal flush requirement in existing browser discussions
- [Native synchronous codecs](/quest/m2/native-compression-sync.md) - report the stateful small-frame synchronous API requirement
Expand Down
Loading
Loading