Skip to content

Fix PTY deadline output drain#2139

Merged
steipete merged 4 commits into
steipete:mainfrom
kiranmagic7:kiran/tty-deadline-drain-20260714
Jul 14, 2026
Merged

Fix PTY deadline output drain#2139
steipete merged 4 commits into
steipete:mainfrom
kiranmagic7:kiran/tty-deadline-drain-20260714

Conversation

@kiranmagic7

@kiranmagic7 kiranmagic7 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • drain non-Codex PTY output for a bounded no-input settle window before returning a deadline result
  • keep waiting for a still-running child after PTY closure, so descriptor closure does not shorten the configured deadline
  • add regressions for retained OAuth prompt output and PTY closure followed by delayed successful child exit

Fixes #2134

Tests

  • swift test --filter TTYCommandRunnerEnvTests - passed, 28 tests in 1 suite
    • includes deadline drain preserves prompt output when first poll misses it
    • includes PTY closure keeps waiting for child exit before deadline
  • swift test --skip-build --no-parallel --filter '(^CodexBarTests\.ClaudeEducationAvailabilityTests/|^CodexBarTests\.ClaudeExtraWindowQuotaWarningTests/|^CodexBarTests\.ClaudeLoginFlowTests/|^CodexBarTests\.ClaudeLoginRunnerTests/)' - passed, 12 tests in 4 suites
  • make check - passed; existing app-locale missing-translation warnings only
  • git diff --check - clean
  • Earlier broad check caveat from the first head: swift test --filter AdaptiveRefreshTimerTests and make test failed in AdaptiveRefreshTimerTests.swift on menu open advances a long idle timer during refresh without postponing an earlier tick with CancellationError, outside the touched PTY files.

Notes

This only changes the non-Codex PTY completion path. The extra drain window is bounded to 0.2-0.5s and runs without sending input, preserving late-readable output while still respecting a live child process through the configured deadline.

@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: 0810bbe31d

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

if case .closed = readResult, !process.isRunning { break }
if ptyClosed { break }

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 Keep waiting for live children after PTY closure

When a non-Codex child closes or redirects all PTY fds but keeps running, this new break exits the poll loop immediately even though the configured timeout has not elapsed. The later finishSynchronously() only waits its 1s default, so a command like exec </dev/null >/dev/null 2>/dev/null; sleep 5; exit 0 with returnOnEmptyProcessExit now gets killed/reported as timed out instead of waiting for the process to exit and returning its status as before.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. labels Jul 14, 2026
@clawsweeper

clawsweeper Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed July 13, 2026, 9:26 PM ET / July 14, 2026, 01:26 UTC.

Summary
The PR adds a bounded late-output drain to the non-Codex PTY deadline path, treats PTY closure as terminal for polling, and adds a regression test for retaining delayed OAuth prompt output.

Reproducibility: yes. The linked issue supplies a current-main zero-retry grouped-suite command and observed failures for both lost OAuth output and an incorrect immediate-exit result; the review comment also gives a deterministic compatibility case for the proposed patch.

Review metrics: 2 noteworthy metrics.

  • Patch surface: 2 files; 50 added, 15 removed. The change is focused, but most production edits alter central PTY completion semantics.
  • Regression coverage: 1 test added. The test covers late prompt output but leaves the live-child-after-closure compatibility case untested.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #2134
Summary: This PR explicitly targets the intermittent output and exit-status loss tracked by the linked issue, but the candidate fix currently introduces a separate child-lifecycle regression.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦪 silver shellfish
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Preserve the configured wait for children that remain alive after PTY closure and add focused regression coverage.
  • [P1] Add redacted live terminal or runtime-log proof for both retained prompt output and delayed successful child exit.

Proof guidance:

  • [P1] Needs real behavior proof before merge: Only automated tests and CI are reported; before merge, add a redacted terminal capture, copied live output, or runtime log showing the after-fix OAuth prompt and child-exit behavior. Update the PR body afterward to trigger a fresh review; if that does not happen, ask a maintainer to comment @clawsweeper re-review.

Risk before merge

  • [P1] Existing commands that close or redirect their PTY descriptors while continuing useful work can now be killed or reported as timed out before the configured deadline expires.
  • [P1] The added test covers delayed readable output but not the compatibility case where PTY closure precedes a later successful child exit.
  • [P1] No live after-fix evidence confirms that the intended OAuth prompt is retained without altering real child-exit behavior.

Maintainer options:

  1. Preserve live-child waiting (recommended)
    Change the closure branch so it drains remaining output but continues waiting for a still-running child through the configured deadline, with regression coverage for delayed successful exit.
  2. Pause the PTY semantic change
    Keep the PR open until the contributor can prove that early termination after PTY closure is intentional and safe for existing non-Codex command runners.

Next step before merge

  • [P1] The contributor should repair the live-child regression and supply real PTY proof; automation cannot provide evidence from the contributor's runtime setup.

Security
Cleared: The two-file PTY and regression-test diff adds no dependency, secret, permission, download, release, or supply-chain surface.

Review findings

  • [P1] Keep waiting for live children after PTY closure — Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift:831
Review details

Best possible solution:

Drain late readable output without equating PTY closure with child termination: continue waiting for a live child up to the configured deadline, add a regression for closed PTY descriptors followed by a delayed successful exit, and demonstrate both cases with a redacted live terminal transcript.

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

