Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a62b26d
quest: claim quest/m1/quic/fork/switch
kixelated Oct 16, 2026
590d323
feat(moq-tokio): import quinn's async layer and web-transport-moq ver…
kixelated Oct 16, 2026
e8195bd
feat(quic)!: run moq-tokio and moq-uring on moq-quic
kixelated Oct 16, 2026
282197e
claim quest/m1/quic/scheduler
kixelated Oct 16, 2026
866b13d
fix(moq-tokio): log a CONNECT stream cut off by the close at debug
kixelated Oct 16, 2026
88a6fae
docs: point fork and advisory guidance at moq-quic
kixelated Oct 16, 2026
2d50267
docs: format the upgrade note
kixelated Oct 16, 2026
c2993ca
quest: finish quest/m1/quic/fork/switch
kixelated Oct 16, 2026
fcd8ea4
Merge origin/main into quest/m1/quic/fork/switch
kixelated Oct 16, 2026
e111abf
test(moq-tokio): gate the timed helper with its only caller
kixelated Oct 16, 2026
5b7bff2
Merge origin/main into quest/m1/quic/fork/switch
kixelated Oct 16, 2026
43193f9
Merge remote-tracking branch 'origin/main' into quest-switch-alias
kixelated Oct 16, 2026
188b08c
fix(tokio): mark quic::web and quic::driver error enums non_exhaustive
kixelated Oct 16, 2026
5d21b4f
fix(tokio): count in-flight accepts in wait_all_draining
kixelated Oct 16, 2026
e05a711
feat(moq-quic)!: schedule streams in send groups
kixelated Oct 16, 2026
9db3b98
feat(moq-net)!: give every subscription its own send group
kixelated Oct 16, 2026
e09b3b4
quest: finish quic/scheduler
kixelated Oct 16, 2026
21cac2b
fix(tokio): wake draining waiters when accept empties the queue
kixelated Oct 16, 2026
3e3eec2
Merge remote-tracking branch 'origin/quest/m1/quic/fork/switch' into …
kixelated Oct 16, 2026
c1f4cfd
fix(tokio): surface non-WouldBlock receive errors, cap moq_quic logs
kixelated Oct 16, 2026
5f9b8d9
fix(moq-net): gate GroupOf on the async feature
kixelated Oct 16, 2026
270e630
Merge remote-tracking branch 'origin/quest/m1/quic/fork/switch' into …
kixelated Oct 16, 2026
437eee9
refactor(transport): one set_priority, seal the group adapter traits
kixelated Oct 16, 2026
674746b
Merge remote-tracking branch 'origin/main' into quest/m1/quic/scheduler
kixelated Oct 16, 2026
ee83984
Merge remote-tracking branch 'origin/main' into quest/m1/quic/scheduler
kixelated Oct 16, 2026
b1920f1
Merge origin/main into quest/m1/quic/scheduler
kixelated Oct 16, 2026
409da0b
Merge branch 'main' of github.com:moq-dev/moq into quest/m1/quic/sche…
kixelated Oct 16, 2026
47613a5
Merge branch 'main' of github.com:moq-dev/moq into quest/m1/quic/sche…
kixelated Oct 16, 2026
188a508
refactor(transport): send-group priority is i64, like stream priority
kixelated Oct 16, 2026
76296c7
Merge remote-tracking branch 'origin/main' into quest/m1/quic/scheduler
kixelated Oct 16, 2026
39dbc17
quest(m2): plan dropping web-transport-trait from the Rust stack
kixelated Oct 16, 2026
9c41dc6
Merge origin/main into quest/m1/quic/scheduler
kixelated Oct 16, 2026
1031168
Merge branch 'main' of github.com:moq-dev/moq into quest/m1/quic/sche…
kixelated Oct 16, 2026
2c16b11
Merge branch 'main' of github.com:moq-dev/moq into quest/m1/quic/sche…
kixelated Oct 16, 2026
8836fc4
doc(moq-lite): scope equal-priority fairness to native stream data
kixelated Oct 16, 2026
ddeb523
doc(moq-lite): datagrams join the fair split later
kixelated Oct 16, 2026
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: 1 addition & 1 deletion doc/concept/moq-lite.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ Each subscription carries the knobs that decide behavior under congestion:

