Skip to content

fix: drain PTY output after process exit - #2807

Merged
steipete merged 3 commits into
mainfrom
steipete/pty-empty-output-race-7e7159
Aug 9, 2026
Merged

fix: drain PTY output after process exit#2807
steipete merged 3 commits into
mainfrom
steipete/pty-empty-output-race-7e7159

Conversation

@steipete

@steipete steipete commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Summary

Root exit and reaping can precede PTY delivery. The shared runner now terminates and reaps residual same-group or output-holder helpers before draining, so they cannot keep the PTY slave open. The PTY master then drains through EOF/EIO before output is classified as empty, while genuinely empty exits remain supported.

The shared Kiro and Claude login/provider version paths are covered. Regressions include a 50-iteration fast-process-exit test and a same-group-helper cleanup test.

Testing

  • DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer swift build --build-tests (passed)
  • make check (passed with zero violations)
  • tty runner cleans a same group helper after normal exit (passed)
  • fast process exit drains buffered PTY output (passed for 50 iterations)
  • post-exit drain processes trailing chunk through callback path (passed)
  • Autoreview clean; no accepted/actionable findings

@clawsweeper

clawsweeper Bot commented Aug 9, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@steipete
steipete force-pushed the steipete/pty-empty-output-race-7e7159 branch from 136dbe8 to 780367b Compare August 9, 2026 08:19

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 136dbe83ff

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +979 to +981
guard try drainNonCodexOutput(for: Self.postExitDrainTimeout) else {
Self.log.warning("PTY did not close after process exit", metadata: ["binary": binaryName])
throw Error.timedOut

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve exited output when descendants keep the PTY open

When a CLI exits successfully after printing output but leaves a background helper/daemon inheriting the PTY fds, this new guard waits for EOF/EIO and then throws timedOut even though buffer already contains the command's result. The generic non-Codex path is used for provider probes such as Kiro and Claude/version checks, so wrappers that briefly leave a child holding stdout/stderr open now report timeouts and discard usable output; the closure requirement should only block empty-result classification or otherwise allow non-empty process-exit output after the drain timeout.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Aug 9, 2026
@clawsweeper

clawsweeper Bot commented Aug 9, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed August 9, 2026, 5:34 AM ET / 09:34 UTC.

ClawSweeper review

What this changes

The PR terminates and reaps residual PTY helper processes after a command exits, then drains remaining output through terminal closure before deciding whether the result is empty.

Regression provenance

Possible regression — probable (reviewed change; failure trace). No predecessor PR is attributed.

Merge readiness

⚠️ Ready for maintainer review - 2 items remain

Keep this owner-authored PR open for normal merge review. The latest branch addresses the prior concern by cleaning residual PTY helpers before terminal draining, while current main still has the post-exit drain path without that cleanup.

Priority: P2
Reviewed head: 9dec482a555d05c52b1c4916a7c2ba378b07b44a

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) The stated repair is focused, addresses the previous review concern, and includes targeted regression coverage.
Proof confidence 🌊 off-meta tidepool Not applicable: This maintainer-authored PR is exempt from the external-contributor real-behavior-proof gate; its focused automated regressions remain useful supplemental evidence.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: This maintainer-authored PR is exempt from the external-contributor real-behavior-proof gate; its focused automated regressions remain useful supplemental evidence.
Evidence reviewed 5 items Current drain behavior: Current main already drains briefly after a non-Codex command exits, but it does not clean a residual PTY process group before that drain.
Residual-process cleanup support: The existing process-group helper detects residual groups and synchronously terminates remaining descendants and group members, which matches the PR's stated cleanup boundary.
Provider consumers: Kiro's PTY path accepts a successful process-exit result, while Claude version detection requires successful PTY output; both are affected by incorrect post-exit output handling.
Findings None None.
Security None None.

How this fits together

CodexBar runs provider and login commands inside a pseudo-terminal and feeds their captured output into status and version probes. The shared runner sits between process lifecycle events and Kiro, Claude, and Codex provider outcomes.

flowchart LR
  A[Provider probe] --> B[PTY command runner]
  B --> C[Direct command exits]
  C --> D[Residual helper cleanup]
  D --> E[Terminal output drain]
  E --> F[Captured command result]
  F --> G[Provider status or login flow]
Loading

Before merge

  • Resolve merge risk (P2) - Because this shared runner feeds provider version and login probes, an incorrect residual-helper boundary could still turn valid provider output into a timeout or terminate an unintended process-group member.
  • Complete next step (P2) - This owner-authored PR remains open for ordinary merge review; no discrete automated repair is indicated.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Change scope 3 files affected; 86 additions, 40 deletions The patch is concentrated in the shared PTY runner, its focused regression coverage, and one release-owned changelog entry.

Merge-risk options

Maintainer options:

  1. Keep cleanup scoped to the owned PTY group (recommended)
    Merge after confirming the same-group-helper regression and provider-probe paths retain output from successful short-lived commands.

Technical review

Best possible solution:

Land the narrow residual-helper cleanup with the existing fast-exit and same-group-helper regressions, preserving successful buffered output for provider probes.

Do we have a high-confidence way to reproduce the issue?

Yes, source-reproducible: the supplied branch adds a 50-iteration fast-exit PTY regression and a same-group-helper cleanup case, although this read-only review did not execute the unavailable PR head.

Is this the best way to solve the issue?

Yes. Reaping only residual helpers that retain the owned PTY before draining is a narrower solution than discarding buffered output or weakening empty-result handling.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f5a1f799186e.

Labels

Label justifications:

  • P2: The shared PTY path can affect provider probe reliability, but the repair is bounded and does not indicate a broad outage.
  • merge-risk: 🚨 auth-provider: Kiro and Claude provider paths consume this runner's post-exit output, so a lifecycle regression could cause false probe failures.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🌊 off-meta tidepool and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: This maintainer-authored PR is exempt from the external-contributor real-behavior-proof gate; its focused automated regressions remain useful supplemental evidence.

Evidence

What I checked:

Likely related people:

  • steipete: Authored the current PR and the most recent adjacent main change to the shared PTY lifecycle path. (role: recent area contributor; confidence: high; commits: 9dec482a555d, b2e2938dbf0d; files: Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift, Sources/CodexBarCore/Host/Process/SpawnedProcessGroup.swift)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (3 earlier review cycles)
  • reviewed 2026-08-09T08:23:07.992Z sha 780367b :: needs changes before merge. :: [P2] Preserve output when a descendant keeps the PTY open
  • reviewed 2026-08-09T09:03:58.938Z sha f7ea00c :: needs changes before merge. :: [P2] Preserve output when a descendant keeps the PTY open
  • reviewed 2026-08-09T09:14:41.313Z sha f7ea00c :: needs changes before merge. :: [P2] Return buffered output when descendants hold the PTY open

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Aug 9, 2026
@steipete
steipete merged commit 171c2dc into main Aug 9, 2026
9 checks passed
@steipete
steipete deleted the steipete/pty-empty-output-race-7e7159 branch August 9, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. P2 Normal priority bug or improvement with limited blast radius. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant