diff --git a/quest/m1/README.md b/quest/m1/README.md index 9501773df5..246d1b26c8 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -27,6 +27,7 @@ transport, benchmark tooling); worktrees isolate commits, not semantics. - [Close codes](/quest/m1/close-codes.md) - a client sees the peer's application close code over WebSocket and raw QUIC, like WebTransport - [Raw stream codes](/quest/m1/raw-stream-codes.md) - raw QUIC stream resets and stops carry the application's code, not an HTTP/3-mapped one - [WebTransport close upstream](/quest/m1/wt-close-upstream.md) - web-transport-moq delivers the close capsule itself, and moq-tokio's `CLOSE_LINGER` is deleted +- [Browser close code](/quest/m1/browser-close-code.md) - a playwright case proves the page reads a relay's close code and reason, on every web-transport backend - [Watch refusal](/quest/m1/watch-refusal.md) - `` shows an origin refusal as an error instead of sitting offline - [Resumed groups](/quest/m1/resume-latest.md) - a half-delivered group ends once the new copy is past it, so a group-only reader never parks after a mid-group failover - [SUBSCRIBE_DROP](/quest/m1/subscribe-drop.md) - every stream group in a lite subscription arrives or is dropped by name, and lite-07 drops its stream count for it diff --git a/quest/m1/browser-close-code.md b/quest/m1/browser-close-code.md new file mode 100644 index 0000000000..95df47c767 --- /dev/null +++ b/quest/m1/browser-close-code.md @@ -0,0 +1,35 @@ +# [M] A browser sees the close code on every WebTransport backend + +## Goal + +A browser interop case proves a relay's rejection reaches the page: the relay +closes the session with an application code and reason, and the page reads +both from `WebTransport.closed`. Every `moq-dev/web-transport` backend that +speaks WebTransport (noq, quinn, iroh) delivers the close capsule, verified by +that case or an equivalent test, and any that doesn't is fixed upstream. + +## Plan + +[WebTransport close upstream](/quest/m1/wt-close-upstream.md) fixed +`web-transport-moq`'s close path with a Rust regression test, but only +Chromium treats the H3 control stream ending early as fatal, so no Rust peer +proves the browser path. The playwright interop harness in `test/interop/` +has no close-code scenario yet. + +- Add the browser case: a relay (or `Request::reject`) closes with a code, and + the page asserts the code and reason. It should fail with the capsule fix + reverted. +- Audit `web-transport-noq`, `-quinn`, and `-iroh` for the same bug: a close + capsule sent from a task that doesn't keep the H3 control streams alive. + `web-transport-iroh` 0.7 sends no capsule at all, only a QUIC close; decide + there whether iroh's WebTransport path should send one. +- Fix upstream, release, and bump the pins, once wt-close finishes. + +Decided with the maintainer: the browser case and the backend audit ship +together, since the case is what proves each backend. + +Public API: none. Wire: none, unless iroh starts sending the capsule. + +## Required + +- [WebTransport close upstream](/quest/m1/wt-close-upstream.md) - the noq fix and pin bump the browser case needs diff --git a/quest/m1/wt-close-upstream.md b/quest/m1/wt-close-upstream.md index a277c17cb0..84f801729d 100644 --- a/quest/m1/wt-close-upstream.md +++ b/quest/m1/wt-close-upstream.md @@ -1,4 +1,4 @@ -# [S] WebTransport close delivers its capsule upstream +# [XS] WebTransport close delivers its capsule upstream ## Goal @@ -20,22 +20,32 @@ detached task until `closed()` resolves, capped at a 10s `CLOSE_LINGER`. Decided 2026-09-29: fix it at the source and remove the timeout workaround. -- In moq-dev/noq, the close path keeps whatever the capsule needs alive until - it is delivered, without the caller's help. Its regression test drops the - session right after `close()` and asserts the peer reads the capsule - before the H3 control stream ends; it must fail on 1.3.2. A Rust peer - alone proves nothing: `session_close_surfaces_a_rejection_code` in - `rs/moq-tokio/tests/broadcast.rs` passed on 1.3.2 without the linger, - because only Chromium treats the control stream's end as fatal. Add a - browser check too if the playwright harness makes it cheap. -- Release `web-transport-moq` 1.3.x and bump the pin on `main` (2.x on `dev` - if it has moved). +The upstream fix makes the close task own a clone of the whole session: +[moq-dev/noq#23](https://github.com/moq-dev/noq/pull/23) for 2.x (`dev`) and +its backport [moq-dev/noq#24](https://github.com/moq-dev/noq/pull/24) for +1.3.x (`main`). Their `web-transport-moq/tests/close_capsule.rs` drops the +session right after `close()` against a hand-rolled HTTP/3 peer and fails on +1.3.2 and 2.0.0. + +Remaining, once the releases carrying them are published: + +- Bump the `web-transport-moq` pin on `main` (and on `dev` if 2.0.x lands + first). - Delete `CLOSE_LINGER`, its task, and its mock-session tests from - moq-tokio. + moq-tokio. They are exactly what #4429 added, so reverting it is enough. + +A browser check is left to +[Browser close code](/quest/m1/browser-close-code.md): the playwright harness +has no close-code scenario, so it is not cheap to add here. Public API: none. Wire: none. +## Required + +- A `web-transport-moq` 1.3.x release that carries moq-dev/noq#24 + ## Related +- [Browser close code](/quest/m1/browser-close-code.md) - the playwright case that proves Chromium reads the code this quest unblocks - [Close codes on every transport](/quest/m1/close-codes.md) - the same symptom over qmux and raw QUIC - [UnknownSession log flood](/quest/m1/unknown-session-logs.md) - another `web-transport-moq` release and pin bump