Skip to content

Native chat: every agent takes a message while it starts, and Stop ends the session for every agent - #26561

Closed
brennanb2025 wants to merge 16 commits into
mainfrom
brennanb2025/agent-publish-before-handshake
Closed

brennanb2025 wants to merge 16 commits into
mainfrom
brennanb2025/agent-publish-before-handshake

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 136 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​5618 $\color{#cf222e}{\Huge{\mathbf{−}}}$​2368 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​3250
Prod 111 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​3901 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1148 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​2753

ELI5

While an agent finishes starting, a native chat used to hold later messages at “Sending…” and hide its model and effort pickers. The first message already appeared immediately; this change makes later sends immediate too, keeps saved picks visible, and makes Stop end every agent’s session, including Codex’s background work. The next message resumes the same conversation.

What Changed

The chat becomes addressable as soon as its process exists. The execution host holds accepted messages in the durable journal, finishes the handshake in the background, records the real provider handle, applies saved picks, and delivers only after the single started signal. A silent start ends after 60 seconds; output can extend it only to ten minutes. Codex’s mandatory start requests use that same host deadline.

  • Additional messages during startup are accepted at once and delivered in order. The model and effort pickers show the saved selection throughout startup; they remain disabled while a message is working. Picks accepted during a start without a held message are applied before delivery, model before effort; a refused pick returns to what the agent runs.
  • Stop during startup closes the child immediately. The held message keeps main’s “Stopped manually” wording. Other start failures settle held messages once as not sent, with the agent’s own sign-in words when appropriate; signed-out Pi cannot repeatedly restart for the same send.
  • Goals, rewind, unfinished rewind recovery and conversation commands wait for protocol readiness. Worker startup receipts respect the caller’s budget while the accepted preamble remains held on the execution host and can be delivered after client disconnection.
  • Chat Stop interrupts Codex, allows up to five seconds for the turn to settle, then closes its app-server. The Stop on a running-task row remains scoped to that task (Let a Codex chat stop a sub-agent from the background-tasks strip #27026).
  • Final main integration preserves fix(native-chat): a new chat's model and effort pickers match their first frame before the agent starts #27031’s folder-scoped option defaults and older-client fallback during startup as well as at rest.

Final correctness fixes

  • Codex close now snapshots descendants by process ID and start time before closing input, refreshes while the root lives, and reaps survivors after it exits. Commands in separate process groups are covered. Root exit and descendant exit are reported separately; a missing observation stays unverifiable, and a dead root still releases the session.
  • Codex Stop gives the interrupt up to five seconds from the Stop timestamp, then closes the session. A child row says interrupted only when the actual cause is user Stop and its root and workload were proven exited; user-close, contact loss and missing proof keep status unavailable.
  • A failed start no longer starts a fresh model-catalog probe when its options are read. The extra Grok process in the QA trace was launched 0.187 seconds after the failed child closed, from the account folder, and ran for 14.965 seconds: the catalog runner's 15-second probe. Released-session catalog reads are now passive; a new chat can still discover models and a new user send can retry startup.
  • Starting-child option reads now use the same saved folder-scoped catalog and older-client fallback as at-rest reads.

Why

A spawned process is owned before its protocol session is ready. Separating those facts lets Stop, messages, picks and reads remain responsive without sending protocol calls too early. Holding input and startup deadlines on the execution host also lets remote work continue through client contact loss. Descendant cleanup must track process identities across separate process groups; signalling one group cannot prove that all commands ended.

Differences from the common pattern

  • Intended: each chat owns its process, and chat Stop ends that session for every agent. This covers retained background work; the next send resumes the conversation.
  • Intended: input holds and the 60-second silence / ten-minute ceiling belong to the execution host, so an SSH client disconnect cannot cancel accepted work.
  • Temporary — Awaited startup and conversation option display: protocol operations still use refusal/wait/retry, and picker state retains selections across runtime replacement. A separate awaited-start draft removes the startup paths; the option-display follow-up remains separately scoped.

Linked Issue

None; maintainer change. Builds on #26416 and #26332.

Visual Proof

These are hidden Orca dev builds on a Windows test machine. The agents are stand-ins: small scripts that speak the Codex app-server protocol and Grok's ACP protocol. No real agent ran. "Before" is this PR's base, 2cb2bef67e3 (main), and "after" is a6c3a0fada3. For every screenshot, the time it was captured was checked against the stand-in's own log.

1. Sending a message while the agent starts. The stand-in takes 8 s to answer initialize. Open a new chat, type "hello" and press Enter at once. Each screenshot was taken 1.5–5 s after Enter, before the stand-in had answered.

Before (main) After (this PR)
Codex base-codex-send-during-start pr-codex-send-during-start
Grok base-grok-send-during-start pr-grok-send-during-start
  • What they show. On both builds "hello" appears at once and reaches the agent once it has started. For the first message in a new chat, main already behaved this way: the host-side hold from Hold messages in the host until a chat's agent has finished starting #26416 covers it. So the first message is not one of this PR's changes; the ELI5 and "What the user sees now" say which sends change. The one visible difference is the composer. While the agent starts, main shows no model or effort picker. This PR shows them: "GPT-6.1 Sol · Medium" for Codex and "Model" for Grok. The notice in the corner of the "after" Codex shot ("Codex in Orca now uses ~/.codex") is an unrelated first-run notice.
  • Timestamp check (UTC, screenshot capture window vs. the stand-in's initialize answer).
    • Codex after: Enter 23:00:14.39, captured 16.10–20.56, answered 22.70, turn started 22.78.
    • Codex before: Enter 23:20:39.20, captured 40.94–44.27, answered 47.57.
    • Grok after: Enter 23:02:00.58, captured 02.21–05.78, answered 09.01.
    • Grok before: Enter 23:22:01.19, captured 02.78–06.39, answered 09.53.

2. Stop ends Codex's background work. The Codex stand-in's first turn starts a background terminal (npm run dev) and leaves it running when the turn ends, the way Codex does. While its app-server process is alive, the stand-in writes a line to its log every 2 s. A second turn keeps working, then Stop is pressed.

Before Stop (this PR) After Stop, main After Stop, this PR Next message, this PR
pr-codex-before-stop base-codex-after-stop pr-codex-after-stop pr-codex-next-message-after-stop
  • Main. Stop interrupts the turn only. Ten seconds later the running-tasks card still shows "1 shell command". The background terminal kept writing its 2 s log line until the test app was shut down 3 minutes later (Stop at 23:26:33.72, still logging at 23:29:45). The next message ran on the same app-server.

  • This PR. Stop interrupts the turn, then closes the app-server. The stand-in logged:

    • turn/interrupt at 23:15:01.93
    • turn interrupted at 02.14
    • its input closed at 02.34
    • last background line at 23:15:00.74, none after

    The card is gone in the screenshot captured at 23:15:11.91–14.63. The next message started a new app-server, which resumed the same thread (thread/resume with the first app-server's thread id) and answered.

  • What this does not prove. The stand-in fills the running-tasks card the way Codex does: a background command whose turn has ended while the command is still running. A real Codex was checked separately on macOS, as described in "What the user sees now".

3. Live QA across macOS, Windows and an SSH host (dev builds of this PR vs main, hidden windows driven over the DevTools protocol, screenshots checked against agent or stand-in logs; real agent homes hashed before and after, unchanged).

Real Codex 0.159 (macOS): Stop with a background shell and a running subagent. With this PR the card clears and both shells are gone within 2 s (still gone at 30 s), and the next message resumes the same thread. On main both keep running and the subagent keeps spending tokens (23.6k at Stop, 95.2k 90 s later).

Before Stop (this PR) 2 s after Stop (this PR) Next message (this PR) 30 s after Stop (main)
real-codex-before-stop real-codex-after-stop real-codex-next-message main-real-codex-after-stop

A second message while the agent starts (stand-ins, 8–20 s start). Main shows it as "Sending…" and holds further sends; this PR shows it at once and delivers both in order (checked for Codex, Grok, OpenCode, OMP and Pi).

Main This PR
Codex main-codex-second-message pr-codex-second-message
Pi main-pi-second-message pr-pi-second-message

A saved model pick stays on screen while the agent starts (head 05ccab6; the pickers are disabled during a start that a message triggered). Codex Terra/High, Grok 4.7/Low and Pi Sonnet 4/High each show in every frame from the send to after the start; a pick the agent refuses goes back to what it runs.

Codex mid-start Grok mid-start Pi mid-start Refused pick, after start
codex-pick-mid-start grok-pick-mid-start pi-pick-mid-start grok-refused-pick-after

Start limits are the host's for every agent (head 5c66c69). A Codex that answers initialize after 25 s starts normally (it used to be cut off at 15 s); one that never answers is ended at 60.0 s with the host's wording. A signed-out Pi starts once and the message settles with Pi's sign-in line (an earlier head restarted it in a loop).

Codex at ~22 s, still starting Codex never answers, ended at 60 s Signed-out Pi
codex-slow-start codex-silent-60s pi-signed-out

SSH host: the client's connection drops during a 25 s start (throwaway Debian SSH host running this build's managed server). The host keeps starting, delivers the held message during the outage, and the reply is on screen at reconnect; the app only says the host is reconnecting.

Codex during the outage Codex after reconnect Grok after reconnect
ssh-codex-outage ssh-codex-reconnect ssh-grok-reconnect

Testing

  • Previous QA at 05ccab6 covered real Codex and Claude on macOS, all five stand-in agents on Windows, and SSH. These are earlier-head results, retained above for context.

  • Targeted registration/start-deadline/signed-out tests: 51 passed. Folder-scoped first-frame, learned-default, older-client fallback and catalog tests: 57 passed. Cleanup/Stop/router tests: 96 passed; the five-second deadline cases passed; the restored connection/teardown suite passed 39 tests after the new grandchild case failed against the old root-only close.

  • The single real Codex hung-process probe on macOS froze Codex after starting foreground and background commands. Close reported root and workload exited in 4.317 seconds; all marked processes stayed gone through the 30-second observation. The user's configuration hash, excluding project trust entries, was unchanged. This probe tested teardown directly, not rendered UI.

  • Final pre-push checks on 34e53888a3d: 24/25 passed, including all four CI-pinned typechecks, root lint, changed-code quality, localization and runtime/wire checks. Full native typechecks and the freshly synced full anti-slop check also passed. The remaining local mobile import-cycle warning is the documented false red in unchanged files; remote static analysis passed.

  • CI on 34e53888a3d: all 19 required checks passed, with no failures or pending checks. All five unit-test shards, package jobs, cross-version wire compatibility, relay, macOS/Linux/Windows runtime, persistence and verification passed; 14 path/platform-selected checks were skipped.

  • The corrected queued Stop test reproduces the original timeout under Node, then passes 27 affected tests after advancing its frozen five-millisecond fixture timer before awaiting the Stop lane. Every assertion and timeout is preserved; product Stop, delivery and five-second grace code are unchanged.

  • The coordinator reported four macOS rechecks passing on the same production diff at 18ec576514e: real Codex Stop with stopped subagent row and shells gone, held startup picks, folder-scoped first frames, and a second startup message. The final commit changes only the test clock.

  • The coordinator owns rendered UI rechecks; this implementation worker launched no Electron app.

  • I manually tested these changes locally

  • Automated tests added/updated

AI Disclosure

AI coding agents (Codex and Claude Code).

Review

Four architecture reviews agreed on publish-at-spawn, execution-host holds and one readiness signal. They identified descendant-exit evidence and option ownership as the material remaining gaps; this update completes the pre-merge fixes and leaves the larger consolidation to draft stacked PRs.

Agent skill upstream boundary

  • Not applicable; no upstream skill-installer content copied.

Notes

  • Mixed clients and hosts keep existing RPCs and stream operations; new evidence fields are optional. Older producers supply no descendant proof, which remains unverifiable.
  • A live record can carry no proven provider handle between spawn and startup completion. An older downgraded build cannot validate that record after a mid-start crash; it keeps the chat listed but cannot send until a newer build runs again.
  • Older clients keep their bounded send-settlement reply (up to 120 seconds, then pending); accepted input remains on the host. A desktop build between Show "Pi isn't signed in" in native chat before the first send #26743 and this PR shows Pi’s sign-in notice on the first send rather than before it, an intended compatibility limitation affecting no released app.
  • Folder workspaces use the same lifecycle. WSL remains unsupported for structured chat. Real Codex cleanup on Linux/Windows and mobile were not exercised by this worker.

Checklist

  • This PR is small and focused
  • Problem, user-facing change, mechanism and alternatives explained
  • Earlier before/after screenshots retained
  • Cross-platform, SSH and mixed-version behavior considered
  • Final static checks and CI complete

@brennanb2025
brennanb2025 changed the base branch from brennanb2025/agent-startup-host-attempt to main October 8, 2026 18:58
…ain)

Rebuilds #26561 on main now that #26416 is squash-merged. Same change as
before, re-applied onto what main has since:

- Every adapter answers acquire at spawn and reports `started` on protocol
  readiness with its real handle (Claude initialize, Codex thread, ACP
  session new/load plus restore, Pi session file plus restore). No bridge,
  no per-adapter phase or Stop opt-outs.
- Picks made while starting are intents applied model then effort before
  the start is accepted; rewind, goal, rewind recovery and compact wait for
  a proven start outside the session queue.
- One Stop rule: Stop ends the session for every agent (Codex: interrupt,
  up to 2 s for the turn to end, then close).
- Orchestration worker starts share one deadline; a send's answer copies
  its row; a re-attach during start keeps the start wait.

Integrated with main:
- ACP: the subagent-stop probe, child-work delivery and new/loaded origin
  move into the handshake; the sign-in rule (#26544) classifies a failed
  handshake; acpAgentName stays in acp-structured-agent-definitions.
- Codex: the session journal translator and account kind (#26407) reach the
  start step.
- Pi: the start choice (#26821) and the signed-out verdict (#26743) are read
  in Pi's start, so both exist when `started` is reported; commands follow.
- openWithAgent keeps main's pre-agent check and replay rule.
- A report with no model drops the saved one, as #26587 decided.
- The renderer re-reads a start's sign-in verdict once the start is proven.
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agent-publish-before-handshake branch from a0a8038 to 1a07fc6 Compare October 9, 2026 21:02
…ad wait out an agent's start

A signed-out Grok, OpenCode or OMP that wrote to stderr before refusing its
start showed that log line instead of its sign-in message. A sign-in
refusal now keeps the agent's own words; other start failures keep the
stderr tail.

While a chat's agent proves its start, the model-catalog read answers
listingInProgress and a waiting read waits the start out (bounded), so a
client that re-reads only then still hears Pi's signed-out verdict.
The gap it closed exists only for a desktop app built between #26743 and
this change; no released app shows the Pi notice yet, and the first send
still says not signed in. Not worth a held read on every agent's start.
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review summary

Reviews: two rounds on the original branch, plus a fresh full review of the rebuild on current main (1a07fc6). The rebuild review found no P0/P1. It checked file by file that main's behaviour survives: the first message travels with the create call (#26332), learned defaults (#26407/#26821), Grok subagent Stop (#26508), the empty-model rule (#26587), and the Pi sign-in notice (#26743).

Fixed after the rebuild:

  • A signed-out Grok, OpenCode or OMP could show stray error output instead of its own sign-in message. Fixed in ad5d2cc, with a test that fails without the fix.
  • Older apps lose Pi's "isn't signed in" notice before the first send. A host-side hold was tried and then taken back out (a6c3a0f) as more machinery than the gap deserves. Show "Pi isn't signed in" in native chat before the first send #26743 shipped after v1.4.223, so no released app is affected. This is labelled intended in the body.
  • PR body corrected after live QA: a new chat's first message already worked while the agent started on main. The body now says which sends change.

Visual proof (in the body), on Windows with stand-in agents and screenshots checked against the stand-in logs:

  • Stop ends Codex's background terminal. On main the running-tasks card stays and the terminal keeps logging. With this PR the terminal stops within half a second and the card clears, and the next message resumes the same thread.
  • While starting, the model and effort pickers show on this PR; they are missing on main.

CI: cross-version wire compatibility fails on main's own "kiro" search tests, and the verify job only reports that result. All five test shards and both package jobs pass.

Not verified: real Codex (whether its background terminals and subagents end when the app-server closes), a second message sent while the agent starts (the claim comes from the code), Pi/OpenCode/OMP live, and SSH/WSL/macOS/Linux. Whichever of this PR and #26982 merges second needs a sync with main.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 9, 2026 23:47
@coderabbitai

coderabbitai Bot commented Oct 10, 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: cb0d03f1-9198-47ee-9711-0d1cae43b6e5
















📥 Commits

Reviewing files that changed from the base of the PR and between 2cade43 and 20832cb.

















📒 Files selected for processing (13)
  • src/main/codex/codex-structured-publish-at-spawn.test.ts
  • src/main/codex/codex-structured-service-tier.test.ts
  • src/main/codex/codex-structured-session-acquire.ts
  • src/main/codex/codex-structured-session-adapter.test.ts
  • src/main/codex/codex-structured-session-adapter.ts
  • src/main/codex/codex-structured-session-options.test.ts
  • src/main/codex/codex-structured-session-options.ts
  • src/main/codex/codex-structured-session-start.ts
  • src/main/codex/codex-structured-turn-cancellation.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-option-restoration.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.ts
  • src/main/runtime/structured-foreground-command-strip.test.ts
















💤 Files with no reviewable changes (1)
  • src/main/native-chat/agent-session-wire/structured-agent-session-option-restoration.ts
















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


















📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough

@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


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: de35af34-d6e3-411e-99ca-9889112a06bb
📥 Commits

Reviewing files that changed from the base of the PR and between d358e59 and a6c3a0f.

📒 Files selected for processing (221)
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • src/main/acp/acp-prompt-content.ts
  • src/main/acp/acp-scripted-child-runtime.test.ts
  • src/main/acp/acp-scripted-child.test-fixture.ts
  • src/main/acp/acp-scripted-connection.test-fixture.ts
  • src/main/acp/acp-structured-acquire.ts
  • src/main/acp/acp-structured-adapter.test-support.ts
  • src/main/acp/acp-structured-auth.test.ts
  • src/main/acp/acp-structured-broken-stream.test.ts
  • src/main/acp/acp-structured-child-lifecycle.ts
  • src/main/acp/acp-structured-child-stop.ts
  • src/main/acp/acp-structured-child.ts
  • src/main/acp/acp-structured-handshake.ts
  • src/main/acp/acp-structured-host-configured-default.test.ts
  • src/main/acp/acp-structured-host-lifecycle.test.ts
  • src/main/acp/acp-structured-host-restore-failed.test.ts
  • src/main/acp/acp-structured-host-start-aborts.test.ts
  • src/main/acp/acp-structured-host-start-failure.test.ts
  • src/main/acp/acp-structured-host.test-support.ts
  • src/main/acp/acp-structured-missing-model.test.ts
  • src/main/acp/acp-structured-options.ts
  • src/main/acp/acp-structured-publish-at-spawn.test.ts
  • src/main/acp/acp-structured-session-adapter-lifecycle.test.ts
  • src/main/acp/acp-structured-session-adapter-resume.test.ts
  • src/main/acp/acp-structured-session-adapter-teardown.test.ts
  • src/main/acp/acp-structured-session-adapter.test.ts
  • src/main/acp/acp-structured-session-adapter.ts
  • src/main/acp/acp-structured-session.ts
  • src/main/acp/acp-structured-sign-in.test.ts
  • src/main/acp/acp-structured-steer.test.ts
  • src/main/acp/acp-turn-failures.ts
  • src/main/claude/claude-scripted-child.test-fixture.ts
  • src/main/claude/claude-structured-prompt-ownership.ts
  • src/main/claude/claude-structured-real-cli.test.ts
  • src/main/claude/claude-structured-resume-point.test.ts
  • src/main/claude/claude-structured-session-acquisition.ts
  • src/main/claude/claude-structured-session-adapter.test.ts
  • src/main/claude/claude-structured-session-adapter.ts
  • src/main/claude/claude-structured-session-prompts.test.ts
  • src/main/claude/claude-structured-session-startup-state.ts
  • src/main/claude/claude-structured-session-startup.test.ts
  • src/main/codex/codex-app-server-connection.ts
  • src/main/codex/codex-app-server-spawn-publication.test.ts
  • src/main/codex/codex-collab-call-frames-fixture.ts
  • src/main/codex/codex-default-mode-subagents.test.ts
  • src/main/codex/codex-provider-retry-row.test.ts
  • src/main/codex/codex-request-end-wait.test.ts
  • src/main/codex/codex-request-end-wait.ts
  • src/main/codex/codex-scripted-child.test-fixture.ts
  • src/main/codex/codex-structured-background-catalog.ts
  • src/main/codex/codex-structured-child-work-producer.test.ts
  • src/main/codex/codex-structured-dispatch-test-support.ts
  • src/main/codex/codex-structured-fast-mode.test.ts
  • src/main/codex/codex-structured-journal-translation.ts
  • src/main/codex/codex-structured-live-provider-process.test.ts
  • src/main/codex/codex-structured-prompt-ownership.test.ts
  • src/main/codex/codex-structured-publish-at-spawn.test.ts
  • src/main/codex/codex-structured-session-acquire.ts
  • src/main/codex/codex-structured-session-adapter-fixture.ts
  • src/main/codex/codex-structured-session-adapter-lifecycle.test.ts
  • src/main/codex/codex-structured-session-adapter.test.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-cancel.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-exit-blame.test.ts
  • src/main/codex/codex-structured-session-options.test.ts
  • src/main/codex/codex-structured-session-options.ts
  • src/main/codex/codex-structured-session-prompts.test.ts
  • src/main/codex/codex-structured-session-shutdown.test.ts
  • src/main/codex/codex-structured-session-start.ts
  • src/main/codex/codex-structured-session-state.ts
  • src/main/codex/codex-structured-session-teardown.ts
  • src/main/codex/codex-structured-starting-child.ts
  • src/main/codex/codex-structured-turn-steer.test.ts
  • src/main/codex/codex-structured-visuals.test.ts
  • src/main/jsonl-rpc/agent-connection.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-accept-then-deliver.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-acquisition-options.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-acquisition.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-append-delivery.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attach-flow.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attach-orchestration.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-option-queue.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-command-readers.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-conversation-close.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-conversation-lifetime.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-crash-mid-start.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-event-recovery.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-held-start.test-support.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-delivery.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-mutations.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-runtime-state.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-test-harness.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-types.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-instant-start.test-support.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-late-settlement.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-legacy-handoff-record.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-main-agent-working-agreement.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-mutation-plans.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-option-restoration.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-option-settlement.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-child-record.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-child-start-wait.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-child.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-start-hold.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-started-catalog.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-started.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-compact.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-message-rig.test-fixture.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-messages.test.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-refusal-retry.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-repeat-press.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-rest-test-rig.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-context-clear.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-resume-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-resume.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-status-publication.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-witnesses.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-witnesses.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind-at-rest.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind-live-send.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind-stop-note.test-fixture.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-send-restarts-failed-start.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-settled-attach-retry.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-start-failure-writer.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-startup-attempt-registrations.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-intent.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-picks.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-never-waits.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-stopping.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-surface-lifetime.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-thread-goal.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.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-unrun-send-hold.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-working-at-teardown.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command.test.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-compaction.test.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-compaction.ts
  • src/main/native-chat/agent-session-wire/structured-rewind-refusal.ts
  • src/main/native-chat/native-chat-inline-visuals-setting.test.ts
  • src/main/pi/pi-scripted-child.test-fixture.ts
  • src/main/pi/rpc-configured-default.test.ts
  • src/main/pi/rpc-runtime-registration.ts
  • src/main/pi/rpc-session-adapter.test-fixture.ts
  • src/main/pi/rpc-session-adapter.test.ts
  • src/main/pi/rpc-session-adapter.ts
  • src/main/pi/rpc-session-startup.test.ts
  • src/main/pi/rpc-session-startup.ts
  • src/main/pi/rpc-session.ts
  • src/main/runtime/agent-session-acquisition-failure-settlement.ts
  • src/main/runtime/agent-session-lease-transitions.ts
  • src/main/runtime/agent-session-record-options.test.ts
  • src/main/runtime/agent-session-record-store.test.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/claude-structured-startup-unanswered-control-request.test.ts
  • src/main/runtime/orchestration/send-agent-turn.test.ts
  • src/main/runtime/orchestration/send-agent-turn.ts
  • src/main/runtime/rpc/methods/orchestration-structured-worker-session.ts
  • src/main/runtime/rpc/methods/orchestration-structured-worker-start-deadline.test.ts
  • src/main/runtime/rpc/methods/orchestration/worker/deliver-worker-dispatch-preamble.ts
  • src/main/runtime/rpc/methods/orchestration/worker/local-worker-start.ts
  • src/main/runtime/rpc/methods/orchestration/worker/worker-start-readiness-settlement.test.ts
  • src/main/runtime/rpc/methods/orchestration/worker/worker-start-readiness-settlement.ts
  • src/main/runtime/structured-agent-registration-lifecycle-matrix.test.ts
  • src/main/runtime/structured-agent-runtime-registrations.ts
  • src/main/runtime/structured-agent-scripted-child.test-fixture.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-opening-send-hold.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-agent-session-pi-startup.test.ts
  • src/main/runtime/structured-agent-session-provider-operations-while-starting.test.ts
  • src/main/runtime/structured-agent-session-runtime.ts
  • src/main/runtime/structured-agent-session-transport-overrides.ts
  • src/main/runtime/structured-claude-pending-rewind.test.ts
  • src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
  • src/shared/agent-session-record.ts
  • tests/e2e/cross-version-wire/cross-version-agent-session-wire.unit.test.ts
  • tests/e2e/cross-version-wire/cross-version-stop-note-test-rig.ts
  • tests/e2e/cross-version-wire/structured-agent-session-host-fixture.ts
  • tests/e2e/structured-chat-owner-status-activation.unit.test.ts
💤 Files with no reviewable changes (9)
  • src/main/runtime/claude-structured-startup-unanswered-control-request.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-witnesses.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt-registrations.test.ts
  • src/main/claude/claude-structured-session-startup-state.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-witnesses.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.ts
  • src/main/claude/claude-structured-session-adapter.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-resume-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-unrun-send-hold.test.ts

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

'src/main/native-chat/agent-session-wire/structured-agent-session-start-failure-writer.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-startup-attempt-registrations.test.ts',
'src/main/native-chat/agent-session-wire/structured-agent-session-startup-picks.test.ts',

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
fd -i 'structured-agent-session-startup-attempt-registrations.test.ts'
fd -i 'structured-agent-session-startup-picks.test.ts'
rg -n 'SQLITE_RUNTIME_INCLUDE|SQLITE_DATABASE_RUNTIME_INCLUDE' --type=js --type=ts -g '!node_modules' -C3
for f in $(fd -i -e ts 'startup-attempt-registrations|acp-structured-host-start-failure|acp-structured-publish-at-spawn|acp-structured-host-lifecycle'); do
  echo "== $f"; rg -n 'openTestAgentSessionRecordStore|openTestJournalHostDatabase|openHostRig|openProviderTimelineRig' "$f" | head
  rg -n "$(basename "$f")" config/scripts/vitest-sqlite-runtime-files.mjs
done

Repository: stablyai/orca

Length of output: 3515


🏁 Script executed:

set -eu
printf '%s\n' '== revision availability and changed paths =='
git cat-file -e a6c3a0fada321cce276ed6d75f3717bbe3162fce^{commit}
git cat-file -e 2cb2bef67e3a8c9435c8ebd30ce6f2f0b4dadf08^{commit}
git diff --name-status 2cb2bef67e3a8c9435c8ebd30ce6f2f0b4dadf08 a6c3a0fada321cce276ed6d75f3717bbe3162fce -- \
  config/scripts/vitest-sqlite-runtime-files.mjs \
  'src/main/**/structured-agent-session-startup-attempt-registrations.test.ts' \
  'src/main/**/structured-agent-session-startup-picks.test.ts' \
  'src/main/acp/acp-structured-host-start-failure.test.ts' \
  'src/main/acp/acp-structured-publish-at-spawn.test.ts' \
  'src/main/acp/acp-structured-host-lifecycle.test.ts'
printf '%s\n' '== current runtime include file =='
nl -ba config/scripts/vitest-sqlite-runtime-files.mjs
printf '%s\n' '== relevant files in reviewed head =='
for f in \
  src/main/native-chat/agent-session-wire/structured-agent-session-startup-picks.test.ts \
  src/main/acp/acp-structured-host-start-failure.test.ts \
  src/main/acp/acp-structured-publish-at-spawn.test.ts \
  src/main/acp/acp-structured-host-lifecycle.test.ts; do
  if git cat-file -e "a6c3a0fada321cce276ed6d75f3717bbe3162fce:$f" 2>/dev/null; then
    echo "== $f"
    git show "a6c3a0fada321cce276ed6d75f3717bbe3162fce:$f" | nl -ba | sed -n '1,140p'
  else
    echo "MISSING $f"
  fi
done
printf '%s\n' '== old test in base and head =='
for rev in 2cb2bef67e3a8c9435c8ebd30ce6f2f0b4dadf08 a6c3a0fada321cce276ed6d75f3717bbe3162fce; do
  echo "REV $rev"
  git ls-tree -r --name-only "$rev" | grep -F 'structured-agent-session-startup-attempt-registrations.test.ts' || :
done

Repository: stablyai/orca

Length of output: 42058


🏁 Script executed:

set -eu
printf '%s\n' '== runtime include membership =='
for f in \
  config/scripts/vitest-sqlite-runtime-files.mjs \
  config/scripts/vitest-sqlite-database-runtime-files.mjs \
  config/scripts/vitest-node-runtime-files.mjs; do
  echo "== $f"
  rg -n -F -- \
    'acp-structured-host-start-failure.test.ts' \
    'acp-structured-publish-at-spawn.test.ts' \
    'acp-structured-host-lifecycle.test.ts' \
    'structured-agent-session-startup-attempt-registrations.test.ts' \
    'structured-agent-session-startup-picks.test.ts' "$f" || :
done
printf '%s\n' '== runtime selection references =='
rg -n -F -- 'SQLITE_RUNTIME_INCLUDE' config package.json pnpm-workspace.yaml . 2>/dev/null | head -80 || :
printf '%s\n' '== helper definitions =='
rg -n -F -- 'export async function openHostRig' src/main/acp 'export async function openAcpAdapterRig' src/main/acp || :
rg -n -F -- 'function openHostRig' src/main/acp 'function openAcpAdapterRig' src/main/acp || :
printf '%s\n' '== host rig support =='
for f in src/main/acp/acp-structured-host.test-support.ts src/main/acp/acp-structured-adapter.test-support.ts; do
  echo "== $f"
  rg -n -C6 -F -- 'openHostRig' "$f" || :
  rg -n -C6 -F -- 'openAcpAdapterRig' "$f" || :
done

Repository: stablyai/orca

Length of output: 5345


🏁 Script executed:

set -eu
printf '%s\n' '== exact runtime include membership =='
for name in \
  acp-structured-host-start-failure.test.ts \
  acp-structured-publish-at-spawn.test.ts \
  acp-structured-host-lifecycle.test.ts \
  structured-agent-session-startup-attempt-registrations.test.ts \
  structured-agent-session-startup-picks.test.ts; do
  echo "== $name"
  for f in \
    config/scripts/vitest-sqlite-runtime-files.mjs \
    config/scripts/vitest-sqlite-database-runtime-files.mjs \
    config/scripts/vitest-node-runtime-files.mjs; do
    rg -n -F -- "$name" "$f" || :
  done
done
printf '%s\n' '== runtime selector =='
rg -n -C5 -F -- 'SQLITE_RUNTIME_INCLUDE' config/scripts package.json
printf '%s\n' '== host rig implementation =='
sed -n '1,125p' src/main/acp/acp-structured-host.test-support.ts
printf '%s\n' '== adapter rig implementation =='
sed -n '1,145p' src/main/acp/acp-structured-adapter.test-support.ts

Repository: stablyai/orca

Length of output: 13392


Add the new ACP tests to the SQLite runtime include.

The startup-attempt registrations test was deleted, so it does not need to be restored. However, the three new ACP tests are absent from the SQLite runtime lists. Their rigs use real record-store or journal fixtures. Without these entries, the tests can run under the wrong Vitest runtime.

🐛 Suggested fix
   'src/main/acp/acp-structured-host-configured-default.test.ts',
+  'src/main/acp/acp-structured-host-start-failure.test.ts',
+  'src/main/acp/acp-structured-host-lifecycle.test.ts',
+  'src/main/acp/acp-structured-publish-at-spawn.test.ts',

Comment on lines +391 to +394
// Null: the owner's process is live and its provider has not answered with a handle yet.
(validated.lease.provenHandleLinkId === null ||
(head?.linkId === validated.lease.provenHandleLinkId &&
head.mintedAtFence === validated.lease.runtimeFence))))

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Find how the journal database marks itself as written by a newer Orca, and whether this PR bumps that version.
rg -nP -C3 'readOnly|writtenByNewer|isJournalWrittenByNewerOrca|SCHEMA_VERSION|user_version' --type=ts src/main/native-chat/agent-session-journal src/main/runtime src/shared | head -120
git diff origin/main...HEAD --stat -- src/main/native-chat/agent-session-journal src/shared/agent-session-record.ts 2>/dev/null | tail -20

Repository: stablyai/orca

Length of output: 14066


🏁 Script executed:

set -e
printf '%s\n' '--- journal database schema ---'
nl -ba src/main/native-chat/agent-session-journal/journal-database-schema.ts
printf '%s\n' '--- journal host database open path ---'
nl -ba src/main/native-chat/agent-session-journal/journal-host-database.ts | sed -n '1,180p'
printf '%s\n' '--- journal store schema/open callers ---'
rg -n -C4 -- 'JOURNAL_DB_SCHEMA_VERSION|readOnly|SAVED_BY_NEWER_ORCA|parseJournalRow|isPersistedAgentSessionRecord' src/main/native-chat/agent-session-journal src/shared/agent-session-record.ts
printf '%s\n' '--- changed validator and PR diff ---'
nl -ba src/shared/agent-session-record.ts | sed -n '350,420p'
git diff 2cb2bef67e3a8c9435c8ebd30ce6f2f0b4dadf08 a6c3a0fada321cce276ed6d75f3717bbe3162fce -- src/shared/agent-session-record.ts src/main/native-chat/agent-session-journal/journal-database-schema.ts src/main/native-chat/agent-session-journal/journal-host-database.ts

Repository: stablyai/orca

Length of output: 42087


🏁 Script executed:

set -e
printf '%s\n' '--- merge-base validator and schema ---'
git show 2cb2bef67e3a8c9435c8ebd30ce6f2f0b4dadf08:src/shared/agent-session-record.ts | nl -ba | sed -n '330,405p'
git show 2cb2bef67e3a8c9435c8ebd30ce6f2f0b4dadf08:src/main/native-chat/agent-session-journal/journal-database-schema.ts | nl -ba | sed -n '1,22p'
printf '%s\n' '--- database version/open implementation ---'
nl -ba src/main/native-chat/agent-session-journal/journal-database.ts | sed -n '1,220p'
printf '%s\n' '--- persisted-record loading and invalid-record handling ---'
rg -n -C5 -- 'isPersistedAgentSessionRecord|record_json|quarantine|set_aside|unreadable|agent_session_records' src/main/native-chat/agent-session-journal src/shared

Repository: stablyai/orca

Length of output: 41732


🏁 Script executed:

set -e
printf '%s\n' '--- record row files ---'
rg --files src/main/native-chat/agent-session-journal src | rg 'agent-session-record-rows|agent-session-record'
printf '%s\n' '--- record validation/load/quarantine references ---'
rg -n -C8 -- 'isPersistedAgentSessionRecord|decodePersistedAgentSessionRecord|set aside|setAside|quarantine|agent_session_records|record_json' src/main/native-chat/agent-session-journal src/main src/shared/agent-session-record*.ts
printf '%s\n' '--- live unproven writer references ---'
rg -n -C6 -- 'proveAgentSessionOwner|provenHandleLinkId' src/main src/shared

Repository: stablyai/orca

Length of output: 45667


Bump the journal database schema version for the new live lease state.

This change can write a live lease with provenHandleLinkId === null. The merge-base validator rejects that state, but both builds use journal schema version 4. The older opener therefore does not enter read-only mode and can quarantine the record.

If downgrade remains supported, bump JOURNAL_DB_SCHEMA_VERSION so older builds refuse the database instead of refusing individual chats.

Suggested fix
-/** Version 4: the chat records. Each row is one JSON value, so a row this build cannot read stays
+/** Version 5: the chat records. Each row is one JSON value, so a row this build cannot read stays
  *  byte-identical. */
...
-export const JOURNAL_DB_SCHEMA_VERSION = 4
+export const JOURNAL_DB_SCHEMA_VERSION = 5

… start

#26982 reported a no-pick chat's configured default once, from a ready child's
acquisition. With every acquire now returning at spawn, the start listing rides
on `started` instead: ACP's after its option restore, Pi's from the model list
its start reads. The host saves it inside the `started` step, and a failure to
save it is logged, never the start's. Claude keeps its default on the settings
readback, saved behind the attach. The acquisition hook and its field are gone.

Also moves the start-listing saves and the Stop note's turn scope into their own
modules to keep the merged files under the line limit.

@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: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6296aa14-9fd3-49b9-9f0d-186e57bd4f1b
📥 Commits

Reviewing files that changed from the base of the PR and between a6c3a0f and 58f3e6f.

📒 Files selected for processing (20)
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • src/main/acp/acp-structured-handshake.ts
  • src/main/acp/acp-structured-host-configured-default.test.ts
  • src/main/acp/acp-structured-host-live-listing.test.ts
  • src/main/acp/acp-structured-options.ts
  • 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-acquisition.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attach-flow.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attach-orchestration.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-started.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-start-listing.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/pi/rpc-configured-default.test.ts
  • src/main/pi/rpc-session-adapter.ts
  • src/main/pi/rpc-session-startup.ts
  • src/main/pi/rpc-session.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts

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

Comment on lines +184 to +186
// One rule for every agent: a chat's Stop ends its session, background work included; the next
// send resumes the conversation. A row's Stop (`scope`) stops only that task.
const endsSession = input.endSession !== undefined

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Find performCancel callers and check whether endSession and scope can be passed together.
rg -nP --type=ts -C12 '\bperformCancel\s*\(' src/main -g '!**/*.test.ts'
rg -nP --type=ts -C6 '\bendSession\s*:' src/main -g '!**/*.test.ts'
rg -nP --type=ts -C6 "scope:\s*'background-tasks'" src/main -g '!**/*.test.ts'

Repository: stablyai/orca

Length of output: 11689


🏁 Script executed:

set -e
printf '%s\n' '--- input/type declarations and performCancel flow ---'
sed -n '1,340p' src/main/native-chat/agent-session-wire/structured-agent-session-turns-cancel.ts
printf '%s\n' '--- mutation-plan cancel declaration and caller ---'
sed -n '200,275p' src/main/native-chat/agent-session-wire/structured-agent-session-mutation-plans.ts
printf '%s\n' '--- chat-stop caller and input construction ---'
sed -n '90,180p' src/main/native-chat/agent-session-wire/structured-agent-session-chat-stop.ts
printf '%s\n' '--- all endSession references in the native-chat wire scope ---'
rg -n -F --glob '*.ts' -- 'endSession' src/main/native-chat/agent-session-wire

Repository: stablyai/orca

Length of output: 23566


🏁 Script executed:

set -e
printf '%s\n' '--- performCancel input and relevant branch ---'
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-turns-cancel.ts | sed -n '1,215p;250,310p'
printf '%s\n' '--- chat-stop complete local context ---'
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-chat-stop.ts | sed -n '1,175p'
printf '%s\n' '--- definitions/usages of named and stop input ---'
rg -n -C8 --type=ts '\bnamed\b|structuredAgentSession.*Stop|scope' src/main/native-chat/agent-session-wire/structured-agent-session-chat-stop.ts src/main/native-chat/agent-session-wire/structured-agent-session-turns-cancel.ts

Repository: stablyai/orca

Length of output: 42163


🏁 Script executed:

set -e
rg -n -C10 --type=ts 'function structuredAgentSessionStopNamesTurnNotLive|structuredAgentSessionStopNamesTurnNotLive\s*=' src/main src/shared

Repository: stablyai/orca

Length of output: 2806


Prevent a scoped Stop from ending the session.

PerformCancelInput accepts scope and endSession together. A scoped input without turnId makes namesTurnNotLive false, so the background task can be stopped and the session wind-down branch can still run. Exclude scoped Stops from session termination.

🐛 Suggested fix
-  const endsSession = input.endSession !== undefined
+  const endsSession = input.endSession !== undefined && input.scope === undefined
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// One rule for every agent: a chat's Stop ends its session, background work included; the next
// send resumes the conversation. A row's Stop (`scope`) stops only that task.
const endsSession = input.endSession !== undefined
// One rule for every agent: a chat's Stop ends its session, background work included; the next
// send resumes the conversation. A row's Stop (`scope`) stops only that task.
const endsSession = input.endSession !== undefined && input.scope === undefined

…blish-before-handshake

# Conflicts:
#	src/main/acp/acp-structured-session-adapter-lifecycle.test.ts
#	src/main/pi/rpc-session-adapter.test.ts
…blish-before-handshake

# Conflicts:
#	src/main/codex/codex-app-server-connection.ts
#	src/main/jsonl-rpc/agent-connection.ts

@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: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 523e16bd-b59d-4304-b0bb-5d6253d85d6b
📥 Commits

Reviewing files that changed from the base of the PR and between d7acf9a and 2cade43.

📒 Files selected for processing (5)
  • src/main/codex/codex-app-server-connection.ts
  • src/main/codex/codex-app-server-spawn-publication.test.ts
  • src/main/codex/codex-structured-session-close.ts
  • src/main/jsonl-rpc/agent-connection.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-card-holds.test.ts

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

Comment on lines +86 to +92
const error = withProviderDiagnostic(
new Error(
exit.processless
? 'Agent process could not start'
: `Agent process exited (code ${exit.code ?? 'none'}, signal ${exit.signal ?? 'none'})`
),
providerDiagnostic(managed.stderrTail(), 'person')

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Inspect the managed-process exit callback and stderr-tail lifecycle.
ast-grep outline src/main/provider-process/managed-provider-process.ts \
  --match 'spawnManagedProviderProcess|onExit|stderrTail' --view expanded
rg -n -C 6 'onExit|stderrTail|stderr.*(end|close)|child\.on\(.exit.|child\.on\(.close.' \
  src/main/provider-process/managed-provider-process.ts

Repository: stablyai/orca

Length of output: 3054


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- agent connection ---'
nl -ba src/main/jsonl-rpc/agent-connection.ts | sed -n '55,110p'
printf '%s\n' '--- managed process lifecycle ---'
nl -ba src/main/provider-process/managed-provider-process.ts | sed -n '1,190p'
printf '%s\n' '--- managed process callers/options ---'
rg -n -C 5 -F -- 'spawnManagedProviderProcess' src/main

Repository: stablyai/orca

Length of output: 44843


Wait for stderr to drain before building the exit diagnostic.

managed.onExit runs from the child exit event, while managed.stderrTail() is updated by the piped stderr data handler. The diagnostic can omit stderr data delivered after exit. Make the managed-process exit callback wait for the stderr stream to close, with a bounded fallback, before reading stderrTail().

…blish-before-handshake

# Conflicts:
#	src/main/codex/codex-structured-background-catalog.ts
#	src/main/codex/codex-structured-fast-mode.test.ts
#	src/main/codex/codex-structured-session-acquire.ts
#	src/main/codex/codex-structured-session-adapter.test.ts
#	src/main/codex/codex-structured-session-options.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-option-restoration.ts
Codex sent its startup `initialize` with a hard 15 s timeout, and `thread/start`
or `thread/resume` with the 30 s request timeout, under the host's startup
attempt (a minute without output, ten minutes at most). A Codex that answered
after 15 s was closed and the held message reported as not sent. Pi's
`get_state` and saved model and effort restores had the same 30 s cap.

A request the start cannot go on without now waits as long as the host's
attempt does, as Claude's initialize and ACP's protocol requests already did.
Optional reads that never fail a start keep their own bounds. Other callers of
the Codex handshake keep 15 s.
…blish-before-handshake

# Conflicts:
#	src/main/acp/acp-structured-acquire.ts
#	src/main/acp/acp-structured-child-stop.ts
…eld picks shown while the agent starts

A child started for a send is no longer replaced as signed out for that same
send, which restarted a signed-out Pi forever. The provisional launch latches
its held picks so the disabled pickers show the saved pick during the start.
…arts

The picker's option state was reset to the listing's default at every fence,
and a starting new chat is not read. With the agent published at spawn the
fence moves before the handshake, so a pick made at rest showed the default
for the whole start. Keep the same chat's state across its fences until the
new runtime's own read answers.
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Live QA round and fixes (head 05ccab6)

This PR was QA'd on macOS (real Codex 0.159 and real Claude 2.1.280), Windows (stand-ins for all five agents), and an SSH host. Each run compared this PR against main. The screenshots are in the body under Visual Proof, section 3.

QA found these, and they are fixed with tests that fail without the fix:

  • A signed-out Pi restarted in a loop after a send. The fix keeps a child that was started for this send, so the message settles once with Pi's sign-in line.
  • Disabled pickers showed the agent's default during a start, then flipped to the saved pick.
    • A pick carried by the create is now latched.
    • The chat's option state is now kept across its own fences. This fence-level fix is the root cause.
    • Re-QA live: Codex, Grok and Pi show the pick in every frame.
  • Codex's own 15 s initialize cap and 30 s thread cap, and Pi's 30 s start-request cap, now defer to the host's limits (60 s of silence, 10 min ceiling). Re-QA live: a 25 s Codex start works. A Codex that never answers is ended at 60.0 s.
  • A main comment claimed Codex kills a stopped turn's commands. Real Codex keeps them as background terminals; the comment is fixed.
  • The PR body is corrected:
    • Pickers are disabled while a message holds the start.
    • Stop during a start shows "Stopped manually", not "not sent".
    • Rewind and goal didn't fail on main in live flows.

Verified live on this PR:

  • Real-Codex Stop ends background shells and subagent work, and the next message resumes the same thread.
  • A second message while starting is accepted at once, for all five agents.
  • Stop during a Codex start takes effect in 29 ms. Main waited for initialize.
  • Start-failure and 60 s silence wording.
  • The agent's own sign-in words for Grok, OpenCode and OMP.
  • Rewind and goal during start.
  • worker-start respects a short --timeout.
  • On an SSH host, a dropped client connection during a 25 s start does not end it: the message is delivered during the outage.
  • Real Claude: send, Stop, next message, and the learned default first frame.

CI: green at 05ccab6 (20 pass, 15 skipped, 0 fail).

Known gaps, labelled in the body:

  • After the chat's Stop, a Codex subagent row reads "status unavailable". This is temporary; a follow-up PR settles it to the stopped wording. Claude's roster has the same sweep on main.
  • A hung Codex whose own shutdown can't run leaves its commands running, while close reports clean. This is temporary; a follow-up PR uses the existing process-tree capture/reap for Codex.

Not verified:

  • Real Grok, OpenCode, OMP and Pi.
  • Real Codex on Linux or Windows.
  • Mobile and WSL.

The queue test waited for its lane before advancing the fake provider's
wind-down check, so CI timed out. Advance the existing five-millisecond
timer after the accepted turn settles, preserving the behavior assertions.
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Final round: ready to merge (head 34e5388)

Since the last round:

  • Main merged in once. Starting and at-rest option reads both keep fix(native-chat): a new chat's model and effort pickers match their first frame before the agent starts #27031's folder-scoped defaults and the fallback for older clients.
  • Codex close cleans up leftover processes. It records each child process (by pid and start time) before closing, then reaps any still running after Codex exits. If it can't see the process tree, the close is reported as unverifiable, never clean. A test with a frozen app-server and a separately grouped grandchild fails without this. On real Codex 0.159 on macOS, a frozen Codex and its commands were gone in 4.3 s and still gone 30 s later.
  • Stop waits 5 s for Codex to wind down (was 2 s).
  • Subagent rows after Stop. A row now settles to "stopped" only when both the root and its work are proven exited. Contact loss and missing evidence still show "unavailable".
  • No catalog probe after a failed start. A failed start no longer kicks off a model-catalog probe. That probe explains the extra Grok process the Windows QA saw after the 60 s limit.
  • CI fixes, both test-only: a fixture-module mock rule, and a fake clock that was never advanced in the queued-card wind-down test.

Live re-QA at 18ec576 on macOS: all pass. The commit after it changes only a test.

  • Real Codex Stop with a background shell and a running subagent:
    • the running-tasks card clears;
    • both shells are gone at 2, 10 and 30 s;
    • the subagent row reads "stopped";
    • the next message resumes the same thread.
  • A pick saved at rest shows on every frame through the start, for Codex, Grok and Pi.
  • fix(native-chat): a new chat's model and effort pickers match their first frame before the agent starts #27031 first frames still hold. A plain folder shows no jump. A folder with its own config stays on the placeholder until the start, then shows the configured value.
  • A second and third message during a Codex start show at once and are delivered in order.
  • Real agent config files were unchanged before and after.

CI: green at 34e5388 (20 pass, 14 skipped).

Follow-up: the lifecycle refactor from the architecture review continues as separate stacked draft PRs: one awaited start per agent, and option state. It does not block this PR.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Closing as superseded: a merged PR already covers this change. #27925 (b3048a2) says it 'Replaces the host-readiness portion of #26561'; #28046 (5319125) accepts messages while any agent starts and lets Stop/close cancel a start at once, for every agent. Files deleted by

(Stale-PR cleanup 2026-10-20, approved by Brennan. Reopen if something here is still missing on main.)

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