Conversation
Ctrl-C used to exit without a word. The peer found out from a dropped connection, and the relay counted it as a failure. Now the first Ctrl-C (or SIGTERM) cancels: whatever the transfer waits on next sends the peer `cancel` and stops, and the other side says who stopped it. A second Ctrl-C, or two seconds without stopping, quits at once as before. The mechanism is a wrapper around the transport, since every wait in both directions already goes through one. Sends are refused before they start, never interrupted, so no frame is left half-written. Two bugs found on the way, both covered by tests: - A receiver left a partial file behind on any early exit other than an integrity failure, including a dropped connection. A guard now deletes it unless every byte arrived and was verified. - A sender that was mid-write when the receiver cancelled reported "Broken pipe": the relay forwards `cancel` and closes, and the write fails first. A failed write now reads what already arrived and reports the peer's reason. Exit statuses: 3 declined or not answered, 4 cancelled by the other side, 130 cancelled here. With --status each side prints `drop-status: state=` lines, which netlab now asserts in the relayed topology. Consent plan phase 4; decisions entry 20. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G7Fy45hUvna94cd79WKG8S
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
The Windows CI run showed the sender still reporting "connection aborted" when the receiver cancelled, after the relay learned to drain. The sender only read when its window was full, so it never answered the relay's close. The drain expired, the relay reset the connection, and Windows discarded the unread `cancel` along with everything else. Reading after the failed write, which works on Linux, cannot get it back there. The sender now reads whatever has already arrived before each chunk, without waiting, which is safe because a receive must be cancel-safe. Acknowledgements move the window as before, and a `cancel` ends the transfer with the receiver's reason while it is still readable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G7Fy45hUvna94cd79WKG8S
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Consent plan, phase 4, recorded as decision 20. It changes behaviour, so it waits for your review. Stacked on #72.
What changes for a person
0done,1failed,3declined or didn't answer,4the other side cancelled,130cancelled here. Declines and cancels print as sentences, noterror:.--status, each side printsdrop-status: state=connected | code-ok | accepted | finishing | done | declined | cancelled.How
cancel::Cancellable<T>wraps the transport. Once a cancel fires, the next receive (including one already waiting) or send tells the peercancel {reason:"user"}once, bounded by 1s, and fails withTransportError::Cancelled. Every wait already goes through a transport, so no transfer function needed a new parameter. Sends are refused before they start, never interrupted mid-frame.Bugs found on the way (both now tested)
PartialFilenow deletes on drop unless every byte was verified and flushed. Negative control: with the guard disabled, both mid-transfer cancel tests fail on the leftover file.Broken pipewhen the receiver cancelled. The relay forwardscanceland then closes the socket, so the sender's next write fails before it reads the reason. A failed write now reads what already arrived (≤500 ms) and reports the peer's reason.Tests (248, up from 240)
drop recvexits 130 with "Cancelled.";drop sendexits 4 and prints statesconnected, code-ok, accepted, cancelled.Not tested: a cancel over the direct path (it uses the same wrapper), and the "N files were kept" message for a cancelled extraction.
🤖 Generated with Claude Code
https://claude.ai/code/session_01G7Fy45hUvna94cd79WKG8S