Bound the drain's send, and stage what times out - #320
Merged
Merged
Conversation
#316 bounded the presence read, but drainPendingFollowUps still awaited deliverToSession unbounded in the same walk — the stable-release check's DeliveryWedgeTests reproduce the freeze reached through the send instead: one loop's hung zmx send held the queue for the lease's whole 300s, every other loop's staged mail unmoving and silent. The send now has the same withDeadline the presence read has (45s, the loser abandoned rather than cancelled-and-waited). What the deadline drops is staged to the target's memory log and taken off the queue, so the target still reads it at its next wake — and a delivery that fails without hanging is recorded the same way, which the old code silently dropped. A delivery-stall line in the daemon log keeps frozen and working looking different. The lease stays: it is the backstop for the awaits that are not the drain's walk (stop requests, nudges), not a licence to park the queue for minutes first.
#316 bounded the presence read, but drainPendingFollowUps still awaited deliverToSession unbounded in the same walk — the stable-release check's DeliveryWedgeTests reproduce the freeze reached through the send instead: one loop's hung zmx send held the queue for the lease's whole 300s, every other loop's staged mail unmoving and silent. The send now has the same withDeadline the presence read has (45s, the loser abandoned rather than cancelled-and-waited). What the deadline drops is staged to the target's memory log and taken off the queue, so the target still reads it at its next wake — and a delivery that fails without hanging is recorded the same way, which the old code silently dropped. A delivery-stall line in the daemon log keeps frozen and working looking different. The lease stays: it is the backstop for the awaits that are not the drain's walk (stop requests, nudges), not a licence to park the queue for minutes first.
# Conflicts: # GraphcodeKit/Sources/GraphStore.swift
scgopi
added a commit
that referenced
this pull request
Sep 7, 2026
Retry a timed-out follow-up whose send then fails; fix the gate after #320 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014niBD1D1yQ7F2gjV2K54eB
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.
Closes the send-path half of the stable gate's NO-GO on 0.1.64: the delivery chain in
drainPendingFollowUpsnow has the same deadline the presence read got in #316, and whatever the deadline drops is staged to memory rather than stranded or silently lost.Defect (fails without the change)
drainPendingFollowUpsawaitsdeliverToSessionunbounded in its walk —ZmxSessionLauncher.send→PTYProcessSession.waitCollectingOutput, three sequentialzmx sendbeats per message — so one loop's hung send held the queue for the drain lease's entire 300s while every other loop's staged mail sat unmoving, with nothing logged. The stable-release check'sDeliveryWedgeTestsreproduce it against 0.1.64-beta6: control delivers in the window, one hung send freezes the bystander.Red (82b86a6's tests, drain hunk reverted, private DerivedData): exit 65 —
aHungDeliveryNoLongerFreezesTheBystandersFollowUps(bystander never delivered) andaTimedOutFollowUpIsStagedToMemoryNotSilentlyDropped(memory never written) both fail; the control passthrough and the three read-side inverted tests (read bounded at 45s, timed-out item still owed, poll reaches loops behind a hung one) pass.Green: same tests exit 0 after 41315a9.
Fix
deliverToSessionawait now runs underwithDeadline(deliveryDeadline)— the samewithDeadlineBound the presence read, and let the drain alone decide delivery (#311, #304) #316 introduced, loser abandoned rather than cancelled-and-waited (cancel ignores a task parked on a pipe that will never close).staged(_:)writes the canonical "follow-up staged:" memory entry exactly once and the item leaves the queue — the Mailroom mirror already carries the content, so the target reads it at its next wake instead of retrying a send that may only ever hang.delivery-stalllogged via#289diagnostics when a deadline passes — frozen no longer looks identical to working.presenceReadDeadline— a bystander behind one wedged target waits one span, not 300s and not the process's life.Gate on 41315a9 (private DerivedData)
xcodebuild testexit 0 — 1692 tests / 180 suites / 0 failures (beta6 baseline 1686; +6 from the newDrainWedgeVerificationTestsfile carrying the read-side inverted tests and the delivery suite)graphcode-clibuild exit 0;graphcodedbuild exit 0scripts/cli-smoke.shexit 0 (five verbs; run against a freshswift buildin an isolated scratch — the shared.build's debug CLI was stale, which was a shuttle from before, not a gate failure)