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
5 changes: 2 additions & 3 deletions doc/concept/transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ connection (`wss://`) and keep whichever wins. A small multiplexer,
[qmux](/draft/qmux-websocket), carries MoQ streams over the socket. It works
everywhere but cannot escape TCP head-of-line blocking, so priority and resets
only help once bytes leave the TCP queue. The fallback is automatic in every
client; the relay enables it with `[web.https]`. A native Rust client that
lands on WebSocket keeps dialing QUIC and moves the session over once QUIC
succeeds.
client; the relay enables it with `[web.https]`. A session that lands on
WebSocket stays there until it ends; the next connect races again.
Comment on lines +45 to +46

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Update every remaining WebSocket-upgrade reference

After this paragraph establishes that sessions no longer upgrade, a repo-wide search still finds test/portrait/relay.toml:8-9 and test/ts/README.md:596-603 justifying version selection and CI coverage in terms of WebSocket-to-QUIC upgrades; the README even points readers to transport-upgrade tests that this commit deletes. Update those references, along with the stale statements in quest/m1/slow-source.md:8-9 and quest/m3/quic-careful-resume.md:13-15, so the harness rationale and documented coverage describe the behavior that now ships.

AGENTS.md reference: AGENTS.md:L28-L29

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.

Agreed, fixed in 22fa4f2. test/portrait/relay.toml and test/ts/README.md now justify lite-07 by a replacement session instead of the upgrade, and the README no longer points to the deleted transport-upgrade tests. quest/m1/slow-source.md, quest/m3/quic-careful-resume.md and quest/m2/quic-sim.md no longer describe the upgrade as current behavior. The two remaining mentions (restart-followers.md, uring-tcp/README.md) record the removal itself.

(Written by Claude Opus 5.5)


## Raw QUIC (native)

Expand Down
3 changes: 1 addition & 2 deletions quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Interop on main (2026-10-13): the cross-client matrix failed with `unroutable`
whenever WebSocket won the connect race: since #5294, #4180's upgrade
retired epochless handles before its held `Restart` reached anyone. Handles
now retire only once it is deliverable. First-party consumers following it
moved to m1 (maintainer, 2026-10-13), since the upgrade is being removed.
moved to m1 (maintainer, 2026-10-13), since the upgrade is removed.

