Skip to content

refactor: give agent startup one readiness owner - #27627

Closed
brennanb2025 wants to merge 4 commits into
brennanb2025/agent-publish-before-handshakefrom
brennanb2025/agent-awaited-start
Closed

brennanb2025 wants to merge 4 commits into
brennanb2025/agent-publish-before-handshakefrom
brennanb2025/agent-awaited-start

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

If you clicked Rewind or changed a Codex goal while the agent was starting, Orca could give up after two minutes and still perform the action later. Retrying an already accepted message after an interrupted rewind could also report that it had not run, inviting a duplicate send. On a running agent, a later message could overtake an earlier rewind or goal change.

Now an action waiting for startup is refused when its host-side two-minute wait expires, and an expired request cannot begin later. Accepted message and /compact retries answer from their recorded acceptance without starting an agent. Rewind and goal changes on a running agent keep their order ahead of later messages and Stop.

What Changed

The host's existing startup owner supplies one readiness promise, settled when that child starts, ends, is replaced, or reaches its startup limit. Requests wait outside the host's ordered work and recheck their deadline and the selected child before acting. A running child performs the action in the same ordered step that selects it.

Ordinary messages remain accepted immediately and wait on the host for delivery. A new send, /compact, or /clear still recovers an interrupted rewind before acceptance. Existing accepted retries use their receipts; an unreadable receipt or unrecoverable replay result stays unknown, without accepting new work or starting an agent. A timed-out caller does not cancel accepted messages or other callers sharing the start.

Removed the separate readiness waiters, retry module, and the flag that made each caller choose whether to queue its work. One function builds known-not-run refusals; expired waits use the existing expiration result instead of claiming that an agent which started failed to restart.

Why

One owner already knows which child is starting and when that start ends. Reusing it removes competing wait paths. Keeping ready actions in one ordered step preserves the user's action order; only a child still starting needs to release that step and wait.

Design choices and planned follow-ups:

  • Intended — Host ownership: startup and accepted messages continue on their execution host through a client disconnect, including SSH chats.
  • Intended — Interrupted rewind recovery: a new message or conversation command settles an earlier interrupted rewind before acceptance; an accepted retry starts nothing.
  • Intended — Starting remains ordered: starting an agent already underway may delay the refusal until it settles, but an expired request never calls the provider afterward.
  • Temporary — Agent startup flow: a planned follow-up will separate starting an agent process from opening its chat, using one host-managed flow. Its tracking link is pending.
  • Temporary — Choices attached to each message: a planned follow-up would tie a queued message to the choices visible when it was sent. Its tracking link is pending; messages currently use the latest accepted choices when delivered.

Linked Issue

Maintainer lifecycle follow-up to #26561; no separate issue.

Visual Proof

Pending coordinator-owned rendered QA on this exact head. This worker used scripted providers and did not run an Electron app or real agent.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated

On macOS, 156 tests across 15 affected suites pass, covering receipt replay across callers, ready rewind/goal ordering, shared readiness, independent waits, replacement, close, Stop, expiry, no late provider call, failed startup, and delivery exactly once. All four new receipt/ordering cases fail on the previous head: retries restart and refuse, the later send overtakes the goal, and rewind refuses as busy. The signed-out integration case verifies that the child started for a message receives it once. No-write-before-readiness checks now run again after existing event flushes or idle-sweep waits.

pnpm tc:node and all 25 required local static checks pass, including all four CI typecheck projects with the pinned Bun 1.4.3 toolchain. Two mutation checks fail as expected: repeating preparation after readiness prevents the signed-out message from being delivered, and restoring the restart-failure result for an expired ready request fails the timeout-copy assertion. Both source files were restored byte for byte, and those two suites pass all 25 tests afterward. The first pushed head exposed a receipt-read error that the new pre-check retried instead of refusing. That regression is fixed: ordinary sends use their existing admission path, and a receipt read error during rewind recovery is logged and answered as unknown. The existing read-error test and its new rewind case both fail without this correction and pass now. Final-head CI passed: all five full unit-test shards, both package builds, static analysis, cross-version compatibility and relay integration succeeded. Verification also passed. The PR watch encountered intermittent TLS timeouts; the run-level watch confirmed that the final workflow completed successfully.

AI Disclosure

AI coding agents (Codex and Claude Code)

Review

Production is +518/-374 = +144 net lines across 14 main-process files against #26561; tests are excluded. The receipt check and one-step action execution repair the two round-2 findings while retaining the smaller readiness design. This remains above the earlier net-negative target. Renderer and shared production source are unchanged.

Agent skill upstream boundary

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

Notes

No new wire fields, stream operation, persisted state, or platform-specific behavior. Folder workspaces, remote hosts, and older peers retain the existing protocol; loss of contact does not prove exit. The two-minute request budget starts on the host, so it does not eliminate the small client/host timeout offset over a remote connection. Changing when queued messages retain execution choices remains outside this PR.

Checklist

  • Explained the problem, user-facing change, mechanism and approach
  • Before/after visual proof attached
  • Self-reviewed source and regression evidence; rendered QA remains pending
  • Cross-platform, SSH, folder and older-peer compatibility considered
  • Required final static checks and CI complete
Files Added Deleted Net
Test 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​443 $\color{#cf222e}{\Huge{\mathbf{−}}}$​132 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​311
Prod 15 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​519 $\color{#cf222e}{\Huge{\mathbf{−}}}$​374 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​145

@brennanb2025
brennanb2025 force-pushed the brennanb2025/agent-awaited-start branch from 668037f to 8fcfb4e Compare October 12, 2026 00:05
@brennanb2025 brennanb2025 changed the title Share one agent startup result without blocking chat actions refactor: give agent startup one readiness owner Oct 12, 2026
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Closing as superseded: a merged PR already covers this change. Merged #27925 (b3048a2) says it 'folds in #27627', and #28046 (5319125) extended it. 57% of the PR's added production lines are already verbatim on main, and 3 of its files were deleted by those

(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