Repository navigation
Fix PTY attach output ordering - #476
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f83e4da. Configure here.
Sayan-
left a comment
There was a problem hiding this comment.
-
p2: attaching before the first output can leave the terminal blank.
changedis initialized by the first write, but an earlier attachment can already be waiting on nil. A real WebSocket probe receives neither later output nor exit; attaching after initial output works. -
p2: the two-second PTY drain deadline can wait without a bound. A shell exiting with a background child holding the terminal open leaves the reader polling a closed descriptor and the waiter blocked. Reproduced on this PR; the same process test completes before this change. Cleanup and scale-to-zero reenable cannot run while blocked.
-
p2: a retiring attachment can corrupt the next attachment's output position. The forwarder is outside the handler's wait group. A controlled WebSocket reconnect probe pauses the old callback after enqueueing, reconnects, then resumes it: the stale worker advances the new cursor and the next byte disappears. The control without that overlap passes.
|
@Sayan- thanks for the detailed review. Pushed 1. Attaching before the first output leaves the terminal blank. 2. The drain deadline can block without bound. After 3. A retiring attachment can corrupt the next attachment's cursor. The forwarder ran outside any wait group, so a stale forwarder could finish an in-flight sink call after the next attach and advance the new cursor. Cursor-level fix for #3 is in Cursor Bugbot's finding on the earlier commit (writes forwarding into the sink while holding the lock) doesn't match the current code: Verification: Remaining limit: if the PTY produces more output than the reader can drain in the 2s deadline, the excess is dropped at close. I left that as is. |
Sayan-
left a comment
There was a problem hiding this comment.
rechecked early PTY attachment, bounded drain completion, and reconnect isolation; the regression and WebSocket tests pass with the race detector.
Drain PTY output for the process lifetime into a replay buffer so a client that attaches after output was written still receives it. - Attach replays buffered output, then forwards live output; the exit event is sent only after the attached sink has flushed. - Detach waits for the forwarder to leave any in-flight sink call so a stale forwarder cannot move the next attachment's cursor. - The waiter stops the PTY reader through its stop channel after a bounded drain before closing the master. The reader polls the raw fd and spins on a closed one.
06c8292 to
a079358
Compare

Summary
Overlap with #463
Checked open PR #463 first. It changes process lifecycle and
process.go, but its description explicitly excludes TTY sessions from output capture; it does not cover PTY attach replay or ordering. This PR changes the same file, so a merge conflict with #463 is possible. The PTY changes are otherwise separate from #463's non-TTY output lifecycle work.Validation
cd server && go test -race ./cmd/api/api -run 'TestPTYOutput' -count=10cd server && go test ./cmd/api/api -count=1cd server && go vet ./cmd/api/api