Repository navigation
fix(net): mock resets carry only codes; ietf publisher cancels with CANCELLED - #7099
Conversation
Quest-Claim: babad187d02fab29
…ANCELLED The mock transport handed the peer the local reset/stop reason object, which real WebTransport cannot carry. Build each stream direction from a WritableStream/ReadableStream pair whose abort and cancel hooks deliver only the stream error code (0 for a plain Error). That exposed the ietf publisher resetting group and fill streams with plain Errors (INTERNAL_ERROR on the wire) when the subscriber left or a REQUEST_UPDATE excluded the group. Reset those as CANCELLED, as the draft and the Rust publisher do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6975a78c19
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 6975a78c198a6a790b912f7c3fc65a30ac0c400b
No additional actionable correctness bugs found. The direction is sound: the mock no longer leaks local error messages to its peer, and subscriber-driven group/fill cancellations now pass through the existing stream-code mapping as CANCELLED rather than INTERNAL_ERROR. The explicit stream pair is justified by the need to translate abort/cancel reasons while waking backpressured writes; no public API change is needed.
The test synchronization concern at js/net/src/mock.test.ts:50 is already covered by the independent finding; no duplicate inline comment added.
Verification: static inspection of the diff, mock lifecycle/backpressure paths, publisher cancellation paths, and transport error mapping. I did not run tests or real-peer interop.
(Written by OpenAI)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: e39f2a5b3d203b8b28753a92deb507f171ae4231
Compared with my previous review of 6975a78c198a6a790b912f7c3fc65a30ac0c400b: only the backpressure test changed. The previously referenced synchronization finding is fixed: js/net/src/mock.test.ts:49-51 now waits for write progress instead of a real timer. With the current 256-chunk queue and sequential sink writes, the next write has entered backpressure before cancellation runs. This is a focused, simpler fix; no new actionable bugs found. Production API/wire behavior is unchanged from the prior review.
Verification: static comparison and inspection of the test and mock write/wakeup paths; tests were not run.
(Written by OpenAI)
|
Merge summary for head
Landing through the merge queue. (Written by Claude Opus 5.5) |
Finishes quest/m1/mock-reset-codes.md.
Problem
js/net's mock transport built each stream direction from aTransformStream. A reset (writable.abort(reason)) or STOP_SENDING (readable.cancel(reason)) passed the local reason object straight to the peer. Real WebTransport carries only a code: aWebTransportError'sstreamErrorCode, or 0 for anything else. Tests could therefore assert on messages that never cross a real wire. One such case hid a wrong code on the wire.Approach
WritableStream/ReadableStreampair. The sink'sabortand the source'scancelerror the other end with{ source: "stream", streamErrorCode }, built from the reason's code (0 for a plainError). Unlike a transformercancelhook, this doesn't makeabort()/cancel()reject. Backpressure, the per-chunk copy, and a session close failing every open stream all behave as before.Errors. On a real wire that sends INTERNAL_ERROR (0). They now reset with CANCELLED (1), which is what the draft asks for and what the Rust publisher sends (Error::Cancel).code: StreamCode.Cancelwhere they used to check reason text. The newmock.test.tspins the mock's behavior: a reset or stop reaches the peer as a code with no local message; a coded reason keeps its code; a write parked on a full peer gives up when the peer stops.Verified: the new mock tests fail on the old mock (2 of 4), and the parked-write test hangs when the wake on stop is removed. With the new mock, the 4 publisher tests got
remote error: 0until the publisher fix.Impact
Choices made without asking
Writer.reset(plain Error)callswithCode, which hands the transport the rawError, and both the WebTransport spec and the qmux fallback send 0 for that (see thetoTransportdoc injs/net/src/error.ts). The same reasoning covers the WebSocket path. I did not run a separate interop run.cancelhook makingabort()reject. For example,reload.test.tsawaitswritable.abort(toTransport(...)). None of them asserts a reset reason that the peer couldn't observe, so I left them alone.Checks
just js check-changed(biome, tsc, builds of net and its dependents): passjust js test-changed(net and every dependent package): pass, 0 failuresquest check --base origin/main: passFollow-ups
🤖 Generated with Claude Code
(Written by Claude Opus 5.5)