| Knob | Effect |
| --- | --- |
| **Priority** (0..255) | Higher-priority tracks get bandwidth first. Audio above video, base layer above enhancement. |
| **Priority** (0..255) | Higher-priority tracks get bandwidth first. Audio above video, base layer above enhancement. From a native Rust publisher over QUIC or WebTransport (iroh excepted), subscriptions at the same priority split stream bandwidth evenly by bytes, however many groups each has queued. Datagrams are not part of that split yet. |
| **Order** | Which group to send first when several are pending. Newest first for live (the default), oldest first for catch-up. Needs moq-lite 07 or moq-transport; older moq-lite always sends newest first. |
| **Max delay** | How long a non-latest group stays worth delivering before it is skipped. Zero means "live edge only", and raising it is also what asks for history. |

Expand Down
3 changes: 0 additions & 3 deletions quest/m1/quic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ cache limits remain separate; bitrate pacing composes with this memory cap.
- [A reset group keeps its header](/quest/m1/quic/group-reset.md) - a lite
publisher resets a group with `RESET_STREAM_AT`, so its subscriber drops the
tail grace
- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - strict
subscription priority, fair buckets, and newest-first group order replace
the lossy scalar; retransmits follow the same order
- [Schedule datagrams by subscription priority](/quest/m1/quic/datagram-priority.md) -
datagrams join their subscription's send group instead of preempting every stream
- [Relay peers get wider limits](/quest/m1/quic/peer-limits.md) - MAX_STREAMS
Expand Down
8 changes: 3 additions & 5 deletions quest/m1/quic/datagram-priority.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Decided 2026-10-10 with the maintainer:
datagram track starve streams up to the congestion window, which is what
every stack does today.
- **A datagram queue per send group.** Each send group (one per
subscription, from [the scheduler](/quest/m1/quic/scheduler.md)) owns a
subscription, from `moq-quic`'s `SendGroups`) owns a
datagram queue. Datagram bytes spend
the group's fair-share credit, so a datagram-heavy subscription buys no
extra bandwidth over its equal-priority peers. The datagram send API takes
Expand Down Expand Up @@ -103,10 +103,8 @@ on the browser's WebTransport, which cannot rank a datagram against
a stream, so it ignores the handle and order and keeps its current
best-effort send. Wire: none.

## Required

- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - supplies
the send groups and fair tier the datagram queues join
Docs: the Priority row in `doc/concept/moq-lite.md` says datagrams are not
part of the equal-priority byte split yet; drop that once they are.

## Related

Expand Down
1 change: 0 additions & 1 deletion quest/m1/quic/receive-memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,5 @@ separate guide quest is needed.

- [Unbounded groups](/quest/m2/unbounded-groups/README.md) - removes the frame cap; frame payload credit becomes per segment
- [Scope track priority](/quest/m1/track-priority-scope.md) - broadcast fairness domains and subscription priority semantics
- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - share priority semantics without requiring sender-side recovery
- [QUIC bitrate caps](/quest/m2/rate-quic.md) - pace credit grants inside the independently bounded memory allowance
- [Relay peers get wider limits](/quest/m1/quic/peer-limits.md) - client and peer windows must both fit supported units
122 changes: 0 additions & 122 deletions quest/m1/quic/scheduler.md

This file was deleted.

5 changes: 0 additions & 5 deletions quest/m1/track-priority-scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,6 @@ Public API impact: `u8` priority fields become `i8` in every language, and
in format, but the default byte moves from 127 to 128 on moq-lite and from 128
to 127 on IETF. Report both with the draft change.

## Required

- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - the fair
tier the broadcast domains and subscription send groups ride on

## Related

