Bound PTY hard-stop cleanup latency - #2811
Conversation
|
🦞👀 Pull request received. I will update this pull request when review starts. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5778321424
ℹ️ 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".
| // A forced stop still owns a live root, so its descendants and dedicated process group | ||
| // are enough to terminate it without the load-sensitive system-wide output-holder scan. | ||
| Self.log.debug("PTY hard stopping", metadata: ["binary": binaryName]) | ||
| launchedProcess.abortSynchronously() |
There was a problem hiding this comment.
Keep sweeping detached PTY holders
When a provider CLI daemonizes a helper that keeps the PTY slave open while the root TUI is still alive (for example, a double-fork/setsid helper), this new live-root branch only signals the tracked descendants/process group via abortSynchronously() and skips the terminateSynchronously() output-holder sweep. That detached holder is no longer a descendant or group member, so cleanup can return after killing the root and leave the helper process running; the previous path found it by scanning PTY descriptor holders. Please retain a holder sweep for this case, or run it after the bounded root abort.
Useful? React with 👍 / 👎.
|
Codex review: needs maintainer review before merge. Reviewed August 13, 2026, 3:12 AM ET / 07:12 UTC. ClawSweeper reviewWhat this changesThe PR makes PTY hard-stop cleanup return promptly while a deferred, lease-bounded worker terminates detached processes that still retain the terminal. Regression provenancePossible regression — probable (reviewed change; known regression link). No predecessor PR is attributed. Merge readinessThe final head addresses the prior escaped-holder concern with a bounded caller path and deterministic coverage; no discrete correctness finding remains. The remaining choice is whether a utility-queue holder scan that can outlive its disarmed 15-second lease is acceptable operationally. Priority: P2 Review scores
Verification
How this fits togetherCodexBar runs provider CLIs through a pseudo-terminal and consumes their output for status probes. When a probe stops early, its cleanup must release the caller quickly while preventing detached helpers from keeping the PTY alive. flowchart LR
A[Provider CLI] --> B[PTY command runner]
B --> C[Early-stop cleanup]
C --> D[Abort root process group]
D --> E[Deferred holder scan]
E --> F[Lease expiry guard]
E --> G[Detached holders terminated]
B --> H[Probe result returned]
Decision needed
Why: Source confirms the lease bounds caller latency and late cleanup effects, but cannot cancel a scan already inside process enumeration; the operational resource tradeoff needs maintainer intent. Before merge
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Keep the deferred post-abort holder cleanup and accept it only with explicit ownership of the disarmed-but-not-cancellable scan tradeoff; future hard bounding would require a cancellable discovery mechanism. Do we have a high-confidence way to reproduce the issue? Yes, from source: current main synchronously performs output-holder discovery during ordinary early-stop cleanup, and the final head supplies deterministic fixtures for the escaped-holder cases. The fixtures were not executed in this read-only review. Is this the best way to solve the issue? Yes, conditionally: aborting the owned root before deferred holder discovery preserves prompt return and catches TERM-created detached holders; only the uncancellable-scan operational tradeoff remains for maintainer acceptance. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 208016687098. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (8 earlier review cycles)
|
5778321 to
33034b4
Compare
|
@clawsweeper re-review The branch is reconstructed on current main at |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review Final head is |
|
🦞👀 Re-review progress:
|
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review Final reconstructed head is |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Summary
Bound PTY idle/deadline hard-stop latency without abandoning detached processes that still retain the PTY.
The original PR routed a live root through the scoped abort path, but that could miss true double-forked/session-escaped holders. This reconstruction keeps the immediate bounded abort while moving holder discovery and cleanup into a small, deadline-bounded lease.
Design
launchPTYreserves one CLOEXEC duplicate of the PTY master beforeposix_spawn. Reservation failure prevents child creation, so cleanup never needs to allocate underEMFILE/ENFILEpressure.SpawnedProcessGroup: only immutable output identities, exclusions, grace values, and the reserved master descriptor.Deliberately unchanged:
/exitwrite for ordinary non-overflow cleanup;Regression proof
The composite deterministic fixture covers four escaped generations:
setsid();A second fixture proves an early-stopped root can exit during settle while a detached holder remains, without returning to synchronous system-wide discovery.
Wall-clock assertions use the repository standard: 3 seconds locally and 9 seconds on loaded CI. Synthetic discovery begins one second beyond that budget in either environment, so an implementation that waits for discovery still fails. A DEBUG-only lease allowance keeps the artificial delay separate from production's fixed 15-second cleanup window.
Validation
KiroStatusProbeTests: 57/57 passed.SpawnedProcessGroupTests: 18/18 passed, including descriptor ownership, reservation failure, and lease expiry.TTYCommandRunnerTests: 29/29 passed.BoundedChildProcessProofTests: 3/3 across repeated runs.CodexBarCorebuild passed with DEBUG test APIs excluded.make checkpassed.