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: 0 additions & 2 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ transport, benchmark tooling); worktrees isolate commits, not semantics.
- [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`
- [Interop flakes](/quest/m1/interop-flakes.md) - the interop harness passes with other runs sharing the machine
- [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
- [Binding audio delay](/quest/m1/binding-surface.md) - moq-ffi, libmoq, and every wrapper configure and observe audio playout delay
- [FFI shape](/quest/m1/ffi-shape/README.md) - the bindings mirror Rust's layers: net at the root, then media, json, audio, and video namespaces built from the handle below
- [Track demand](/quest/m1/track-demand.md) - Rust and JS watch a track's subscribers through `demand()` alone
- [Broadcast close](/quest/m1/broadcast-close/README.md) - `close()` is the one way to end a broadcast in every language, a permanent retraction that leaves in-flight tracks alone
- [Relay peer set](/quest/m1/relay-peer-set.md) - a wire consumer tells a client hop from a peer hop, and every mesh credential can mark a peer
- [CLI inspection](/quest/m1/cli-inspect/README.md) - `moq ls` lists what is live and `moq fetch` reads a group over MoQ, and a guide shows how to inspect a relay
- [Session close](/quest/m1/session-close.md) - a graceful session end withdraws announces and waits one second for the ack
- [JS caught up](/quest/m1/js-announce-caught-up.md) - @moq/net's announce consumer says when the initial set has landed, like Rust
Expand Down
7 changes: 4 additions & 3 deletions quest/m1/auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Decisions settled while planning, recorded so review does not relitigate them:
the union and cancels publications and subscriptions that lose authorization.
Other authorized work continues on the same session. An empty union leaves
the session connected with no access, so it can accept a fresh token.
[Origin narrowing](/quest/m1/origin-narrowing.md) owns the common resize
[Origin narrowing](/quest/m1/auth/narrowing.md) owns the common resize
operation; relay token handling requires it rather than shipping a temporary
close-on-shrink policy.
- **A public grant contains publish patterns, subscribe patterns, and an
Expand Down Expand Up @@ -96,6 +96,9 @@ existing lite-06 ALPN.
each lite-06 cell's grant and that a publish outside it fails loud
- [Unauthorized reset](/quest/m1/auth/unauthorized.md) - a subscription that
loses access resets with a dedicated UNAUTHORIZED stream code
- [Origin narrowing](/quest/m1/auth/narrowing.md) - a live grant narrows in
place: subscriptions outside it reset, publishes outside it abort, and relay
revalidation stops closing the session
- [Relay tokens](/quest/m1/auth/relay-refresh.md) - the relay verifies tokens
sent in band, unions their grants, and cancels only work that loses access
- [Request tokens](/quest/m1/auth/request-token.md) - an `AUTHORIZATION
Expand All @@ -113,8 +116,6 @@ existing lite-06 ALPN.

## Related

- [Origin narrowing](/quest/m1/origin-narrowing.md) - resizes a live session
when the union shrinks, for revalidation and token expiry alike
- [Pattern interest](/quest/m1/path-patterns.md) - moves AUTH's legacy wire prefixes to patterns along with ANNOUNCE_REQUEST
- [Expiring media grants](/quest/m1/processor/grant-lease.md) - a worker's
lease renewal is a new in-band token
Expand Down
58 changes: 58 additions & 0 deletions quest/m1/auth/narrowing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# [M] A live origin grant narrows in place

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the moved quest reference

Moving this quest leaves rs/moq-relay/src/auth.rs:277 pointing to the deleted quest/m1/origin-narrowing.md; a repo-wide git grep finds this as the only remaining old-path reference. Update it to quest/m1/auth/narrowing.md so readers of Lease::ended can still reach the plan.

AGENTS.md reference: AGENTS.md:L27-L27

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6b8d1be (also updated the new quest/m1/auth/request-token.md reference that arrived with main).

(Written by Claude Opus 5.5)


## Goal

A `moq-net` session's grant can be replaced by a narrower pattern union
while the session is live: announce cursors retract the patterns that fell
outside, resolution refuses them, subscriptions under them reset with
`UNAUTHORIZED`, and broadcasts the session published under them abort. The
relay uses it on revalidation so a moderation decision (a deafened user's
audio path) takes effect on the session it targets, which a forked client
cannot bypass. This is the per-subscriber exclusion
[#2714](https://github.com/moq-dev/moq/issues/2714) asked for; the scope and
match half already landed in #3672 and #3746.

A narrowing always succeeds. A changed root still closes the session.

## Plan

- Enforce per session, not per handout. The line's session gate for received
grants (`auth::Gate`, the lite publisher resetting subscriptions it denies,
`regrant` retracting announces no longer covered, and the IETF equivalent)
is the same mechanism pointed at the relay's own grant. Reuse it rather than
building a second one. Readers that bypass the session publisher (HTTP
`/fetch` holds its own lease and closes on it; moq-hls and WHEP enforce no
per-user grant today) are out of scope.
- #3971 built narrowing alone and was closed: it refused whenever anything
live sat in the removed part, which is exactly when a grant narrows, and it
kept the ceiling in a side map. Scopes today are copied by value into every
handle and cursor (`OriginScope` in `rs/moq-net/src/model/origin.rs`), so
narrowing needs shared state. If handles need a tree to share it, keep the
ceiling on the grant node itself (an `Arc` shared by clones and children).
- Publish side: routes and broadcasts the session published outside the
narrowed grant abort, so consumers see `Unauthorized` just as the subscribe
side does. Draining is not an option: a group may stay open as long as its
track.
- Relay revalidation uses it: a re-checked grant with the same root narrows
the session instead of closing it (`Lease::ended` reporting "grant
narrowed" in `rs/moq-relay/src/auth.rs`), on every accept path: native,
io_uring, and `moq --listen` share `connection::supervise`, while WebSocket
has its own copy of the loop.
- Prove the deafen case end to end: subscribe under a room prefix, narrow
with a grant that excludes that audio path, and assert the subscription
resets with `UNAUTHORIZED` and no further objects arrive, while a sibling
path under the same prefix keeps flowing.
- Benchmark the narrowing and per-session gate cost in
`rs/moq-net/benches/origin.rs`, swept over routes and subscribers, with a
session that never narrows as the baseline.

Public API: additive on moq-net and on moq-relay's revalidate path. Wire:
none beyond the UNAUTHORIZED code the required quest adds.

## Required

- [Unauthorized reset](/quest/m1/auth/unauthorized.md) - the stream code a narrowed subscription resets with

## Closes

- [#2714](https://github.com/moq-dev/moq/issues/2714) - close this issue when the quest finishes
4 changes: 2 additions & 2 deletions quest/m1/auth/relay-refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ expiry, an expiry that leaves the union intact ends only that token, and
publish-only session never starts receiving announcements because a later
token happened to carry subscribe prefixes, and swapped in whenever the set
grows; keep it behind one function, and a shrinking union goes through
[Origin narrowing](/quest/m1/origin-narrowing.md) rather than a close.
[Origin narrowing](/quest/m1/auth/narrowing.md) rather than a close.
- Expiry: the deadline today is the admitted lease's `closed()` inside one
`tokio::select!` arm. Select on one lease per token in the set instead, and on any firing recompute the union without it: unchanged
means `AUTH_ERROR { Expired }` on that token's stream and the session
Expand Down Expand Up @@ -80,7 +80,7 @@ Additive.

## Required

- [Origin narrowing](/quest/m1/origin-narrowing.md) - the live re-scope a shrinking token union needs, so no temporary close-on-shrink policy ships
- [Origin narrowing](/quest/m1/auth/narrowing.md) - the live re-scope a shrinking token union needs, so no temporary close-on-shrink policy ships
- [Pattern interest](/quest/m1/path-patterns.md) - AUTH can represent the complete grants relay revalidation returns
- [Lite stream](/quest/m1/auth/lite.md) - supplies the AUTH stream and
`auth::Request` this consumes
Expand Down
2 changes: 1 addition & 1 deletion quest/m1/auth/request-token.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ on the unknown key, and the legacy drafts silently ignore it.
until it lapses. When a request's grant expires or is revoked, that request
alone ends with `EXPIRED_AUTH_TOKEN` or `UNAUTHORIZED`. A session grant
that shrinks cancels the requests it covered, as for any request, through
[Origin narrowing](/quest/m1/origin-narrowing.md).
[Origin narrowing](/quest/m1/auth/narrowing.md).
- Relay: each such request attaches its own lease through the
`Client::attach` path [Relay tokens](/quest/m1/auth/relay-refresh.md)
builds, once per request, with no sharing across requests carrying the
Expand Down
72 changes: 0 additions & 72 deletions quest/m1/origin-narrowing.md

This file was deleted.

31 changes: 0 additions & 31 deletions quest/m1/relay-peer-set.md

This file was deleted.

1 change: 1 addition & 0 deletions quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ upstream release waits in [m4](/quest/m4/README.md).
- [Compressed tracks](/quest/m2/flate/README.md) - any track compresses per group from every language, not only the JSON modes
- [Binary delta stats](/quest/m2/stats-delta.md) - an on-demand varint delta flavor of every stats track, if relay encode CPU still matters after the JSON fixes
- [#3115](/quest/m2/3115-moqsink-the-publication-has-no-generation-so-a-flush.md) - moqsink: a flushing restart after EOS opens a new publication generation
- [Plan: routing without a hop list](/quest/m2/plan-routing-origin.md) - whether announcements can drop the hop list and stay loop-free once stitching keys on the subscribe reply
- [Redundant ingest](/quest/m2/redundant-ingest.md) - decide whether two publishers sharing one epoch may splice, and who declares the incumbent dead before the keep-alive does
- [Multipath spike](/quest/m2/multipath-spike.md) - whether bonded contribution over multipath QUIC is worth building, given it needs noq on both ends
- [Receive timestamps](/quest/m2/quic-receive-ts.md) - per-packet arrival times in ACKs, the feedback GCC and deadlines need
Expand Down
41 changes: 41 additions & 0 deletions quest/m2/plan-routing-origin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# [M] Plan: routing without a hop list

## Goal

Decide whether moq-lite announcements can drop the full hop list and still
route loop-free, then write the decision into quests. Today every
announcement carries the Hop IDs it traversed. That path does three jobs:
loop prevention (a relay discards a path containing itself), request
exclusion (never serve a request back through the peer that made it), and
route identity (the first hop decides whether a failover may stitch
seamlessly). The hop list was designed before prefix claims, and once the Spread quest in
[Wildcard advertisements](/quest/m1/wildcard/README.md) moves stitching
identity onto the subscribe reply, only the first two jobs remain.
Comment on lines +11 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for hop-list-based route selection

When routes have equal costs, including common cost=0 sibling links, the hop chain still has routing duties after stitching identity moves: route_order in rs/moq-net/src/model/origin.rs:585-600 ranks identified over anonymous routes, then uses hop count and a hash of the entire chain before recency. Saying only loop prevention and request exclusion remain lets the follow-on drop those inputs and select the newest route instead of the shortest, stably hashed route. Include replacement decisions for anonymity, hop count, and deterministic tie-breaking in this plan.

Useful? React with 👍 / 👎.


## Plan

Open questions, to settle with the maintainer:

- Loop freedom without a path. Rising cost alone ("cost + 1, never
advertise lower") counts to infinity after a withdrawal, as two relays
offer each other the stale route at ever higher cost. Remembering each
route's immediate neighbor and never echoing a route back to it (split
horizon) stops two-relay loops, but not three-relay loops. It also hides
backups: a relay never learns an alternative that passes back through the
neighbor it came from. Babel's feasibility condition (RFC 8966: a
per-origin sequence number; a route is feasible when its sequence number is
newer, at any cost, or equal and cheaper than the best seen for it) is
loop-free with only the origin on the wire. Weigh it and
any simpler scheme against what the relay cluster actually needs.
- What replaces request exclusion, and whether it still matters once
announcements are loop-free.
- What the stats and sidecar consumers lose without a path, and whether
anything besides the origin must stay on the wire.
- The version it lands in (lite-07 is `moq-lite-07-wip` today) and the
bridge to versions that still carry a hop list. lite-07 already compresses
each announcement's hop chain against a live base (#4196,
`rs/moq-net/src/lite/compress.rs`); dropping the hop list removes that too.

## Related

- [Wildcard advertisements](/quest/m1/wildcard/README.md) - its Spread quest moves stitching identity to the subscribe reply, which this builds on
2 changes: 1 addition & 1 deletion rs/moq-relay/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ impl Lease {
/// revoked, or was re-checked into one that no longer covers the token.
///
/// A changed root or a narrower grant ends it: origin handles cannot yet narrow
/// a live scope in place (tracked by `quest/m1/origin-narrowing.md`). A flipped
/// a live scope in place (tracked by `quest/m1/auth/narrowing.md`). A flipped
/// `peer` ends it too, since the routes it already announced would be
/// misreported as entering here or from a peer. A changed tier keeps the
/// session and moves its [stats](Self::with_stats) to the new tier.
Expand Down
Loading