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/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ removed).
- [Announcement takeover](/quest/m1/announce-takeover.md) - a new independent route explicitly continues instances served through its predecessor, with shared Rust/JS semantics and lite-07 wire
- [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 tightened SUBSCRIBE keeps the start's budget honest](/quest/m1/start-budget-update.md) - a relay copy records the delay its start was resolved under, so a SUBSCRIBE_UPDATE tightening cannot make later readers skip fillable history
- [Aborted copies don't hold an end open](/quest/m1/settled-abort.md) - a track's declared end settles when a fetched copy finishes a group whose live copy was cut or evicted
- [Broadcast archives](/quest/m1/archive/README.md) - ANNOUNCE, TRACKS, and a SUBSCRIBE per track record every track under a prefix to any object_store, a host serves a stored broadcast back, and the catalog drops its archive pointer for a per-rendition `hls` field
- [HLS recorder target](/quest/m1/hls-record-target.md) - the moq-cli HLS recorder takes its target duration from the declared `hls` duration
Expand All @@ -153,6 +154,7 @@ removed).
- [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
- [On-demand JavaScript FETCH](/quest/m1/js-fetch-on-demand.md) - browser publishers answer IETF FETCH for evicted or uncached groups through the JS ranges request surface
- [JS evicted FETCH groups are unknown](/quest/m1/js-fetch-evicted-unknown.md) - a group evicted between listing and writing goes out as End of Unknown Range on drafts 18 and 22, not a silent skip
- [A cold moq-transport-22 copy serves its absolute floor](/quest/m1/ietf22-cold-floor.md) - a draft-22 relay copy asking from `0..` gets every held group, and `warm_backfill` covers draft 22 again
- [Rust FETCH parity](/quest/m1/ietf-fetch-parity.md) - Rust finishes an answered joining FETCH's head, refuses a lost head with DOES_NOT_EXIST, and sends no timestamps without TIMESCALE, as the JS publisher does
- [SUBSCRIBE honors the properties opt-out](/quest/m1/subscribe-timestamps.md) - the Rust publisher sends untimed objects to a SUBSCRIBE that declines Track Properties, and the Rust subscriber asks for them when it needs timestamps
- [JS FETCH timeout test](/quest/m1/js-fetch-timeout-test.md) - a JS joining FETCH still waiting on its SUBSCRIBE at the deadline is refused with TIMEOUT
Expand Down
26 changes: 26 additions & 0 deletions quest/m1/ietf22-cold-floor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# [S] A cold moq-transport-22 copy serves its absolute floor

## Goal

A relay copy that subscribes upstream over moq-transport-22 with an absolute
floor, such as `0..`, receives every group from the floor the publisher
still holds, not only the latest. `warm_backfill` in
`rs/moq-net/tests/integration` covers moq-transport-22 again.

## Plan

Decided 2026-10-29 (maintainer, `/quest-plan` of moq.pro's announce ramp
loss follow-ups): its own quest in m1, beside the other IETF fill and FETCH
quests. This quest owns the draft-22 absolute-floor backfill, and
[Rust FETCH parity](/quest/m1/ietf-fetch-parity.md) excludes it.

Found while landing [#7168](https://github.com/moq-dev/moq/pull/7168), which
dropped moq-transport-22 from `warm_backfill` for this. On `main`, the copy
records start 0, but the publisher's cursor starts at the live edge, so only
the latest group arrives. Find which side loses the floor: the subscriber's
draft-22 SUBSCRIBE or fill mapping, or the publisher's resolution of an
absolute start. Fix it there, and keep draft 18 unchanged.

## Related

- [IETF fill timeout](/quest/m1/ietf-fill-timeout.md) - the other draft-22 fill work in Rust
54 changes: 54 additions & 0 deletions quest/m1/start-budget-update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# [S] A tightened SUBSCRIBE keeps the start's budget honest

## Goal

A relay copy remembers the `max_delay` that was in effect when its
publisher resolved SUBSCRIBE_START, not only the one sent at SUBSCRIBE. If a
SUBSCRIBE_UPDATE tightens the delay before the start is picked, a later
reader whose delay is looser than the tightened one, but no looser than the
original, still fills the history between the two starts. Released wires are
unchanged.

## Plan

Decided 2026-10-29 (maintainer, `/quest-plan` of moq.pro's announce ramp
loss follow-ups): its own quest in m1, rather than waiting on
[Drop set](/quest/m1/drop-set.md) or
[Delete the old start bookkeeping](/quest/m1/subscribe-ranges/start-bookkeeping.md),
since it fixes released lite-06 behavior.

Found by review of [#7168](https://github.com/moq-dev/moq/pull/7168): the
lite subscriber sets `requested_max_delay` once, at SUBSCRIBE
(`rs/moq-net/src/lite/subscriber.rs`). `Misses` then gives up every group
below the start for any reader whose budget is no looser than that value.
After a tightening update, the start was resolved under the tighter budget,
so the recorded looser one makes some readers skip history they could have
filled. It loses history only in that window; it does not bring back #7168's
over-fetch.

Record the budget the start was actually resolved under. SUBSCRIBE_START
carries a group, not which update it was picked under, and updates can cross
it in flight, so the budget current when START arrives is not enough: an
update sent after the publisher picked the start would be recorded in its
place, too loose after a widening or too tight after a tightening. When the
subscriber cannot tell which of its sent budgets the publisher applied,
record the loosest of them. That keeps today's history loss in the
ambiguous window but never brings back the over-fetch.

Add integration tests in `rs/moq-net/tests/integration`, direct and through
a relay: subscribe, tighten before the start, then a second reader widens
partly, which fails on `main` and passes with the fix; and a tightening and
a widening that each cross an already-picked START, where the recorded
budget must never be tighter than the one the start was picked under.

Open question for whoever starts this: which lite-06 ordering, if any, tells
the subscriber the publisher applied a tightening before picking the start.
Without one, every tightening sent before START arrives stays ambiguous, the
loosest-budget rule records the SUBSCRIBE budget as today, and the Goal is
out of reach on the released wire. Then propose rewriting this quest to a
wire change for a later draft, or deleting it.

## Related

- [Drop set](/quest/m1/drop-set.md) - records the budget each drop was judged under, the same idea for drops
- [Delete the old start bookkeeping](/quest/m1/subscribe-ranges/start-bookkeeping.md) - moves where a subscription starts into the model, which should carry this field
7 changes: 7 additions & 0 deletions quest/m1/subscribe-ranges/js.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ Also mirror Rust's optional `Subscription::max_delay`
combine, and goes out as the largest delay the wire allows, where today an
omitted one means the live edge only.

Fills mirror Rust's rule from [#7168](https://github.com/moq-dev/moq/pull/7168)
(decided 2026-10-29, maintainer): give up a run below a start already
resolved under a budget at least as loose as the reader's, and on a pre-06
wire fill below the start only when the reader names a floor. `js/net`
requests no fills today, so nothing over-fetches yet; this keeps it that way
once it does.

Decided in the 2026-10-05 audit: the producer half of
JavaScript FETCH folds in here, so `@moq/net`'s
on-demand request surface takes range requests from the start instead of the
Expand Down
Loading