- [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - owns the group
Expand Down
1 change: 1 addition & 0 deletions quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ ranked just below deterministic TS legs, which it requires.
become resets, and a tail loss probe fires early while there is still time
- [qmux on the QUIC stream state machine](/quest/m2/quic-qmux.md) - qmux is a
first-class crate over `moq-quic`'s shared stream state machine
- [Drop web-transport-trait](/quest/m2/drop-web-transport-trait.md) - every backend implements moq-net's `transport::poll` traits, and the generic `web_transport_trait` adapters are deleted
- [Align BBR loss handling with draft-06](/quest/m2/quic-bbr-loss-parity.md) - losses use their own sample and the draft-05 links go, keeping the spurious-loss undo that already re-enters ProbeUp through Refill
- [Measure ECN on the backbone](/quest/m2/quic-ecn-measure.md) - a written
verdict on marking versus dropping, and whether Linode and OVH keep marks
Expand Down
47 changes: 47 additions & 0 deletions quest/m2/drop-web-transport-trait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# [L] Drop web-transport-trait from the Rust stack

## Goal

moq-tokio, moq-uring, moq-relay, moq-ffi and moq-wasm no longer depend on
`web-transport-trait`. The qmux, iroh and wasm backends implement moq-net's
`transport::poll` traits, either directly or through a thin adapter per
backend. The generic adapters over `web_transport_trait` are deleted:
moq-tokio's `transport::Session<S>` with its async-to-poll emulation, and
moq-uring's `transport::Session<S>`. The sealed `Grouped`/`GroupedSend` pair
goes with them. A custom transport implements moq-net's traits, which are
already generic and send-group-aware (`Session::send_group`,
`SendStream::Group`, `Ungrouped`).

## Plan

Decided 2026-10-16 in the review of #5711: the extension point for custom
transports is moq-net's `transport::poll`, not `web_transport_trait`. #5711
sealed the adapters' bound to the crate's own backends, so a foreign
`web_transport_trait::Session` no longer fits them. This quest removes the
layer instead of reopening it.

- Native QUIC (`moq_tokio::quic::web`, `moq_uring::quic::web`) implements
`poll::Session` itself, keeping its real send groups. It is a candidate for
the first step, since its `web_transport_trait` impl only feeds the adapter.
- qmux and iroh get their own impls. Flat backends use `Ungrouped`.
- The browser backend in moq-wasm and the ffi backend implement the traits
directly. Their adapters already clamp priorities themselves.
- Report the public API impact per crate: deleted generic `Session<S>`
adapters, and new impls on concrete session types.

Notes from related quests:
- [qmux on moq-quic](/quest/m2/quic-qmux.md) planned to port qmux's
`web-transport-trait` impl. If it lands first, its impl targets moq-net's
`transport::poll` instead.
- [poll_acked](/quest/m2/quic-ack-hook.md) already puts its hook on moq-net's
trait because moq-net has no `web-transport-trait` dependency. That holds
here.
- [Rust request credit](/quest/m1/rs-request-credit.md) prefers adding a
credit query to qmux and iroh upstream in moq-dev/web-transport. Once this
lands, that query belongs on each backend's own moq-net impl.

## Related

- [qmux on the QUIC stream state machine](/quest/m2/quic-qmux.md) - the in-tree qmux implements the moq-net traits directly
- [poll_acked on moq-net's send stream](/quest/m2/quic-ack-hook.md) - another hook that lives only on moq-net's traits
- [Rust requests fail fast without stream credit](/quest/m1/rs-request-credit.md) - its credit query moves to each backend's moq-net impl
5 changes: 0 additions & 5 deletions quest/m2/quic-deadline.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ raises loss or latency under any profile stays off by default.

Decided in the 2026-09-30 audit: moved to m2. No m1 quest consumes it.

## Required

- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - the
scheduler decides which stream's data a probe carries

## Related

- [QUIC receive-timestamps spike](/quest/m3/quic-gcc.md) - measures whether
Expand Down
8 changes: 2 additions & 6 deletions quest/m2/quic-qmux.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Decided in the 2026-09-30 plan:
- **Scope is the Rust core plus adapters.** Port the prototype core and
moq-dev/web-transport's TCP, TLS, WebSocket, and UDS adapters, ALPN
negotiation, byte-stream framing, and socket stats (about 2.3k lines) onto
it, along with the `web-transport-trait` impl. The TypeScript `@moq/qmux`
it. Its session implements moq-net's `transport::poll` traits instead of
`web-transport-trait` ([Drop web-transport-trait](/quest/m2/drop-web-transport-trait.md)). The TypeScript `@moq/qmux`
and `@moq/web-socket-stream` stay in moq-dev/web-transport with their own
state machine and become the interop reference.
- **All four wire versions stay**: draft-02, draft-01, draft-00, and the
Expand Down Expand Up @@ -76,11 +77,6 @@ the uring runtime never unifies two copies of the stream state.
Decided in the 2026-09-30 audit: moved to m2, since no m1 quest consumes it;
the fork plan the same day kept it there.

## Required

- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - qmux must
expose the same scheduling contract as native QUIC

## Related

- [noq#812](https://github.com/n0-computer/noq/issues/812) - the qmux proposal to n0
Expand Down
1 change: 0 additions & 1 deletion quest/m3/cut-through/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,5 @@ stats field, which its quest documents inline.

## Related

- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - orders streams; offset writes order ranges within one
- [QoS](/quest/m2/qos/README.md) - the loss-delay counter follows its per-broadcast ingress row conventions
- [Frame slots are cached for free](https://github.com/moq-dev/moq/pull/5239) - changes how the cache charges the in-flight frames a cut-through build would hold
2 changes: 0 additions & 2 deletions quest/m3/ladder/controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,3 @@ priority where the subscriber's order wins, and a custom ladder order.
## Related

- [Encoder feedback](/quest/m3/stats-encoder-feedback.md) - viewer stalls for `moq import`; its `moq transcode --echo` leg, split out if revived, feeds this controller
- [Hierarchical stream scheduling](/quest/m1/quic/scheduler.md) - supplies the
fair subscription buckets beneath this rendition policy
10 changes: 9 additions & 1 deletion rs/moq-ffi/src/transport/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ impl<S: backend::Session<SendStream: 'static, RecvStream: 'static> + Clone + 'st
.map_err(Error)
.map(|res| res.map(|(send, recv)| (SendStream(send), RecvStream(recv))))
}
fn send_group(&mut self, _: i64) -> Option<poll::Ungrouped> {
None
}
fn poll_send_datagram(&mut self, cx: &mut Context<'_>, payload: &[u8]) -> Poll<Result<(), Self::Error>> {
backend::Session::poll_send_datagram(&mut self.0, cx, payload).map_err(Error)
}
Expand Down Expand Up @@ -106,15 +109,20 @@ impl<S: backend::Session<SendStream: 'static, RecvStream: 'static> + Clone + 'st
pub struct SendStream<S>(S);
impl<S: backend::SendStream + 'static> poll::SendStream for SendStream<S> {
type Error = Error<S::Error>;
type Group = poll::Ungrouped;
fn poll_write(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, Self::Error>> {
backend::SendStream::poll_write(&mut self.0, cx, buf).map_err(Error)
}
fn poll_write_buf<B: Buf>(&mut self, cx: &mut Context<'_>, buf: &mut B) -> Poll<Result<usize, Self::Error>> {
backend::SendStream::poll_write_buf(&mut self.0, cx, buf).map_err(Error)
}
fn set_priority(&mut self, order: i32) {
fn set_priority(&mut self, order: i64) {
let order = order.clamp(i32::MIN.into(), i32::MAX.into()) as i32;
backend::SendStream::set_priority(&mut self.0, order)
}
fn set_group(&mut self, group: &Self::Group) {
match *group {}
}
fn finish(&mut self) -> Result<(), Self::Error> {
backend::SendStream::finish(&mut self.0).map_err(Error)
}
Expand Down
6 changes: 6 additions & 0 deletions rs/moq-net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ name = "priority"
harness = false
required-features = ["async"]

# Compiles moq-quic's send scheduler from source to compare it with the priority queue.
[[bench]]
name = "schedule"
harness = false
required-features = ["async"]

[[bench]]
name = "stats"
harness = false
Expand Down
Loading
Loading