Crashes (2026-10-13, #5407): a publisher on a host whose wall clock reads
before 2020 panics, and `panic = "abort"` turned any library panic into a
Expand All @@ -84,5 +84,4 @@ have fixes on `main`: macOS tests (#5335), drill-sensitivity (#5338), loom
- [web-transport releases the qmux fixes](/quest/m0/qmux-credit-upstream.md) - waiting on moq-dev/web-transport#412 and #413 to merge and ship, which qmux credit bumps to
- [qmux credit](/quest/m0/qmux-credit.md) - qmux returns connection credit for dropped and stopped streams and delivers its close frame, on both lines
- [Broadcast epochs](/quest/m0/broadcast-epoch/README.md) - every first-party publisher that can restart mints a fresh route epoch, the newest wins a path, and only routes with the same epoch resume a subscription
- [Keep the winning transport](/quest/m0/drop-ws-upgrade.md) - a connection stays on the transport that won the race; the WebSocket-to-QUIC upgrade and its epochless `Restart` are removed
- [Parked drain](/quest/m0/parked-drain.md) - draining parked groups after a cap rise, as a same-epoch relay handover causes, is near-linear in the backlog, not quadratic
60 changes: 0 additions & 60 deletions quest/m0/drop-ws-upgrade.md

This file was deleted.

9 changes: 4 additions & 5 deletions quest/m1/restart-followers.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ then costs a long-lived consumer nothing but the restart.
## Plan

Moved to m1 on 2026-10-13 (maintainer): the WebSocket-to-QUIC upgrade is
being removed (separate m0 quest), so an epochless Restart no longer follows
removed, so an epochless Restart no longer follows
every connect; it remains for GOAWAY drains and publisher replacement.

The origin side is done: a handle resolved through a peer keeps serving new
requests while the peer's epochless replacement is held, and refuses them
with `Unroutable` only once the `Restart` is deliverable (`Release` in `rs/moq-net/src/model/origin.rs`,
`rs/moq-net/tests/upgrade.rs`). So a consumer that never follows `Restart`
`rs/moq-net/tests/replacement.rs`). So a consumer that never follows `Restart`
works through the hold (300 ms by default), and its open subscriptions stay
sticky on the old session until it closes, where they end cleanly. A
consumer that opens a request after the hold, or reads past the old
Expand Down Expand Up @@ -45,9 +45,9 @@ Audit and fix:
- The interop clients under `test/interop/clients`, where they resolve a
broadcast themselves.

Regression: extend `rs/moq-net/tests/upgrade.rs` (or the consumer's own
Regression: extend `rs/moq-net/tests/replacement.rs` (or the consumer's own
tests) so each follower reads past the old session's close after an
epochless upgrade. Then run `just test interop --all`.
epochless replacement. Then run `just test interop --all`.

If a failing client still leaves its connection to idle out, fix that
client's error path to close its session, as a separate commit. The C
Expand All @@ -59,5 +59,4 @@ Wire: none.

## Related

- [Keep the winning transport](/quest/m0/drop-ws-upgrade.md) - removes the upgrade, so `Restart` no longer follows every WebSocket connect
- [Broadcast epochs](/quest/m0/broadcast-epoch/README.md) - the players that already follow `Restart`
2 changes: 1 addition & 1 deletion quest/m1/slow-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ An export whose source arrives further off real time than the output's
clock may follow ends with an error naming the measured rate, once it has
used half its delay. It no longer drops nearly every frame for hours with
only per-frame "missed its deadline" warnings. A short stall, such as a
WebSocket-to-QUIC upgrade, still drops late frames and recovers.
reconnect, still drops late frames and recovers.

## Plan

Expand Down
2 changes: 1 addition & 1 deletion quest/m2/quic-sim.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The `moq-time` sim drives two `moq-quic` endpoints over in-memory datagrams
with configurable latency, loss, reordering, and bandwidth, so QUIC behavior
(BBR, reliable reset, stream deadlines, the transport upgrade) and MoQ over
(BBR, reliable reset, stream deadlines, the transport race) and MoQ over
real QUIC are tested deterministically with no sockets.

## Plan
Expand Down
2 changes: 0 additions & 2 deletions quest/m3/quic-careful-resume.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ to slow start without hurting the path.
## Plan

Decided in the 2026-10-10 audit: scope this to remembered QUIC connections.
Transferring TCP estimates into a WebSocket-to-QUIC upgrade is out of scope;
that upgrade starts without a seed.

Follow the shape of draft-ietf-ccwg-careful-resume: the sender keeps a
per-destination record of the last validated bandwidth estimate and minimum
Expand Down
5 changes: 2 additions & 3 deletions quest/m3/uring-tcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ number is what justifies the rest of the line.

Decided in the 2026-09-30 audit: moved to m2, since no fleet demand asks
for ring TCP. (Decided 2026-10-13: the WebSocket-to-QUIC upgrade that would
have shrunk the WebSocket hot path is being removed by
[Keep the winning transport](/quest/m0/drop-ws-upgrade.md), so a WebSocket
session will stay on TCP for its lifetime.)
have shrunk the WebSocket hot path is removed, so a WebSocket session stays
on TCP for its lifetime.)

Decided 2026-10-08: moved to m3. No fleet demand asks for ring TCP; the
ablation stays the gate for the rest of the line.
Expand Down
18 changes: 5 additions & 13 deletions rs/moq-net/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ impl Client {
crate::session::Handles {
goaway: start.goaway,
auth: start.auth,
setup: start.setup,
estimate: Some(start.estimate),
},
))
Expand Down Expand Up @@ -292,7 +291,7 @@ impl Client {
// The peer's SETUP decides whether AUTH is negotiated. A handle that does not
// offer it keeps the option out of our SETUP and presents no credential.
let auth = crate::auth::Handle::new(self.extensions.auth);
let (protocol, goaway, setup) = ietf::start(ietf::Config {
let (protocol, goaway) = ietf::start(ietf::Config {
runtime: runtime.clone(),
limits: self.limits,
session: session.clone(),
Expand Down Expand Up @@ -323,7 +322,6 @@ impl Client {
crate::session::Handles {
goaway,
auth,
setup,
estimate: None,
},
));
Expand Down Expand Up @@ -418,7 +416,7 @@ impl Client {
.copied()
.ok_or(Error::Version)?;

let (recv_bw, protocol, goaway, auth, setup, estimate) = match version {
let (recv_bw, protocol, goaway, auth, estimate) = match version {
Version::Lite(v) => {
let stream = stream.with_version(v);
let start = lite::start(lite::Config {
Expand All @@ -444,7 +442,6 @@ impl Client {
crate::driver::Protocol::Lite(Box::new(start.driver)),
start.goaway,
start.auth,
start.setup,
Some(start.estimate),
)
}
Expand All @@ -466,7 +463,7 @@ impl Client {
// Draft 14-16 carry no AUTH, but the session is still limited through this handle.
let auth = crate::auth::Handle::new(false);
// Draft 14-16: the path rode in the bidi SETUP above, not the uni one.
let (protocol, goaway, setup) = ietf::start(ietf::Config {
let (protocol, goaway) = ietf::start(ietf::Config {
runtime: runtime.clone(),
limits: self.limits,
session: session.clone(),
Expand All @@ -486,7 +483,7 @@ impl Client {
early_unis: Vec::new(),
extensions: self.extensions,
})?;
(None, crate::driver::Protocol::Ietf(protocol), goaway, auth, setup, None)
(None, crate::driver::Protocol::Ietf(protocol), goaway, auth, None)
}
};

Expand All @@ -496,12 +493,7 @@ impl Client {
version,
recv_bw,
protocol,
crate::session::Handles {
goaway,
auth,
setup,
estimate,
},
crate::session::Handles { goaway, auth, estimate },
))
}
}
Expand Down
10 changes: 0 additions & 10 deletions rs/moq-net/src/ietf/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,6 @@ impl PeerSetup {
}
}

/// Poll until the peer's SETUP arrives.
pub fn poll_seen(&self, waiter: &kio::Waiter) -> std::task::Poll<()> {
self.0
.poll(waiter, |peer| match peer.is_some() {
true => std::task::Poll::Ready(()),
false => std::task::Poll::Pending,
})
.map(|_| ())
}

/// Await the peer's SETUP.
///
/// The peer MUST send exactly one, so this resolves once that stream is read. Waits
Expand Down
Loading
Loading