Repository navigation
Record Stop immediately and settle subagents from exit proof - #28051
brennanb2025 wants to merge 269 commits into
Conversation
2d46899 to
6ba01b3
Compare
d070825 to
ef1ad55
Compare
Main's rewind recovery now cuts the chat history from the journal; the read step outside the session's serialize takes the journal to find that cut, and the apply step refuses evidence read for a different cut. The saved-pick display keeps main's refused-model exception.
…ests A model the Claude CLI retired is reported again, so the picker shows what the child runs and the next send moves the chat off it. The start reads a rewind in doubt against the handle it answered with, the record its commit then applies to. Main's tests follow the start's open: the admission fixture holds a real turn, and a sign-in close during setup fails the open.
…ity, held-send revert Sleep (#28445) closes a workspace's chats through the same abort a close gives a registered start, re-aborts a start registered while it waited for the lane, and judges its receipt once the start it aborted has settled, so only a newer start reads as later work. Each adapter's owned-acquisition check covers the child it owns between acquire and open. Main's Sleep cases from the deleted surface lifetime suite move to the workspace Sleep suite, plus one for a starting agent. Codex (#30406): the split open sends the chat's command env overrides when it opens the thread; the adapter test keeps that assertion on the open's request. Revert of #30134 (#30572): the event sink, exit observation, Pi held-send wrapper and adapter heldSends overrides go with it; Pi dispatch submits through its turns again and its idle report is wired back.
A start runs outside the chat's lane, so Sleep's step can run before the start it aborted has settled; it then re-reads the chat once that start is done, instead of reporting it unverified.
Brings the agent-start branch's final tip into the Stop change: starts register before any await, Stop/close/quit abort a registered start, and serialize steps are pure fenced commits. The Stop's note writes keep the start-abort wiring and write at the fence a Stop-caused child end moved.
Main now carries #28046's startup design (squash-merged), so its hunks match the previous merge; this adds main's newer changes. Conflicts took the Stop branch's side, since main's text in each conflicted file equals the startup branch tip already reconciled. Tests whose premise the Stop change moved: a Codex Stop now ends the app server, so the replayed-Stop race resumes the saved thread on a new child; a Stop before startup now records its request beside the taken-back send's stopped result. The background-task test regains the tracker import its proof cases use.
The two #29905 cases lived in the turns test this branch removed. They pin that a listed Stop never ends a helper lifetime it did not capture: a same-id restart during acceptance, or a refused helper that appears mid Stop-all, which must not close the agent.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments: 1
src/main/codex/codex-app-server-teardown.integration.test.ts: 1
147-155: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winRequire the detached grandchild to be reaped on supported POSIX runs.
The suite excludes Windows, and the fixture keeps the provider root alive while
close()captures the process tree. The currentelsebranch accepts an unproven result without checking the grandchild. A reaper regression can therefore pass while the grandchild remains alive. Require the exited-tree result and the grandchild's absence.♻️ Suggested tightening
const rootExited = await connection.close() expect(rootExited).toBe(true) - if (connection.closeResult?.tree === 'exited') { - await vi.waitFor(() => expect(processExists(pids.grandchild)).toBe(false)) - expect(connection.closeResult).toMatchObject({ root: 'exited', tree: 'exited' }) - } else { - expect(connection.closeResult?.tree).not.toBe('exited') - expect(connection.processTreeUnproven).toBe(true) - } + expect(connection.closeResult).toMatchObject({ root: 'exited', tree: 'exited' }) + await vi.waitFor(() => expect(processExists(pids.grandchild)).toBe(false)) + expect(connection.processTreeUnproven).toBe(false)
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
b63f489d-9884-4676-85d2-cd7769633edf
📒 Files selected for processing: 77
config/scripts/vitest-sqlite-runtime-files.mjssrc/main/acp/acp-structured-host-lifecycle.test.tssrc/main/acp/acp-structured-host-start-aborts.test.tssrc/main/acp/acp-structured-session-adapter.tssrc/main/agent-hooks/server/server-status-application.tssrc/main/agent-hooks/server/server-status-update.tssrc/main/claude/claude-close-turn-end.test.tssrc/main/claude/claude-scripted-child.test-fixture.tssrc/main/claude/claude-structured-prompt-ownership.tssrc/main/claude/claude-structured-session-adapter.tssrc/main/codex/codex-app-server-connection-tree-unproven.test.tssrc/main/codex/codex-app-server-connection-types.tssrc/main/codex/codex-app-server-connection.test.tssrc/main/codex/codex-app-server-connection.tssrc/main/codex/codex-app-server-teardown.integration.test.tssrc/main/codex/codex-background-task-tracker.tssrc/main/codex/codex-child-work-evidence.test.tssrc/main/codex/codex-child-work-evidence.tssrc/main/codex/codex-request-end-wait.tssrc/main/codex/codex-structured-session-adapter.tssrc/main/codex/codex-structured-session-background-tasks.test.tssrc/main/codex/codex-structured-session-close.test.tssrc/main/codex/codex-structured-session-close.tssrc/main/codex/codex-structured-session-teardown.tssrc/main/codex/codex-structured-turn-cancellation.tssrc/main/daemon/pty-subprocess-spawn-file-foreground.test.tssrc/main/daemon/terminal-host-process-inspection.test.tssrc/main/github/github-remote-identity-parsing.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter-stop.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter.tssrc/main/native-chat/agent-session-wire/structured-agent-session-chat-stop.tssrc/main/native-chat/agent-session-wire/structured-agent-session-child-close.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-hung-start-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-codex-stop-note-end.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-codex-stop-row.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversation-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-create.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-listed-stop-lifetime.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-prompt-cancel.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-card-holds.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig-provider.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-pause-lift.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-stop-row.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-repeated-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt-host.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-steer-while-stopping.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-event-binding.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-event-entries.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-event-restart.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-event.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-note-opened-turn.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-note-withdrawn-send.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-receipts.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-settle-binding.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-wind-down.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stopped-history.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stopping.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-turn-stop-notes.tssrc/main/native-chat/agent-session-wire/structured-agent-session-turns-cancel.tssrc/main/native-chat/agent-session-wire/structured-agent-session-turns.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-unnamed-stop-races.test.tssrc/main/native-chat/agent-session-wire/structured-conversation-compaction.test.tssrc/main/pi/rpc-session-adapter.tssrc/main/providers/local-pty-child-process-verdict.test.tssrc/main/providers/local-pty-provider-foreground-process.test.tssrc/main/runtime/structured-agent-session-codex-compact-exit.test.tssrc/main/runtime/structured-agent-session-codex-interrupt-order.test.tssrc/main/runtime/structured-agent-session-codex-scripted-child.test.tssrc/main/runtime/structured-agent-session-codex-stopped-send-order.test.tssrc/main/runtime/structured-agent-session-codex-turn-end-settlement.test.tssrc/main/runtime/structured-agent-session-integration.test.tssrc/main/runtime/structured-foreground-command-strip.test.tssrc/renderer/src/components/terminal-pane/remote-pane-layout-push.tstests/e2e/cross-version-wire/cross-version-stop-note-test-rig.ts
💤 Files with no reviewable changes: 22
- src/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.test.ts
- src/main/codex/codex-structured-session-close.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-host.test.ts
- src/main/codex/codex-app-server-connection.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-stop-event-entries.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-stop-event-restart.test.ts
- src/main/pi/rpc-session-adapter.ts
- src/main/native-chat/agent-session-wire/structured-conversation-compaction.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-stop-settle-binding.test.ts
- src/main/claude/claude-structured-session-adapter.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-steer-while-stopping.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-turns.test.ts
- src/main/codex/codex-child-work-evidence.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-stop-event-binding.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-queued-stop-row.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-queued-card-holds.test.ts
- src/main/runtime/structured-foreground-command-strip.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-stopping.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-create.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-conversation-stop.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-codex-stop-row.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-codex-stop-note-end.test.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.
|
Pressing Stop could leave Codex and its commands running, omit feedback before the first reply, or mark child work stopped before its exit was known. This change records the accepted request immediately, ends the chat runtime, and resumes the same conversation on the next send. Started turns read Interrupted. A send withdrawn before startup keeps Stopped manually beside Cancellation requested. A child is marked stopped only with proof that both its runtime and workload exited. Review rounds remain at 2. Current head Verified on the unchanged production code:
First common observed exit samples after Stop acceptance were within 351ms for Codex, 1,304ms for Pi, 1,000ms for Claude and 2,720ms for the phone's Codex run. These are bounds from actual samples of recorded identities, not exact latency or proof about unobserved descendants. Pi's retained status was observed after 166 seconds; its provider-close-after-exit warning remains disclosed. The phone transcript retains the provider's earlier claim that its command was running; physical process observations establish that the original command exited. Repeated-Stop qualification uses real phone QA plus an automated host contract. In ticket1491 a genuine installed-phone Stop interrupted a live Codex workload; the original recorded runtime/workload identities exited, and one next desktop Send produced the real reply The new test sends two distinct Stop operation IDs while the same turn is working/stopping through the shipping host and actual Codex adapter with a fixture transport. It requires exactly one OpenCode ACP Stop/resume remains unqualified and prevents readiness. Ticket1392 produced a real first reply but no cancellation. Ticket1465's workload failed with a quota error before a command ran, with a saved-model/native-model mismatch recorded separately. Ticket1491 selected the currently answering The 197-file ticket 1294 archive, 277-file ticket 1392 archive, 49-file ticket 1465 archive and all 80 payload files in ticket 1491 were independently hash-verified and audited. The accepted exact-head automated runs passed 78 named tests with five platform skips, then all 26 tests in the two existing child reconciliation/producer files. Internal edge cases are covered by tests/traces only: empty acquisition ( The inherited Claude unknown-default effort reset remains separately owned under STA-11451, outside this Stop change and not intended. Explicit Opus/High exercised Claude here without encountering that reset. Intended differences from the common pattern remain runtime-ending Stop, the shared five-second Codex graceful allowance, execution-host identity/exit proof, and retained request/result feedback. Deleted transport-test coverage and the redundant historical-helper test remain deferred maintenance concerns. Disappearance of command records after partial cleanup is not proof of exit. QA setup limits are preserved: the initial driver used a prohibited clipboard route for a nonsecret draft and was stopped; that draft receives no qualification credit. A fresh normal qa-drive invocation performed the qualifying phone actions through local Orca. Both driver invocations ended without completing the whole plan. Current recorded QA identities exited, allocated ports were empty and the owned simulator shut down before ticket release. Older unrecorded inherited helpers were left untouched; this is not an exhaustive all-profile-processes cleanup claim. The earlier ticket 1465 failure also exposed two known issues outside this Stop change: both clients displayed saved MiniMax while native execution recorded Flint, and the error displayed raw provider text and a subscription URL. The lane owner is handling the model display/recovery follow-up after #31208 and the separate failure-message issue. Neither is intended behavior or attributed to this PR; no contrary causal evidence was found. The earlier ticket 1465 narrow retry used normal qa-drive with a passing Codex preflight and both actual clients on the unchanged final host. It made exactly one workload Send, no second Send or deliberate model substitution, and no Stop action. There were zero new host cancellation receipts or request items. Original OpenCode process exits during rig cleanup do not qualify cancellation. All recorded original identities exited, ports 9460–9479 were clear and the owned simulator was Shutdown before ticket 1465 was released. The two old inherited helpers remained untouched. Existing accepted flows were not replayed. The new archive confirms the isolated environment paths but excludes full launch arguments and private before/after real-config hash records; independent isolation certification is limited to what was included. For Brennan's review These are the actual main-to-final Codex/Pi screenshots. Visible status/replies and the separate process proofs establish different parts of the result.
Additional final-head screenshots follow. Matching main cancellation screenshots are unavailable for these continuation flows; no new main comparison is claimed.
The following images document the two gaps, not passing qualification:
The earlier ticket 1465 retry failed before either Stop action. These are the actual desktop and installed native client showing the same provider failure; they are not cancellation proof.
Ticket 1491 evidence transfer is complete: archive size 5,002,740 bytes, SHA-256
|



















ELI5
Pressing Stop in a Codex chat could interrupt the reply while leaving its background server and commands running. A Stop accepted before the first reply could also be missing from the transcript, and child tasks could read stopped before Orca knew their work had exited.
Stop now ends the agent runtime for every chat agent. The conversation records the accepted request once, and the next message resumes the same conversation. A started turn stopped by the user reads Interrupted; a send withdrawn before startup retains its existing Stopped manually result beside the request. Child tasks read stopped only when the execution host has proved that both their root process and its workload exited.
What Changed
Codex first receives an interrupt. It gets up to five seconds from the Stop request to settle, then Orca closes its background server and cleans up its owned descendants using process IDs and start times. A later proven exit can settle an earlier unconfirmed close. Chat Stop and workspace Sleep both count a proven runtime root exit as stopped. Child-task outcomes have the stronger requirement: both root and workload must be proved exited. Unavailable descendant evidence leaves those outcomes unconfirmed without blocking runtime-level Sleep or a new send.
The transcript writes Cancellation requested. when Stop is accepted, including when an accepted send is still starting or has not echoed its turn yet. It stays beside that message's stopped result and is deduplicated across repeated Stop requests. Stopping a startup with no queued message adds no request row. Question and approval cards keep their current Cancel behavior. Failure to save the request row is logged and cannot prevent the Stop.
Why
An accepted Stop is user intent; an exited process is an observed fact. Keeping those separate gives immediate feedback without claiming unfinished background work has stopped. Reusing the host's existing child-work records preserves completed child outcomes and avoids a second status store.
Differences from the common pattern
Linked Issue
Continues the Stop work tracked in #26561. The startup changes from #28046 and the Claude resumed-message repair from #30982 are already on main and included here.
Visual Proof
Real main-versus-branch Electron QA on M4Air compared main
fece03b5ac4749a50f24f7ad5a148e1f0154a4c8with head70c552fe35f0abe6658f88b800d3cb201ba3bfa4, carrying the same isolated saved conversations through a restart and upgrade. Codex and Claude each produced two real replies after upgrade, then stopped through the UI with physical root and workload exit proof, then produced two further replies in the same native thread. Their latest turn stayed Interrupted beyond sixty seconds. Expanded turn details showed exactly one accepted request for each observed Stop. Final child cancellation also proved root and both workloads exited before the child read stopped; its completed sibling remained completed.Screenshots and the detailed coverage limits are in the existing review status comment. The native Windows process contract passed on this head with the same saved conversation and identical 180-second workload: actual Stop ended the four observed original processes, recorded one request, and allowed a real same-thread reply. Main’s root and workload remained alive about 8.6 seconds after Stop. Independent Windows handles proved the final physical exits; normal-flow hook delivery remains unproven and an internal process-tree proof warning is retained. This short qualification does not cover every descendant or waive the full QA gaps. Overall QA remains BLOCKED. Pi native admission is blocked by the version-probe defect tracked in #30393; the installed CLI writes its version to standard error while admission reads only standard output. OpenCode ACP failed during native startup in this isolated rig; another lane ran the same version successfully, so its working provider recipe will be reused. No ACP Stop ran here. Starting Sleep was not exercised: no Send occurred before its bounded observer expired. Paired web connected to the correct isolated host, but its native chat was unavailable even through Agent Session History; native phone coverage is separate and unexercised. Repeated accepted Stop remains targeted live QA. Empty acquisition, unavailable card/scoped routes, child outcome retention and hook POST transport are verified by named automated tests listed in the review comment. The hook tests invoke generated scripts with controlled input; normal native-send hook delivery was not observed and is not claimed. Actual CLI native launch and a real reply passed; disabled search and unsupported native terminal routes remain gaps.
Testing
Head
70c552fe35f0passed 100 targeted tests across ten files. The tests cover accepted choices with missing readback, delayed interrupt, late response, opening-turn retry, legacy queued withdrawal, startup with and without an accepted send, runtime exit receipts and Sleep. Seventeen bounded source-module scenarios also passed; those traces do not replace real-agent QA. All seven exact-head workflows passed, including the full PR Checks workflow, its required aggregate and Windows load tests.The earlier Windows setup block remains historical. The lane owner authorized a fresh QA budget, which produced the M4Air results above. The separate short native Windows process qualification passed within the stated bounds; the lane owner accepts that observed flow as passing, with the process-tree proof warning retained as a known limit. Hook transport is verified by controlled tests, with live native-send delivery unobserved. Both fresh QA rigs are cleaned and their tickets released. Overall readiness remains blocked by required agents and consumer coverage.
Review
Full review, cumulative round 2: independent runtime and host/surface reviewers verified the fixes and found no new proven behavioral defect. The architecture ruling retained host termination and separate runtime/child proof, with no new persisted state. The full graceful sequence uses one original deadline, and an empty startup produces no cancellation request row. Separate readiness and performance source scans found no new proven defect. The complete final mechanism comparison passed on this head. An inherited refusal when clearing effort to an unknown configured default is owned separately under STA-11443/STA-11451; this PR does not label it intended.
Current head includes pinned main
fece03b5ac47; GitHub reports merge conflicts andbrennan-ready --force --pr 28051reports NOT READY for conflicts and the absent completion marker. Per the lane dependency ruling, the next main refresh waits for #30393 to merge, then requires new-head CI and targeted real Pi startup/Stop/resume, native phone Codex Stop, repeated Stop, starting Sleep/wake, Codex sanity and OpenCode ACP Stop/resume with the proven recipe. No completion marker or ready-to-merge claim is valid yet.Agent skill upstream boundary
Notes
Process actions and exit evidence stay on the execution host. Folder workspaces and independently updated peers retain their existing routes. No new saved field or wire operation is introduced.
Checklist