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
1 change: 1 addition & 0 deletions doc/lib/rs/moq-net.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ above ([hang](/lib/rs/hang)); relays and CDNs implement only this.
- **Patterns** (`Pattern`, `Patterns`) are re-exported from [`moq-pattern`](https://docs.rs/moq-pattern). Literal `Path` stays a coordinate.
- **Tracks** carry groups with a priority, a retention window, and a timescale. Subscribers set their own priority and max age and can change them live.
- **Groups** are written frame by frame and delivered on independent streams. Old groups are cached for fetch-by-sequence; stale groups are skipped per the subscriber's budget.
- **Track ends**: `finish()` ends a track at its live edge, while `finish_at(n)` declares the exclusive end ahead of it and still accepts the groups below. A subscriber awaits it with `finished()`. A remote track ends only once every group below its end has arrived or was dropped; one reset before its header arrived is skipped after the subscription's max age on moq-lite (one second without one), or after one second on IETF.
- **Datagrams** send a single small frame unreliably on moq-lite 05+.
- **Routes** record the relay hops and a cost, which is what the relay [cluster](/bin/relay/cluster) routes on. A hop of 0 marks the chain anonymous: `Route::is_anonymous()` is true, and that route ranks below every fully identified one. `Route::source()` says where a delivered route entered: `Source::Local`, or `Source::Peer(hop)` when a handle marked `origin::Producer::peer()` announced it. `origin::Consumer::local()` sees only the local ones.
- **Stats** counters per broadcast and session, drained by [`moq-stats`](https://docs.rs/moq-stats).
Expand Down
2 changes: 1 addition & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ transport, benchmark tooling); worktrees isolate commits, not semantics.
- [libmoq hidden opt-in](/quest/m1/libmoq-hidden.md) - `moq_origin_announced` takes a `hidden` flag so C callers can list `.`-named broadcasts
- [lite-07 stream count](/quest/m1/lite-stream-count.md) - moq-lite-07 replaces SUBSCRIBE_DROP with a group-stream count in SUBSCRIBE_END, like moq-transport
- [Announce compression](/quest/m1/announce-compression.md) - a lite-07 announce reuses the path head and hop-chain tail of a live announcement on its stream instead of resending them
- [Rust track tail](/quest/m1/rust-track-tail.md) - a moq-net subscriber accepts groups that arrive after the subscription's end, and PublishDone carries the real stream count
- [Session death error](/quest/m1/session-death-error.md) - a dying session ends its tracks with its own error in Rust and JS, never a clean end, `Dropped`, or `Cancel`
- [JS bare FIN](/quest/m1/js-bare-fin.md) - a `@moq/net` subscriber aborts a track whose subscribe stream FINs before its declared end, like Rust
- [Track tail interop](/quest/m1/track-tail-interop.md) - a Rust publisher ending a track with a group in flight is read to its end by the JS subscriber, and the reverse, in `just test interop`
- [Signal.race cleanup](/quest/m1/signal-race.md) - `Signal.race` releases its signal listeners when its result loses a race
- [Origin narrowing](/quest/m1/origin-narrowing.md) - a live origin grant narrows in place and ends the subscriptions it no longer covers, the deafen boundary #2714 asked for
- [Auth expiry clock](/quest/m1/auth-expiry-clock.md) - moq-auth and the relay hold one fixed expiry deadline and honour the same skew allowance
Expand Down
10 changes: 5 additions & 5 deletions quest/m1/lite-stream-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ before its header arrived is still invisible, so the track-tail grace stays.
the upstream count.
- Subscribers on lite-07 stop waiting once the count is reached, accepting a
late stream below the end within the grace. On lite-05 and -06, the
DROP accounting from JS track tail (#4086) stays as it is.
DROP accounting already in moq-net (`rs/moq-net/src/tail.rs`) and `@moq/net`
(`js/net/src/tail.ts`) stays as it is.
- Tests in both languages: a late stream after SUBSCRIBE_END, a skipped group
that is never counted, a reset stream, and a count of zero. Add a Rust-JS
interop case.

This lands before lite-07 is finalized. Rust has never sent or acted on
SUBSCRIBE_DROP, so [Rust track tail](/quest/m1/rust-track-tail.md) builds its
lite accounting on the count rather than on drops.
This lands before lite-07 is finalized. Published drafts keep SUBSCRIBE_DROP,
which moq-net and `@moq/net` already account. lite-07 replaces it with the
count in both. Rust still does not send SUBSCRIBE_DROP.

## Related

- [Rust track tail](/quest/m1/rust-track-tail.md) - builds on this count for moq-lite
- [Reliable stream reset](/quest/m1/quic/reliable-reset.md) - makes the count exact by keeping a reset stream's header
10 changes: 5 additions & 5 deletions quest/m1/quic/reliable-reset.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@ the native interop matrix.
Then use it in MoQ. A publisher that resets a group stream uses a Reliable
Size covering the group header, so the subscriber can always attribute the
reset to its group. Once reliable reset is negotiated, subscribers drop the
grace they wait for missing groups below a track's declared end (see the track
tail quests). Browsers keep the grace until WebTransport exposes
reliable reset.
grace they wait for missing groups below a track's declared end
(`rs/moq-net/src/tail.rs`, `js/net/src/tail.ts`). Browsers keep the grace until
WebTransport exposes reliable reset.

Track the unversioned draft during implementation. The planning baseline is
draft 10, with transport parameter `0x1d` and frame type `0x24`; do not freeze
provisional codepoints if the document changes before release.

## Related

- [Rust track tail](/quest/m1/rust-track-tail.md) - waits a grace for a group
whose reset lost its header until this lands, as `@moq/net` already does
- moq-net (`rs/moq-net/src/tail.rs`) and `@moq/net` (`js/net/src/tail.ts`) wait
a grace for a group whose reset lost its header until this lands
- [qmux on the QUIC stream state machine](/quest/m1/quic/qmux.md) - consumes
the same reset state without a parallel implementation
- The removed quiche backend was the one stack that had this, so it is the
Expand Down
60 changes: 0 additions & 60 deletions quest/m1/rust-track-tail.md

This file was deleted.

4 changes: 0 additions & 4 deletions quest/m1/session-death-error.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,3 @@ controls: a finished track still ends clean while its session lives.
## Closes

- [#4061](https://github.com/moq-dev/moq/issues/4061) - close this issue when the quest finishes

## Related

- [Rust track tail](/quest/m1/rust-track-tail.md) - the clean-end half: a track that did end is delivered whole
34 changes: 34 additions & 0 deletions quest/m1/track-tail-interop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# [S] Track tail interop

## Goal

`just test interop` covers a publisher that ends a track while its last group
is still in flight: a Rust publisher's track is read to its declared end by the
JS subscriber, and a JS publisher's by the Rust subscriber, through the relay.
Each reader gets every group below the end and then a clean end, never an
error or a stall.

## Plan

Both moq-net and `@moq/net` wait for a track's tail once the publisher ends a
subscription, and each is covered by its own in-process tests. Nothing checks
that the two agree across a relay on real QUIC.

What stood in the way when the Rust half landed:

- `moq import` exits the moment stdin ends, closing its session with the tail
still in flight, so a finite CLI publisher cannot end a track cleanly. The
fix is a publisher that waits for its subscriptions to drain before it
closes; `moq export`'s linger ([Export linger](/quest/m1/export-linger.md)) is
the reader-side cousin.
- The native JS subscriber (`test/interop/clients/js-native`) returns on the
first frame. It needs a mode that reads a track to its end and reports how it
ended and which groups it saw.

QUIC on localhost rarely reorders, so this is a smoke check that the end is
delivered and clean. The ordering race itself stays in the unit tests.

## Related

- [Session death error](/quest/m1/session-death-error.md) - the other way a
track ends wrong
Loading
Loading