Yes. The linked issue supplies a current-main zero-retry grouped-suite command and observed failures for both lost OAuth output and an incorrect immediate-exit result; the review comment also gives a deterministic compatibility case for the proposed patch.

Is this the best way to solve the issue?

No, not in its current form. A bounded output drain is appropriate, but PTY closure must not be treated as child exit while the process is still running within its configured deadline.

Full review comments:

  • [P1] Keep waiting for live children after PTY closure — Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift:831
    Breaking whenever ptyClosed becomes true shortens the configured timeout for children that redirect or close all PTY descriptors but remain alive. The later one-second finish can kill and report timeout for a child that previously exited successfully within its deadline; drain the closed PTY, but keep waiting while process.isRunning. This is a late finding because the same line was present at the previously reviewed head.
    Confidence: 0.97
    Late finding: first raised on code an earlier review cycle already covered.

Overall correctness: patch is incorrect
Overall confidence: 0.96

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add merge-risk: 🚨 compatibility: Merging the current closure behavior can turn previously successful long-running child commands into premature timeout results.

Label justifications:

  • P2: This is a bounded PTY reliability fix with a concrete regression risk, but it does not currently threaten the overall application runtime.
  • merge-risk: 🚨 compatibility: Merging the current closure behavior can turn previously successful long-running child commands into premature timeout results.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: Only automated tests and CI are reported; before merge, add a redacted terminal capture, copied live output, or runtime log showing the after-fix OAuth prompt and child-exit behavior. Update the PR body afterward to trigger a fresh review; if that does not happen, ask a maintainer to comment @clawsweeper re-review.
Evidence reviewed

What I checked:

  • Current-main behavior: Before this patch, PTY closure ends the polling loop only after the child is no longer running, preserving the configured timeout for children that close or redirect their PTY descriptors. (Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift:826, b41715f3e3fb)
  • Introduced compatibility regression: The PR changes the loop to break whenever ptyClosed is true, even if the child remains alive; the subsequent one-second synchronous finish can therefore kill or time out a child that would previously have exited normally within the configured deadline. (Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift:831, 0810bbe31df3)
  • Actionable review reproduction: The existing review comment provides a concrete case: a child redirects all PTY descriptors, sleeps for five seconds, and exits successfully; the new path stops polling immediately and reports a timeout instead of waiting for that exit. (Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift:831, 0810bbe31df3)
  • Original bug evidence: The linked issue reports repeated current-main failures in the zero-retry grouped suite where an OAuth URL or immediate exit status is intermittently lost, with exact commands and environment details. (Tests/CodexBarTests/TTYCommandRunnerTests.swift:410, c852c135e10c)
  • Proof gap: The PR body lists focused tests, make check, and CI results, but contains no after-fix live PTY transcript, terminal capture, or redacted runtime log showing the real deadline-output behavior. (0810bbe31df3)
  • Re-review continuity: The previous ClawSweeper cycle reviewed the same head SHA without raising the PTY-closure regression; this finding is therefore marked as a late discovery rather than contributor churn. (Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift:831, 0810bbe31df3)

Likely related people:

  • mickobizzle: The v0.29.0 history credits this contributor with PTY child-process-tree termination work, making them a useful reviewer for closure and child-exit semantics. (role: recent PTY lifecycle contributor; confidence: medium; files: Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift)
  • steipete: Repository history and releases show continued integration of PTY lifecycle changes, including the process-tree cleanup release, so this is the strongest routing fallback for the compatibility decision. (role: recent area integrator; confidence: medium; commits: f61469c; files: Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift, CHANGELOG.md)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

How this review workflow works
  • 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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-14T01:08:21.343Z sha 0810bbe :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. label Jul 14, 2026
@kiranmagic7 kiranmagic7 force-pushed the kiran/tty-deadline-drain-20260714 branch from 0810bbe to 911375c Compare July 14, 2026 05:39
@kiranmagic7

Copy link
Copy Markdown
Contributor Author

Updated in 911375cc.

  • Rebased onto current main (b41715f3).
  • PTY closure now keeps waiting while the child process is still running, so descriptor closure no longer shortens the configured deadline.
  • Exit status is only requested after the child has actually exited.
  • Added coverage for both requested behavior cases: retained prompt output and PTY closure followed by delayed successful child exit.

Tight local proof on the repaired head:

swift test --skip-build --filter 'deadline drain preserves prompt output|PTY closure keeps waiting'
✔ Test "deadline drain preserves prompt output when first poll misses it" passed after 1.651 seconds.
✔ Test "PTY closure keeps waiting for child exit before deadline" passed after 2.551 seconds.
✔ Test run with 2 tests in 1 suite passed after 4.203 seconds.

Broader local proof on the repaired head:

swift test --filter TTYCommandRunnerEnvTests
# passed, 28 tests in 1 suite

swift test --skip-build --no-parallel --filter '(^CodexBarTests\.ClaudeEducationAvailabilityTests/|^CodexBarTests\.ClaudeExtraWindowQuotaWarningTests/|^CodexBarTests\.ClaudeLoginFlowTests/|^CodexBarTests\.ClaudeLoginRunnerTests/)'
# passed, 12 tests in 4 suites

make check
# passed; existing app-locale missing-translation warnings only

git diff --check
# clean

Hosted CI has restarted on 911375cc and is still in progress.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@steipete steipete merged commit 8941bed into steipete:main Jul 14, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ClaudeLoginRunnerTests intermittently lose fixture output in zero-retry suite

2 participants