Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8376466
quest: claim quest/m1/quic/coverage/characterize.md
kixelated Oct 16, 2026
6b899bd
test(quic): characterize frame error paths and resets
kixelated Oct 16, 2026
2d7fe71
test(quic): characterize runtime limits and endpoint routing
kixelated Oct 16, 2026
529170f
test(quic): golden scheduling order and packet/path characterization
kixelated Oct 16, 2026
77f7513
style(quic): format characterization tests
kixelated Oct 16, 2026
4cd6b1c
quest: finish quest/m1/quic/coverage/characterize.md
kixelated Oct 16, 2026
08c75ce
test(quic): drop the global port counter and latency from path tests
kixelated Oct 16, 2026
fd1d2f9
quest: track the four bugs the characterization tests pin
kixelated Oct 16, 2026
14fcc1d
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
b85987f
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
8a9f040
test(quic): a retried handshake must connect, not just stop handshaking
kixelated Oct 17, 2026
73ee3fe
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
0e162a0
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
6e83641
test(quic): stream priority is i64 on main
kixelated Oct 17, 2026
03e8803
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
653eb1b
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
1e0f2cc
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
abc400f
Merge remote-tracking branch 'origin/main' into fix-5781-conflict
kixelated Oct 17, 2026
7de8b6f
test(quic): pin datagram order after group scheduling
kixelated Oct 17, 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: 2 additions & 0 deletions quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ have fixes on `main`: macOS tests (#5335), drill-sensitivity (#5338), loom

- [qmux release backport](/quest/m0/qmux-credit-backport.md) - adopt the 0.5 fix independently of the next breaking cut

- [A discarded Retry no longer blocks the genuine one](/quest/m0/retry-after-invalid-retry.md) - one injected or corrupted Retry no longer kills a handshake, on `main` and then `release`

- [CI cost and latency](/quest/m0/ci/README.md) - PRs stop queueing behind hosted runner caps: macOS and Windows move to the merge queue, caches move to R2, and setup is skipped when no work is selected
- [Draft-22 media on 0.17](/quest/m0/release-22/README.md) - a 0.17.x with the LOCATION_FILTER and FIRST_OBJECT fixes and moq-noq 1.3.5, then a patch with draft-20+ FETCH and the unset-clock and quiet-edge fixes
- [nixpkgs ships the lld fix](/quest/m0/nixpkgs-lld-fix.md) - waiting on NixOS/nixpkgs#568680 to reach `nixpkgs-unstable`, which the release build fix bumps to
Expand Down
33 changes: 33 additions & 0 deletions quest/m0/retry-after-invalid-retry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# [S] A discarded Retry no longer blocks the genuine one

## Goal

A client that discards an invalid Retry (a bad integrity tag, or a source CID
equal to its original destination CID) still follows the server's genuine
Retry and connects. Today the discarded Retry bumps `total_authed_packets`,
so the client then discards the genuine Retry too and never connects: one
injected or corrupted Retry kills a handshake against any server that
validates addresses.

`retry_after_invalid_retry` in
`rs/moq-quic/src/tests/characterize/paths.rs` must pass with its `#[ignore]`
removed, while `invalid_retry_is_discarded` and `second_retry_is_discarded`
keep passing.

## Plan

Decided 2026-10-16 (maintainer): m0, because the shipped release has the same
Retry guard in moq-noq-proto 1.3.5.

The Retry arm of `process_decrypted_packet` in
`rs/moq-quic/src/connection/mod.rs` uses `total_authed_packets > 1` to mean
"already processed a server Initial or Retry", but every Retry reaches
`on_packet_authenticated` before its validity checks run. Make the guard
mean what RFC 9000 17.2.5.2 says: count only a Retry the client accepts, or
track that state explicitly. The VersionNegotiate arm shares the counter;
check whether a discarded Retry also makes it ignore a genuine Version
Negotiation.

Land the fix on `main` first. The `release` backport follows CONTRIBUTING.md
as separate PRs: a moq-dev/noq 1.3.x patch to moq-noq-proto, then a moq-noq
bump onto `release`. The PR that lands the main fix adds that backport quest.
3 changes: 3 additions & 0 deletions quest/m1/quic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ cache limits remain separate; bitrate pacing composes with this memory cap.
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
and MAX_DATA are raised after SETUP identifies a cluster peer
- [A FIN below received data is a final size error](/quest/m1/quic/final-size-below-received.md) - a shrunken final size closes with FINAL_SIZE_ERROR instead of blocking the reader forever
- [A stateless reset keeps a closed connection's reason](/quest/m1/quic/close-reason-after-reset.md) - a reset after a local transport error neither replaces the reason nor reports a second loss
- [0-RTT streams adopt a raised stream window](/quest/m1/quic/zero-rtt-window-raise.md) - a server's larger stream window reaches the client's 0-RTT streams, so they no longer stall

## Related

Expand Down
21 changes: 21 additions & 0 deletions quest/m1/quic/close-reason-after-reset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# [S] A stateless reset keeps a closed connection's reason

## Goal

After a connection closes on its own transport error, a later stateless reset
drains it without changing what the application sees: the original close
reason is reported once. Today, while the connection is `Closed`, the reset
replaces the unread reason with `Reset`, or, once the reason was read,
yields a second `ConnectionLost`.

`stateless_reset_after_local_close_keeps_reason` and
`stateless_reset_after_local_close_is_not_a_second_loss` in
`rs/moq-quic/src/tests/characterize/frames.rs` must pass with their
`#[ignore]` removed.

## Plan

`Connection::finish_packet` in `rs/moq-quic/src/connection/mod.rs` preserves
the close reason on a reset only in `Draining` or `Drained`. Extend that to
`Closed`: move to `Drained` without touching `self.error`, so `poll`, which
takes the error once, reports nothing new.
1 change: 0 additions & 1 deletion quest/m1/quic/coverage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ and the harness defaults to Cubic while production runs BBR3.

## Required

- [Characterization tests](/quest/m1/quic/coverage/characterize.md) - golden scheduling order, and every uncovered frame, reset, limit, and endpoint path, on today's harness
- [Plaintext fuzz crypto](/quest/m1/quic/coverage/fuzz-crypto.md) - a fuzz-only plaintext session so the connection target skips TLS and its injected packets decrypt
- [Richer simulation workloads](/quest/m1/quic/coverage/sim-workloads.md) - resets, bidi streams, datagrams, and migration in the random workloads, each with its own invariant
- [Pin benchmark cores](/quest/m1/quic/coverage/bench-pin.md) - local base/head comparisons run on one core type on hybrid CPUs
Expand Down
44 changes: 0 additions & 44 deletions quest/m1/quic/coverage/characterize.md

This file was deleted.

20 changes: 20 additions & 0 deletions quest/m1/quic/final-size-below-received.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# [S] A FIN below received data is a final size error

## Goal

A STREAM frame whose FIN sets a final size below data already received closes
the connection with FINAL_SIZE_ERROR, as RFC 9000 4.5 requires. Today the
frame is accepted: the reader gets the bytes past the final size, then
`Blocked` forever, since the shrunken final size never matches what was
read.

`stream_final_size_below_received` in
`rs/moq-quic/src/tests/characterize/frames.rs` must pass with its `#[ignore]`
removed.

## Plan

`Recv::ingest` in `rs/moq-quic/src/connection/streams/recv.rs` checks a FIN
only against an already-known final size. When a FIN arrives first, also
reject an `end` below `self.end`, before recording the size. RESET_STREAM
already makes this check (`reset_final_size_below_received`).
25 changes: 25 additions & 0 deletions quest/m1/quic/zero-rtt-window-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# [S] 0-RTT streams adopt a raised stream window

## Goal

When a server raised its stream receive window between sessions, a client's
0-RTT streams adopt the new window once the server's transport parameters
arrive, and run to completion. Today they keep the remembered smaller window,
and the server, believing the client already has the larger one, never sends
MAX_STREAM_DATA, so bidi and uni streams stall forever.

`zero_rtt_bidi_window_raise` and `zero_rtt_uni_window_raise` in
`rs/moq-quic/src/tests/characterize/limits.rs` must pass with their
`#[ignore]` removed.

## Plan

Decided 2026-10-16 (maintainer): `StreamsState::set_params` in
`rs/moq-quic/src/connection/streams/state.rs` raises the send window of the
client's own 0-RTT streams to `initial_max_stream_data_bidi_remote` (bidi) or
`initial_max_stream_data_uni` (uni), and wakes any writer the new credit
unblocks. RFC 9000 7.4.1 forbids a server that accepts 0-RTT from lowering
these, so the window only grows.

The same PR deletes the existing loop over peer-initiated bidi streams in
`set_params`, which is unreachable through the public API.
21 changes: 21 additions & 0 deletions rs/moq-quic/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3918,6 +3918,27 @@ impl Connection {
Some(packet.payload.to_vec())
}

/// Encrypts `payload` as this connection's next packet in `space`, untracked, so tests can
/// send frames a correct peer never would
#[cfg(test)]
pub(crate) fn forge_packet(&mut self, now: Instant, space: SpaceId, payload: &[u8]) -> Vec<u8> {
let mut buf = Vec::new();
let builder = PacketBuilder::new(
now,
space,
self.rem_cids.active(),
&mut buf,
usize::MAX,
0,
true,
self,
)
.expect("connection can still send");
buf.extend_from_slice(payload);
builder.finish(self, now, &mut buf);
buf
}

/// The number of bytes of packets containing retransmittable frames that have not been
/// acknowledged or declared lost.
#[cfg(test)]
Expand Down
Loading
Loading