From afcf2320afc18a7acbc6e6e6daf217fe4b400aff Mon Sep 17 00:00:00 2001 From: scgopi Date: Sun, 6 Sep 2026 10:17:55 -0700 Subject: [PATCH] Add write-path probes for the non-blocking writer (#291) Partial writes resuming without truncation or duplication against a 2 KB receive buffer, a close landing mid-frame ending the stream rather than corrupting it, and a peer that vanishes while the writer is parked being noticed without anyone closing the channel. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01BTGxgXNsZkDeiZE273zbqL --- .../Tests/OutboundChannelReviewTests.swift | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/graphcode/Tests/OutboundChannelReviewTests.swift b/graphcode/Tests/OutboundChannelReviewTests.swift index 1c7d4b08..b446528f 100644 --- a/graphcode/Tests/OutboundChannelReviewTests.swift +++ b/graphcode/Tests/OutboundChannelReviewTests.swift @@ -136,4 +136,83 @@ struct OutboundChannelReviewTests { let elapsed = Date().timeIntervalSince(started) #expect(elapsed < 20, "150 rounds of open/send/close took \(elapsed)s") } + + /// The writer now hands the kernel whatever it will take per call and resumes from + /// where it stopped. Every partial write must resume at the right byte and nothing may + /// be sent twice: a peer that drains in small gulps, with a receive buffer far smaller + /// than any frame, must reassemble every frame intact and in order. + @Test + func partialWritesResumeWithoutTruncatingOrDuplicating() throws { + let (daemon, client) = makeSocketPair() + var tiny: Int32 = 2048 + setsockopt(client, SOL_SOCKET, SO_RCVBUF, &tiny, socklen_t(MemoryLayout.size)) + setsockopt(daemon, SOL_SOCKET, SO_SNDBUF, &tiny, socklen_t(MemoryLayout.size)) + OutboundChannels.open(daemon) + defer { + OutboundChannels.close(daemon) + close(client) + } + + let sizes = [1, 3, 2047, 2048, 2049, 4095, 8191, 8192, 100_000, 7, 65_537, 300_000, 2] + let sent = sizes.enumerated().map { index, size in + Data((0..