Skip to content

Record Stop immediately and settle subagents from exit proof - #28051

Merged
brennanb2025 merged 278 commits into
mainfrom
brennanb2025/agent-start-split-5-stop-workload
Oct 24, 2026
Merged

brennanb2025 merged 278 commits into
mainfrom
brennanb2025/agent-start-split-5-stop-workload

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 54 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1110 $\color{#cf222e}{\Huge{\mathbf{−}}}$​10526 $\color{#cf222e}{\Huge{\mathbf{−}}}$​9416
Prod 34 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​648 $\color{#cf222e}{\Huge{\mathbf{−}}}$​214 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​434

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

  • Not a difference — every chat Stop ends the agent runtime. This follows the common pattern: Stop ends the chat's runtime, background work included, and the next send resumes the same conversation. One detail differs: for Codex, the common pattern can interrupt every turn in the thread while keeping a shared Codex server process alive; Orca runs one Codex process per chat, so ending that chat's runtime ends its process.
  • Intended — Codex's five-second wind-down is counted from the Stop press. Like the common pattern, Stop asks Codex to interrupt the turn and waits up to five seconds for the turn to end on its own before the runtime is closed, so the turn ends with the agent's own result. The difference is when the clock starts: the common pattern gives the interrupt request its own long timeout and starts the five seconds after it answers, so a hung interrupt can hold a Stop open for over a minute. Here one five-second budget covers both, so Stop always finishes within about five seconds.
  • Intended — the execution host proves root and workload exit separately. Orca supports local, SSH and paired clients. A missing reply or lost connection remains unverifiable and cannot finish a child task.
  • Intended — an accepted send stopped before startup keeps request and result feedback. The request has a stable identity before the agent echoes a turn. Starting with no queued send produces no request row.

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 fece03b5ac4749a50f24f7ad5a148e1f0154a4c8 with head 70c552fe35f0abe6658f88b800d3cb201ba3bfa4, 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

  • Complete real QA of every changed agent and consumer on the final head
  • Automated tests added or updated

Head 70c552fe35f0 passed 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 and brennan-ready --force --pr 28051 reports 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

  • Not applicable; no upstream skill-installer source is copied or translated.

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

  • Problem, user-facing change, mechanism and approach explained
  • Full review and readiness checks completed
  • Complete all required main-versus-branch comparisons (available screenshots are consolidated in the review comment)
  • Full workflow green on pinned head 70c552f
  • Dependency main refresh, conflict resolution and new-head checks completed

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.
@brennanb2025
brennanb2025 marked this pull request as ready for review October 19, 2026 18:18
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review.

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5f8f50e2-67b2-40b0-8469-698d295477c6
📥 Commits

Reviewing files that changed from the base of the PR and between 96885e1 and 70c552f.

📒 Files selected for processing: 3
  • src/main/acp/acp-structured-session-adapter.ts
  • src/main/codex/codex-structured-session-adapter.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
🚧 Files skipped from review as they are similar to previous changes: 1
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Walkthrough

Chat Stop now follows a shared child-ending rule and records cancellation-request notes across additional outcomes. Claude and Codex cancellation operations use Stop timestamps to bound interruption work. Codex shutdown now exposes root and workload close observations, which session cleanup uses when ending child-work evidence. The diff also adds and revises tests, removes numerous existing test suites, and updates runtime test inclusion and routing lists.

Priority: Normal

Merge Risk: Minimal · up to 70c55

The change’s Stop and shutdown behavior is supported by the inspected contracts, with no concrete merge-blocking risk identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 59.26% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 54 functions across 62 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly summarizes the primary changes: immediate Stop recording and subagent settlement based on exit proof.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The pull request description is mostly complete. It includes the required ELI5, What Changed, Why, Linked Issue, Visual Proof, Testing, Review, Agent skill upstream boundary, Notes, and Checklist sect…
Full details: Description check

Explanation

The pull request description is mostly complete. It includes the required ELI5, What Changed, Why, Linked Issue, Visual Proof, Testing, Review, Agent skill upstream boundary, Notes, and Checklist sections. It clearly documents the scope, mechanism, validation results, known gaps, merge conflicts, and blocked readiness state. The AI Disclosure section is omitted, but the template allows internal contributors to omit it.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments: 1
src/main/codex/codex-app-server-teardown.integration.test.ts: 1

147-155: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Require 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 current else branch 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
📥 Commits

Reviewing files that changed from the base of the PR and between 846cba6 and 2eef2de.

📒 Files selected for processing: 77
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • src/main/acp/acp-structured-host-lifecycle.test.ts
  • src/main/acp/acp-structured-host-start-aborts.test.ts
  • src/main/acp/acp-structured-session-adapter.ts
  • src/main/agent-hooks/server/server-status-application.ts
  • src/main/agent-hooks/server/server-status-update.ts
  • src/main/claude/claude-close-turn-end.test.ts
  • src/main/claude/claude-scripted-child.test-fixture.ts
  • src/main/claude/claude-structured-prompt-ownership.ts
  • src/main/claude/claude-structured-session-adapter.ts
  • src/main/codex/codex-app-server-connection-tree-unproven.test.ts
  • src/main/codex/codex-app-server-connection-types.ts
  • src/main/codex/codex-app-server-connection.test.ts
  • src/main/codex/codex-app-server-connection.ts
  • src/main/codex/codex-app-server-teardown.integration.test.ts
  • src/main/codex/codex-background-task-tracker.ts
  • src/main/codex/codex-child-work-evidence.test.ts
  • src/main/codex/codex-child-work-evidence.ts
  • src/main/codex/codex-request-end-wait.ts
  • src/main/codex/codex-structured-session-adapter.ts
  • src/main/codex/codex-structured-session-background-tasks.test.ts
  • src/main/codex/codex-structured-session-close.test.ts
  • src/main/codex/codex-structured-session-close.ts
  • src/main/codex/codex-structured-session-teardown.ts
  • src/main/codex/codex-structured-turn-cancellation.ts
  • src/main/daemon/pty-subprocess-spawn-file-foreground.test.ts
  • src/main/daemon/terminal-host-process-inspection.test.ts
  • src/main/github/github-remote-identity-parsing.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter-stop.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-chat-stop.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-child-close.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-claude-hung-start-stop.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-codex-stop-note-end.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-conversation-stop.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-host.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-listed-stop-lifetime.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-prompt-cancel.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-card-holds.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig-provider.test-fixture.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-pause-lift.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-repeated-stop.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt-host.test.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-stop-event-binding.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/native-chat/agent-session-wire/structured-agent-session-stop-event.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stop-note-opened-turn.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stop-note-withdrawn-send.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stop-receipts.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stop-settle-binding.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stop-wind-down.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stopped-history.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-turn-stop-notes.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-turns-cancel.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-turns.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-unnamed-stop-races.test.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-compaction.test.ts
  • src/main/pi/rpc-session-adapter.ts
  • src/main/providers/local-pty-child-process-verdict.test.ts
  • src/main/providers/local-pty-provider-foreground-process.test.ts
  • src/main/runtime/structured-agent-session-codex-compact-exit.test.ts
  • src/main/runtime/structured-agent-session-codex-interrupt-order.test.ts
  • src/main/runtime/structured-agent-session-codex-scripted-child.test.ts
  • src/main/runtime/structured-agent-session-codex-stopped-send-order.test.ts
  • src/main/runtime/structured-agent-session-codex-turn-end-settlement.test.ts
  • src/main/runtime/structured-agent-session-integration.test.ts
  • src/main/runtime/structured-foreground-command-strip.test.ts
  • src/renderer/src/components/terminal-pane/remote-pane-layout-push.ts
  • tests/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.

@brennanb2025

brennanb2025 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor Author

Status: review and real-app QA finished; checks green on the current head

The problem. Pressing Stop in a native chat could leave Codex and the command it was running alive, show no feedback before the agent's first reply, mark child work stopped before anyone knew it had exited, and (found in this round) skip ending the agent entirely when it had just picked up a follow-up message the user sent earlier. In that last case the chat reported the Stop as accepted while the agent kept working.

What changes for the user. A Stop is recorded the moment you press it and the turn reads Interrupted. The agent's runtime ends (background work included), and your next message resumes the same conversation. A message withdrawn before it reached the agent reads Stopped manually beside Cancellation requested. This now also holds when the agent moves on to an already-sent follow-up while the Stop is being accepted: that agent process still ends, and that turn reads Interrupted, not Failed. Child work is marked stopped only once its runtime and workload have really exited.

What was fixed since the last status (review rounds: 2, plus the final readiness pass).

  • Merging main exposed four ordering bugs in one mechanism: when a send's hand-over result is written versus when Stop captures what it is stopping. Two design-panel rulings settled it: the hand-over result is written before Stop closes the agent, and an accepted Stop acts on the facts it captured when it was accepted, rechecking only that it is still the same agent process.
  • Final adversarial review found one P1: a named Stop could drop its runtime end if the same agent process opened another turn during acceptance. Fixed in e55d6cb (64 production lines). The check after acceptance is now identity only, a changed turn only skips the optional interrupt request to the provider, and that turn reads Interrupted. One regression test covers it.
  • Two merges of main (64ac8e8, aba2b47) to clear conflicts from main's comment cleanups ([comment audit] Consolidate completed code comment cleanup #32905, [comment audit] Clean up IPC, host lifecycle and native-chat comments #32966). No working code changed in either resolution for Claude, Codex, ACP or Pi. The real-app QA below ran on e55d6cb; CI on aba2b47 checks the merges (all seven workflows green).

Deferred, with tickets.

  • STA-11949 (P2, a performance slip in this PR): every Stop builds the whole transcript to answer a question only a running command needs (structured-agent-session-chat-stop.ts, the prior-Stop capture). One-line guard; left out so the QA'd code stays as tested.
  • STA-11948 (older than this PR, reproduced on shipped 1.4.237): a shell command cancelled by Stop shows 1 failed for Claude and OpenCode, while Codex shows 1 interrupted. The provider reports the cancelled command as a failed tool result and Orca keeps it.

Verified for real (M4Air, ticket 2034, head e55d6cb). Chats were created on shipped Orca 1.4.237 with a fresh profile, then carried through a real shutdown and upgrade to this build. In each chat: a command running about a minute, a follow-up message sent while it ran, then Stop.

Agent After Stop Agent and command exited Next message
Claude "Interrupted after 40s", follow-up "Stopped manually" yes, within 1.1 s / 0.7 s real reply in the same conversation
Codex "Interrupted after 40s", follow-up "Stopped manually" yes, within 0.34 s "RESUMED DONE", same thread
OpenCode "Interrupted after 8s" yes, within 0.31 s real reply in the same session

A second Stop while the first was closing wasn't possible: the Stop control was already gone, which is the intended outcome. Real agent config files on the machine were unchanged. Earlier rounds (tickets 1294, 1392, 1491) covered Pi Stop/resume, Sleep during startup and phone Stop on earlier heads; the Stop path changed since, so phone and Pi rely on the host tests now (phone Stop goes through the same host code as desktop Stop, which names the running turn the same way). 31 named test files (216 tests) pass on the merged head.

Pi passed real Stop/resume on ticket 1294 (head bfa6885: two real replies, one Stop, Interrupted, original runtime and workload exited, real reply after resuming the same conversation). This PR's own Pi change (src/main/pi/rpc-session-adapter.ts, three deleted lines) is byte-identical then and now; only main merges touched Pi's files since, so that evidence stands. The shared Stop code it uses since then is covered by Claude and Codex above and by Pi's adapter tests.

Not verified. Claude's resumed reply wrongly claimed the command never ran; process records show it did. That is the model's account, not Orca's.

Differences from the common pattern (each labelled; Stop ending the chat's runtime is the common pattern, not a difference): intended — outcomes settle from real exit proof; the Stop request and queue withdrawal are written as one durable record; Stop can abort a send still being prepared; the "Cancellation requested" note. Temporary — the extra transcript read above (STA-11949).

For Brennan's review

Claude: before Stop, after Stop, after resume
Claude before Stop
Claude after Stop
Claude after resume

Codex: before Stop, after Stop, after resume
Codex before Stop
Codex after Stop
Codex after resume

OpenCode: before Stop, after Stop, after resume
OpenCode before Stop
OpenCode after Stop
OpenCode after resume

Shipped 1.4.237, same Stop (shows the older "1 failed" badge)
Shipped 1.4.237 after Stop

Three places where judgment matters:

  1. src/main/native-chat/agent-session-wire/structured-agent-session-chat-stop.ts, the act step after acceptance: identity is the only recheck, so a Stop that was valid when accepted always ends its agent process.
  2. src/main/native-chat/agent-session-wire/structured-agent-session-turns-cancel.ts, where an accepted chat Stop opens the session-wide settle: any turn that ends with that agent process reads Interrupted, while task-row Stops keep their single-turn scope.
  3. src/main/native-chat/agent-session-journal/journal-stop-turn-end.ts: a provider-completed turn stays completed; only a turn cut short by this Stop gets the cancellation outcome.

@brennanb2025
brennanb2025 marked this pull request as draft October 23, 2026 16:35
@brennanb2025
brennanb2025 marked this pull request as ready for review October 23, 2026 16:35
@brennanb2025
brennanb2025 merged commit f04b831 into main Oct 24, 2026
50 checks passed
brennanb2025 added a commit that referenced this pull request Oct 24, 2026
…ct file (#33046)

Main's static lint failed max-lines (303 of 300) on structured-agent-session-adapter.ts after #28051 merged. The adapter's error classes move to structured-agent-session-adapter-errors.ts and are re-exported, so every importer is unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant