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
9 changes: 5 additions & 4 deletions quest/m0/audio-quality-budgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ measures on an `ubuntu-24.04-arm` runner. A red job nobody can act on hides
real regressions, so this moved out of Watch into m0 (maintainer,
2026-10-13).

- Measure several nightly runs, or a matrix dispatched on the runner from
the branch, before setting ceilings. A single sample's noise would make
- Measure across several scheduled nightly runs before setting ceilings;
Nightly is never dispatched from a branch. A single sample's noise would make
the job flaky. Failing runs keep their summaries as the
`audio-quality-run` artifact for 7 days.
- Set each ceiling from the observed spread with modest headroom, and record
Expand All @@ -33,8 +33,9 @@ real regressions, so this moved out of Watch into m0 (maintainer,
rows stalling a third of the time look like one. Budget what the player
does today, and file each suspected defect as a follow-up quest, so the job
goes green without hiding it.
- Rows that are too noisy to bound on a shared runner can be dropped from
`--enforce` instead. That decision needs the maintainer.
- Every row stays budgeted (decided 2026-10-13): a noisy row gets a wider
ceiling from its measured spread. The harness has no per-row opt-out, and
none is added.

Public API: none. Wire: none.

Expand Down
2 changes: 2 additions & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ disabled rung strands WHEP, HLS, and moq-mux export viewers.
- [JSON window timestamps](/quest/m1/json-window-timestamps.md) - Rust and JS window consumers return each event's frame timestamp like the snapshot and stream consumers
- [The catalog root clock is the producer clock](/quest/m1/catalog-clock-adopt.md) - a derivative adopts its input's wall mapping through `modify()`, and a root `clock` change after the clock is fixed is refused
- [Exact catalog wall clock](/quest/m1/catalog-wall-clock-precision.md) - `hang::catalog::Clock::wall_clock` keeps sub-millisecond precision
- [JavaScript answers TRACK_STATUS](/quest/m1/js-track-status.md) - a browser publisher answers IETF TRACK_STATUS like Rust, so a native fetch-only request needs no SUBSCRIBE fallback
- [JavaScript FETCH](/quest/m1/js-fetch.md) - browser publishers answer IETF FETCH through the JS ranges request surface
- [IETF fill timeout](/quest/m1/ietf-fill-timeout.md) - native FILL_TIMEOUT bounds upstream waiting on drafts 18-22, alongside local content-age enforcement
- [IETF group ingest refuses loudly](/quest/m1/ietf-ingest-refusal.md) - a subgroup other than 0 or a datagram past object 0 aborts the track, and a peer's malformed group is refused rather than dropped at debug
Expand Down Expand Up @@ -175,6 +176,7 @@ disabled rung strands WHEP, HLS, and moq-mux export viewers.
- [Route wakes](/quest/m1/route-wakes.md) - a route change wakes only the fronts it can move, so pool churn stops scaling with served paths
- [Publish channel count](/quest/m1/publish-audio-channel-count.md) - forcing a channel count on an Audio.Capture stops costing the subscriber gaps of silence
- [JS request deadline](/quest/m1/js-request-deadline.md) - each JS request, PUBLISH_NAMESPACE included, has one fatal 10 s timer from create to answer and fails fast without stream credit, so nothing queues or retries
- [JS cancellation bench](/quest/m1/js-forget-bench.md) - the requests bench sweeps cancellation over competing dynamic routes, so a per-cancel cost that grows with routes shows as a slope
- [Rust request credit](/quest/m1/rs-request-credit.md) - a moq-net request fails at once without stream credit instead of waiting
- [qmux no-wait opens](/quest/m1/qmux-no-wait.md) - @moq/qmux rejects an over-limit create when waitUntilAvailable is false, like Chrome
- [E2EE](/quest/m1/e2ee/README.md) - TypeScript and Rust peers interoperate over encrypted broadcasts no relay can decrypt
Expand Down
8 changes: 4 additions & 4 deletions quest/m1/js-fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ no `NotFetchable` code, since nothing would send it. Only lite-07 has the
code, and lite-07 drops FETCH for [ranges](/quest/m1/subscribe-ranges/lite.md);
lite-05 and lite-06 answer `NotFound`.

Since #4974, a native fetch-only request asks TRACK_STATUS before its first
FETCH, so the `@moq/net` publisher answers TRACK_STATUS too (a #4974
follow-up, folded in here because answering only matters once JS serves
FETCH).
Answering TRACK_STATUS, which a native fetch-only request asks before its
first FETCH, split out to [JavaScript answers TRACK_STATUS](/quest/m1/js-track-status.md)
(2026-10-13): it does not need FETCH.

Verify with an in-memory application responder: a browser publisher serves a
native IETF subscriber after a group is evicted or was never cached. Run the
Expand All @@ -44,6 +43,7 @@ claims that change.

## Related

- [JavaScript answers TRACK_STATUS](/quest/m1/js-track-status.md) - answers the TRACK_STATUS a native fetch-only request sends first
- [Browser archive](/quest/m3/archive-browser.md) - supplies memory or OPFS archive data through the same request surface
- [IETF fill timeout](/quest/m1/ietf-fill-timeout.md) - native timeout budgets and gap dispositions build on this responder
- [FETCH max-delay](/quest/m1/fetch-max-delay.md) - local per-reader age limits also apply to historical data
27 changes: 27 additions & 0 deletions quest/m1/js-forget-bench.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# [XS] Bench JS request cancellation across competing routes

## Goal

`js/net/bench/requests.ts` sweeps request cancellation over the number of
`dynamic()` routes competing for one path and the number of cancelled
requests, so a per-cancel cost in `OriginState.forget` that grows with the
routes shows up as a slope.

## Plan

#5411 made cancellation release origin demand. Codex flagged on that PR that
`forget` walks every route and failover slot on each cancellation; the merge
argued the walk only covers the cancelled path's own prefixes, the same
entries `bestEntry` already scans. Both cancellation sweeps in the bench use a
single route today, so neither claim is measured.

Add the two-axis sweep (for example 1/16/128 routes on one prefix by
1/64/1024 cancellations). If it shows a slope, fix `forget` in the same PR,
starting with computing the failover-entry set once instead of copying it in
the inner loop.

Public API: none. Wire: none.

## Related

- [JS request deadline](/quest/m1/js-request-deadline.md) - every timed-out request releases its demand through the same path
42 changes: 42 additions & 0 deletions quest/m1/js-track-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# [S] JavaScript answers TRACK_STATUS

## Goal

A `@moq/net` publisher answers IETF TRACK_STATUS on every draft instead of
refusing every one with NOT_SUPPORTED, so a native fetch-only request on
drafts 14-16 and 18-22 learns the track in one round trip rather than falling
back to SUBSCRIBE. Draft 17 still subscribes, since its answer cannot say
whether the track is timed.

## Plan

Since #4974, a native subscriber asks TRACK_STATUS for demand without a
subscription. #5409 found that the relay's IETF publisher can make a reader's
first request look fetch-only, and that against a JS publisher the refusal
failed the track; the Rust subscriber now falls back to SUBSCRIBE on
NOT_SUPPORTED, at the cost of an extra round trip.

Decided 2026-10-13: mirror the Rust publisher
(`rs/moq-net/src/ietf/publisher.rs`, `run_track_status_stream`). Check the
grant before resolving, resolve the broadcast through the serving origin like
a SUBSCRIBE (dynamic handlers included), wait for the track's info, and answer
TRACK_STATUS_OK. A requester that cancels is owed nothing and releases its
demand through the path #5411 added. Errors map to the same refusal codes as
Rust.

Split out of [JavaScript FETCH](/quest/m1/js-fetch.md), which is blocked on
JS ranges; answering TRACK_STATUS does not need FETCH.

Verify with a native IETF subscriber against a browser publisher: on drafts
14-16 and 18-22 a fetch-only request gets TRACK_STATUS_OK with no SUBSCRIBE
fallback, while draft 17 keeps subscribing (`TrackStatusOk::describes_track`).
On every draft, a cancelled request releases origin demand and a request
outside the grant is refused. Run `just test interop --all`.

Public API: none. Wire: implement the existing TRACK_STATUS and
TRACK_STATUS_OK formats in JS; drop JavaScript from the TRACK_STATUS refusals
in `doc/concept/standard.md`.

## Related

- [JavaScript FETCH](/quest/m1/js-fetch.md) - serves the FETCH that follows this answer
1 change: 1 addition & 0 deletions quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,4 @@ and bench readiness. Refusal reasons folded the same day into
- [Catalog broadcast references in MSF and GStreamer](/quest/m2/catalog-broadcast-reference.md) - MSF conversion and the GStreamer source honor a rendition's `broadcast` or refuse it, instead of resolving it in the catalog's own broadcast
- [Binding track resolver](/quest/m2/binding-track-helper.md) - binding apps subscribe to a rendition without inlining `track` or the key
- [Exporters follow a rendition to a new track](/quest/m2/export-rendition-rebind.md) - the fMP4, TS, MKV and FLV exporters rebuild a rendition whose resolved `track` or `broadcast` changes under the same ID
- [IETF driver double poll](/quest/m2/ietf-driver-double-poll.md) - a fired deadline costs a moq-transport session's driver one poll, as #5393 makes moq-lite's
24 changes: 24 additions & 0 deletions quest/m2/ietf-driver-double-poll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# [S] A fired deadline costs a moq-transport driver one poll

## Goal

A moq-transport (IETF) session's driver is polled once per fired
`time::Deadline`, as #5393 makes a moq-lite session's, and
`rs/moq-net/tests/idle_session.rs` bounds the IETF driver at one poll per
refresh too.

## Plan

Start after #5393 (open as of 2026-10-13) merges, and remeasure on top of it.
#5393 adds `kio::Waiter::batch`, which holds a `Tasks` set's wake of its own
owner during that owner's poll. On that branch, IETF sessions still poll
twice: the driver is a boxed future, so its children's sets are woken inside
nested polls that the batch scope does not cover. Find where the nested poll
escapes the scope and cover it, or restructure the driver so its children
belong to the driver's own `Tasks` set.

Measure with the existing `session_idle` bench and the poll-counting harness
(`rs/moq-net/tests/support/harness.rs`).

Public API: none expected. Wire: none.

Loading