Poll for recovery after a stream drop instead of failing at the grace (#30)#38
Merged
TheRealDinghyDog merged 1 commit intoJul 10, 2026
Conversation
…#30) A closed event stream raced the whole turn: after a 5s grace, captureTurn made one recovery attempt and could fail immediately even while the held-open /message request was still running and about to succeed (the review reproduced a turn failing at ~5.8s while the response completed at 6.2s). Treat stream closure as loss of one observation channel, not turn completion. After the stream drops, wait the grace for the response and trailing events to land, then actively poll the server for the finished message on an interval until the turn completes another way (response fallback, HTTP recovery, a reconnected session.idle) or the OUTER turn timeout fires. The turn is never failed merely because the stream ended. The grace is now a delay before polling starts rather than a deadline, and a bounded poll interval (default 2s) governs subsequent attempts. The loop is drained in finally so it cannot poll past return, and it still honors the outer timeout so a genuinely stalled turn ends promptly instead of spinning. captureTurn is exported for tests, which drive it against a localhost server across three timings: stream drop + slow-but-successful response (previously failed at the grace), stream drop + lost POST recoverable only via GET, and stream drop + response that never lands (must end near the outer timeout). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Fixes #30 (review finding M-01).
Problem
The overall turn timeout is 30 minutes, but a closed event stream raced the entire turn: after a 5-second grace,
captureTurnperformed exactly one recovery attempt and could fail immediately — even while the held-open/messagerequest was still running successfully. The review reproduced a turn returning failure at ~5.787s witherror: "terminated"while the response completed at 6.2s.Fix
Treat stream closure as loss of one observation channel, not turn completion. Once the stream drops:
session.idle— or the outer turn timeout fires.The turn is never failed just because the stream ended. The poll loop is drained in
finallyso it can't outlive the turn, and it still honors the outer timeout so a genuinely stalled turn ends promptly rather than spinning. The existing post-race single recovery is retained for the non-drop cases (timeout without a drop, empty response).Tests
captureTurnis exported for testing and driven against a localhost server across three timings:state.recovered === true).npm test: 95 passed, 0 failed, 0 skipped.🤖 Generated with Claude Code