Skip to content

fix(orchestration): stop retried failed worker starts from piling up live agents - #27795

Merged
brennanb2025 merged 7 commits into
mainfrom
brennanb2025/perf-failed-start-retry
Oct 13, 2026
Merged

brennanb2025 merged 7 commits into
mainfrom
brennanb2025/perf-failed-start-retry

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1390 $\color{#cf222e}{\Huge{\mathbf{−}}}$​10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1380
Prod 29 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​568 $\color{#cf222e}{\Huge{\mathbf{−}}}$​93 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​475

ELI5

When a supervised worker agent got stuck at a startup prompt, its coordinator could retry the start again and again. Each retry launched a brand-new agent, and every stuck one before it stayed alive. Nothing ever stopped the loop, so live agents piled up until Orca's main process ran out of memory and macOS killed it. Now a retry cleans up the stuck attempt it replaces, and after three failed starts Orca refuses to retry and tells the coordinator to report the failure instead.

What you see, before and after

"You" is the person watching Orca. "The coordinator" is the agent that starts workers and retries them.

A worker starts normally. Nothing changes for either of you. One terminal opens with the worker, and the coordinator gets the same result as before.

A worker gets stuck at a startup prompt and the coordinator retries until one works.

Before After
You Every retry opens one more terminal, and every earlier one stays open, still stuck at the prompt. When an attempt finally works, the stuck ones are still there next to it. When a retry starts, the stuck terminal it replaces closes. You see at most one stuck terminal at a time, then the working one. If you typed into a stuck terminal (for example to answer the prompt yourself), it stays open.
The coordinator Gets Agent startup blocked: … for each failed attempt. It can still read each old attempt's output with worker-read. Same error for each failed attempt. It can still read the closed attempt's output with worker-read, because the output is saved before the terminal closes.

A worker never gets past the prompt and the coordinator keeps retrying.

Before After
You Stuck agents pile up, one per retry, with no limit (44 in 22 minutes in the report). Orca's memory climbs until macOS kills it. Relaunching gets stuck again. After the third failed start, Orca stops starting new agents for that task, and the coordinator is told to stop and report the failure to you. The last stuck terminal stays open so you can look at it or answer the prompt yourself.
The coordinator Every retry is accepted, so nothing ever tells it to stop. Its fourth retry is refused with Task <id> failed 3 times, so Orca will not retry it again (last error: …). Report the failure to the user instead of retrying. The refusal also tells it not to start a replacement task, to read the last attempt's output with worker-read, and that the last terminal stays open for you until worker-release.

What Changed

What users saw (STA-7113): a Codex worker stopped at an interactive startup prompt, so its start failed with Agent startup blocked: codex-interactive-prompt. The coordinator kept retrying it (44 times in 22 minutes in the report). Each retry opened another terminal with another agent stuck at the same prompt. Orca's main-process memory climbed until macOS killed the app, and every relaunch wedged again.

Why it happened: two gaps met.

  1. A failed start keeps its terminal, on purpose. Since fix(orchestration): own a worker terminal from creation, not after the boot wait #19608, a worker's terminal belongs to the worker from the moment it is created. That way, if the user types into the booting pane to answer the prompt themselves, the pane is theirs and Orca never closes it under them. Cleanup of a failed start is left to worker-release. But a retry (worker-start --retry-of) never called it, so every retry stranded one more live agent.
  2. The circuit breaker never counted failed starts. Orchestration already documents "after three consecutive failures for one Task, its dispatch circuit-breaks and the Task is failed". But a failed worker-start never added to the failure count, and every retry started counting again at 0. The breaker could never trip, so a retry loop had no end.

After this change:

  • Retry releases the attempt it replaces. When worker-start --retry-of <failed dispatch> is accepted, and that failed worker still owns its terminal, Orca releases it through the same path worker-release uses. This also covers a worker that ran and reported its own failure: the retry replaces it the same way. That terminal is one the user hasn't typed into, that isn't a chat-style worker session, and that the retry isn't reusing with --terminal. Its output is archived first, so worker-read still shows what the stuck agent printed. A pane the user typed into stays theirs. If Orca restarts mid-release, the existing startup recovery finishes it. The retry never waits on this cleanup and never fails because of it.

  • Failed starts count toward the breaker. A failed start adds one to its dispatch's failure count, and a --retry-of start inherits the count of the attempt it retries. At the third failure the dispatch is marked circuit-broken, and a fourth --retry-of is refused with a plain error: Task <id> failed 3 times, so Orca will not retry it again (last error: …). Report the failure to the user instead of retrying. The refusal also gives the coordinator its next steps:

    • stop retrying;
    • read the last attempt's output with worker-read;
    • its terminal, if still open, stays for the user until worker-release.

    An older client ignores the new failureCount field.

  • The breaker's existing rules are unchanged.

    • A worker that starts and then reports its own failed result does not count.
    • A plain new start (not --retry-of) still begins at 0, so a worker that exits and is started again behaves exactly as before.
    • A successful worker completes the Task, which ends retries.
    • task-update can still reopen a Task by hand.
  • The orchestration guide (recovery-and-cleanup.md, plus its generated bundled copy) now says that failed starts count, and that a retry releases the failed attempt's terminal.

Mechanism, by file:

  • retried-worker-terminal-release.ts (new): the release-on-retry step. It is called from local-worker-start.ts and from the home side of federated-worker-start.ts, because a remote retry can replace a failed local attempt.
  • dispatch-row-writer.ts and worker-dispatch-start.ts stamp the carried count on a retry's row and refuse a retry of a circuit-broken dispatch. worker-dispatch-outcome.ts (failWorkerStart) counts the failure. orchestration-dispatch-refusal-contract.ts and task-dispatch-refusal.ts hold the refusal's data and next steps.
  • failed-start-dispatch-identity.ts also matches a circuit-broken dispatch. Without that, the third failed start's terminal could not be released.
  • worker-report-settlement.ts and lifecycle-transition.ts keep the [Bug]: agent_prompt_stalled for codex/kimi workers — fixed 5s confirmation window vs ~20s first hook-event latency (root-cause evidence) #16095 correction working: a worker whose start was recorded as failed because its first prompt looked stalled can still report its real outcome, even if that failure tripped the breaker. A repeated failed report on a circuit-broken dispatch is treated as a duplicate.

Why

The terminal-ownership design from #19608 is kept on purpose, so a user who answers the stuck prompt by hand keeps their pane. This PR does not close terminals when a start fails. It closes the old one only when the coordinator explicitly replaces it with a retry, through the normal release path. That path already handles archiving, user takeover and restart recovery. Alternatives considered:

  • Close the terminal inside the failed start: rejected, because it reverses fix(orchestration): own a worker terminal from creation, not after the boot wait #19608 and closes panes the user may be typing into.
  • A time limit that reaps failed starts: rejected. Release would hang on timing rather than on an explicit decision, and the guide already says never to release because of a timeout.
  • Counting only consecutive start failures with a separate counter: rejected. The breaker already exists and is documented, and adding a second counter would duplicate state.
  • Carrying the Task's highest count into every new start: tried in review and rejected. Three worker exits across separate starts, including a user closing the pane, would then have silently failed the Task, which is a behaviour change beyond this bug.

Linked Issue

Linear: STA-7113. This fixes the retry pile-up the ticket describes. The ticket also reports Orca growing to 17 GB after a restart with no retry loop running; this PR does not explain or fix that part.

Visual Proof

chart.png

Method:

  • Hidden production build of main (BEFORE, 9d305f3ce4f) and of this branch (AFTER, built at e7f8df61583; the two later commits only change the refusal's next-step text and add a log line, not what is released or counted), each in an isolated profile on one macOS laptop. This is a count and memory measurement, so it ran without the timing machine.
  • codex was a stand-in that paints a Codex startup permission dialog and sits at it. Orca's own detector reported the ticket's failure: Agent startup blocked: agent-interactive-prompt. Terminal workers, as in the ticket.
  • A coordinator terminal ran worker-start --agent codex, then retried with --retry-of until 10 attempts. Every CLI call was proven to target the rig, not the real app.
  • Runs were interleaved B, A, B, A, B, A (n=3 each).
After 10 attempts (n=3 each) BEFORE median (range) AFTER median (range)
Stuck agent processes still alive 10 (10–10) 1 (1–1)
Live terminals in the app (incl. coordinator + 1 default) 12 (12–12) 3 (3–3)
Attempts that launched an agent 10 3 (4–10 refused)
Main-process JS heap growth after GC +5.1 MB (5.0–5.3) +3.7 MB (3.5–3.8)
Rig process-tree memory (resident) 1026 MB (823–1324) 663 MB (649–770)

Resident memory on macOS swings by hundreds of MB between samples because of memory compression, so read the process and terminal counts as the result. A first series at the round-1 commit gave identical counts. Raw data and scripts: kept locally under perf-lanes/easy/measure/failed-start-retry/ (not committed).

Testing

  • New failed-start-circuit-breaker.test.ts, at the database level: the count carries across retries, the breaker trips on the third failed start and refuses a fourth with the message above, a worker's own failed report is not counted, and the stalled-prompt correction still works after the breaker tripped.

  • New failed-start-retry-release.test.ts, through the real worker-start and worker-release handlers:

    • a retry releases the failed attempt's terminal and archives its output;
    • a pane the user typed into is kept;
    • an already-released terminal is left alone;
    • a retry that reuses a terminal with --terminal leaves it alone;
    • a structured worker is left to its own teardown;
    • a retry loop stops at the third failed start.
  • Existing orchestration suites, run locally: worker start and release, federation, dispatch lifecycle and settlement (95 + 19 files) all pass. tsc node and cli typechecks pass.

  • Live measurement in a hidden production build (macOS): see Visual Proof.

  • Review: two adversarial review rounds plus an architecture review; findings and what was deferred are in the review comment.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • SSH and remote hosts: a local retry runs the release on the host that owns the terminal, through the normal release path, which already handles SSH-hosted terminals. A failed start on a remote orchestration server does not record terminal ownership on either side, so worker-release cannot close it today and neither can this. That gap predates this PR and is left out of scope. The breaker still counts remote failed starts, because the home side records them. Nothing new crosses the wire: no new fields, methods or opcodes.
  • Folder workspaces: no difference; terminal ownership does not depend on git.
  • Windows and Linux: no platform-specific code.
  • App restart in the middle of a release: the release intent is saved before anything closes, and the existing startup recovery finishes it. The intent is written just after the retry is accepted, not in the same transaction; a crash in between leaves the old terminal listed as reclaimable, exactly as before this PR.
  • Known limits (deferred):
    • A coordinator that creates a brand-new Task (--spec) for every attempt is not bounded by the breaker.
    • Setup terminals and new child worktrees made by failed attempts are not released.
    • On remote orchestration servers, argument errors (for example a wrong remote worktree) also count as failed starts; task-update can reopen the Task.
    • After two failed starts in a chain, a user closing the third (running) worker's pane counts as its third failure, because a deliberate close already counts as a failure today.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

…live agents

A failed worker-start keeps the terminal it created (a pane the user typed
into is theirs), so a coordinator retrying a start that can never succeed
left one more live agent behind on every retry, with nothing to stop it.

- A --retry-of start now releases the failed attempt's still-owned terminal
  through the normal worker-release path (output archived, user takeover
  kept, recovery finishes it after a restart).
- A failed start now counts toward the Task's existing three-failure circuit
  breaker, carried across retries; a retry of a circuit-broken Dispatch is
  refused with a plain error.

Linear: STA-7113
…lain breaker refusal

- Only a --retry-of start inherits its predecessor's failure count, so worker
  exits across separate starts keep the old behaviour.
- The circuit-broken refusal carries failureCount and next steps that say to
  stop retrying, read the last attempt, and that its pane stays open.
- A repeated failed report on a circuit-broken Dispatch is a duplicate.

Linear: STA-7113
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review summary

The problem (STA-7113). A supervised Codex worker stopped at an interactive startup prompt, so worker-start failed with Agent startup blocked: codex-interactive-prompt. The coordinator kept retrying with --retry-of. Every retry launched a new agent in a new terminal, while every earlier stuck agent stayed alive. That is on purpose since #19608: a failed start keeps its pane so a user typing into it keeps it, and worker-release is the cleanup. But nothing released it on retry. The documented three-failure circuit breaker never counted failed starts either, so the loop had no end, and the report shows Orca's main memory climbing until macOS killed it.

What changes for users. Retrying a failed worker now closes the stuck attempt it replaces, through the normal release path: output archived, and a pane the user typed into is kept. After three failed starts in a retry chain, Orca refuses the next retry and tells the coordinator plainly to stop and report the failure. Measured in a hidden production build over 10 retry attempts (n=3 each): 10 stuck agents still alive before, 1 after; 12 live terminals before, 3 after.

Review. Two adversarial correctness rounds, one architecture review (verdict: keep the design), and the readiness checklist (no P0/P1).

Fixed during review:

  • Round 1 carried the Task's highest failure count into every new start. That would have let three ordinary worker exits, including a user closing the pane, silently fail a Task. Now only a --retry-of start inherits the count, and plain starts behave exactly as before.
  • The breaker refusal's next steps used to say "fix --retry-of". They now say: stop retrying, read the last attempt's output, and its pane (if still open) stays for the user. This is carried in a new optional failureCount field that older clients ignore.
  • A repeated failed report on a circuit-broken dispatch is now a duplicate, not a rejection.
  • A release on retry that can't prove the old terminal closed is now logged instead of silently dropped, and the helper's database reads are inside its error guard.

Deferred, each narrow and noted in the PR body:

  • A coordinator that creates a new Task per attempt is not bounded.
  • Setup terminals and child worktrees from failed attempts are not released.
  • Argument errors on a remote orchestration server count as failed starts.
  • After two failed starts, a user closing the third (running) worker's pane counts as its third failure, because closes already count today.
  • The release intent is written just after the retry commits, not inside the same transaction.
  • A remote host's failed start has no terminal ownership record, so neither worker-release nor this change can close it. That gap predates this PR.

Kept by decision: a retry also releases a worker that ran and reported its own failure. The retry replaces it the same way; output is archived, and a pane the user typed into is kept.

Verified:

  • New database and RPC tests.
  • Existing orchestration suites (104 files / 1026 tests, run locally).
  • tsc node, cli and web.
  • The repo's lint and code-quality checks.
  • The BEFORE/AFTER hidden-rig series above, with every CLI call proven to target the rig.

Not verified:

  • SSH-hosted worker terminals and remote orchestration servers were not exercised live; they go through the unchanged release path.
  • Windows and Linux were not run (no platform-specific code).
  • Whether the ticket's loop was exactly this --retry-of shape is inferred, not proven.
  • The ticket's separate 17 GB growth after a restart with no loop is not addressed.
  • The measured AFTER build predates the last two commits (refusal wording and logging only; no change to what gets released or counted).

@brennanb2025
brennanb2025 marked this pull request as ready for review October 12, 2026 06:48
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

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: 2e98a8b9-19e8-41ca-af51-46a150d272d5
📥 Commits

Reviewing files that changed from the base of the PR and between 99b9c22 and f691e6e.

📒 Files selected for processing (24)
  • config/scripts/vitest-sqlite-database-runtime-files.mjs
  • src/main/daemon/headless-emulator.ts
  • src/main/daemon/headless-terminal-rows.ts
  • src/main/runtime/orca-runtime-capture-provider-terminal-buffer.ts
  • src/main/runtime/orca-runtime-core.ts
  • src/main/runtime/orca-runtime-resolve-terminal-pane.ts
  • src/main/runtime/orca-runtime-terminal-projection.ts
  • src/main/runtime/orchestration/worker-output-archive.test.ts
  • src/main/runtime/orchestration/worker-output-archive.ts
  • src/main/runtime/orchestration/worker-terminal-archive-read.ts
  • src/main/runtime/orchestration/worker-terminal-redaction.test.ts
  • src/main/runtime/orchestration/worker-terminal-redaction.ts
  • src/main/runtime/orchestration/worker-transcript-payload.ts
  • src/main/runtime/rpc/methods/orchestration/worker/worker-output.test.ts
  • src/main/runtime/rpc/methods/orchestration/worker/worker-output.ts
  • src/main/runtime/runtime-terminal-state-records.ts
  • src/main/runtime/terminal-projection.test.ts
  • src/main/runtime/terminal-screen-row-metadata.test.ts
  • src/main/runtime/terminal-tail-read.ts
  • src/main/runtime/worker-terminal-archive-release.test.ts
  • src/main/runtime/worker-terminal-archive-screen.test.ts
  • src/main/runtime/worker-terminal-archive.test-support.ts
  • src/main/runtime/worker-terminal-wrap-provenance.test.ts
  • src/shared/runtime-terminal-contracts.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.

📝 Walkthrough

Worker-start failures now accumulate across retries and circuit-break a dispatch at the configured threshold. Circuit-broken retries are refused with failure details, while eligible worker reports can still settle. Local and federated retry flows request release of eligible terminals owned by failed workers. Terminal reads also carry row-wrap metadata used for capability redaction and archive capture.

Priority: ⬆️ High

Merge Risk: ⚪ Minimal · up to f691e

No actionable issue is established that would prevent merging after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 45 functions across 38 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
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.
Title check Passed The title clearly identifies the main change: preventing repeated failed worker-start retries from leaving live agents behind.
Description check Passed The description is comprehensive. It covers the user impact, implementation, rationale, linked issue, visual proof, testing, limitations, platform considerations, and checklist. The full pnpm command …
  • Fix all pre-merge checks with AI
✨ 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.

@brennanb2025

brennanb2025 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

A worker blocked at startup could be retried repeatedly, leaving each replaced agent and pane running because failed starts did not reach the three-failure limit. Linked retries now release the prior owned pane through normal cleanup, stop after three failures, and leave the last pane available. A pane the user has taken over or explicitly selected for reuse stays open; cleanup errors are reported without blocking the next start. Separate starts begin with a fresh count.

Review also found that closing the pane could lose the actual failure reason because its archive contained only blank or command-only streamed output. The shared capture now retains history and the current terminal screen before closing. Masking uses the host's actual wrap information so wrapped token patterns are covered while independent failure messages and draft lines remain readable. Recovery instructions and late failure reports were also corrected. Six review rounds converged on this design at f691e6e539276a90050ef96b04482a74008c0b3d.

Verified: 296 targeted tests across 23 files, Node typecheck, all 24 repository static checks, and exact-head CI: 31 successful checks, 14 skipped, no failures or pending jobs. Six review rounds and readiness were already complete; final hidden M4Air Playwright QA now passes on f691e6e. Review complete; this PR is ready. The first two replaced panes exited and their complete stored archive and post-close read both retained the permission dialog; the third failure reached the limit and the fourth request was refused without adding a pane. User takeover and explicit terminal reuse preserved the original live pane. No source changes or merge were performed during final QA.

The matched comparison used the exact integrated main snapshot c77bebfb, rebuilt in the same remote checkout, with identical harmless setup/default tabs and a synthetic startup permission prompt. Main retained four failed workers and seven terminals after four requests; the PR retained one worker and four terminals, including three initial fixture panes. Setup completed on both, and inspected whole-window screenshots show the same initial tab order and permission dialog, with four worker tabs on main versus one on the PR. The same existing Codex settings notice appears in both. All windows stayed hidden and unfocused. This controlled fixture replaces real agent commands and user setup scripts; it is a development-runtime checkout on macOS arm64, not packaged-release or real-agent validation.

Main-process resident memory was also checked on M4Air in this single matched pair:

Revision At launch, MiB After four requests, MiB
Integrated main c77bebfb 338.0 363.4
PR f691e6e 336.2 361.3

The PR ended 2.1 MiB lower in this pair. The original-host three pairs below still show the PR higher by 14.4, 144.9, and 21.7 MiB. These variable, short synthetic measurements do not establish a main-process memory improvement or identify the cause of the earlier increase.

Re-ran the original ten-request measurement on the original host, three runs per build. Values below are median final values (range), and supersede the earlier PR measurements.

Metric Original baseline 9d305f3 Final f691e6e
Retained synthetic agents 10 (10–10) 1 (1–1)
Live terminals, including two initial panes 12 (12–12) 3 (3–3)
Main heap after garbage collection, MiB 41.519 (41.514–41.528) 40.072 (40.066–40.076)
Whole app process-tree resident memory, MiB 1270.766 (1022.406–1341.906) 920.875 (893.703–923.906)
Main-process resident memory, MiB 316.188 (204.891–336.359) 349.781 (337.891–350.766)

Every final-version run started three workers and refused the next seven requests without adding another pane. Main-process resident memory was higher after in every pair, with wide variation before; this does not establish an improvement or identify the cause of that difference. An interrupted partial run was excluded after Orca restarted; the completed first baseline run was preserved and the missing final-version run resumed. These are development-runtime built checkouts with a synthetic startup prompt, reconstructed baseline source, current toolchain and the integrated main changes, not packaged-release or real-agent measurements.

Deferred limits: an old stopped retry ID can give misleading recovery instructions after a manual reopen (the latest failed attempt works); remote failed-start cleanup, configuration errors counting toward the limit, and the small crash window before cleanup is requested remain. Deliberately closing the third pane after two failures can still count as a failure. Older hosts without wrap information retain complete-line masking and disclose its coverage limit; separate hard-line fragments are outside that masking promise. Live Windows/Linux/WSL/SSH/folder and mixed-version failure scenarios, aggregate archive load and separate memory growth after restart remain unverified.

Final-head visual proof (M4Air, hidden Playwright capture):

Before retry:

First failed pane before retry

Main after four failed starts:

Integrated main retains four worker tabs

PR after three failures and the fourth request refused:

PR retains the final worker tab

Takeover keeps the original pane beside the new attempt:

Original user-owned pane remains selected

Explicit terminal reuse keeps a single worker pane:

Explicit reuse preserves the existing worker pane

@brennanb2025
brennanb2025 merged commit b70f13f into main Oct 13, 2026
45 checks passed
@brennanb2025
brennanb2025 deleted the brennanb2025/perf-failed-start-retry branch October 13, 2026 22:20
@nwparker nwparker mentioned this pull request Oct 14, 2026
6 tasks done
hiphapis added a commit to hiphapis/orca that referenced this pull request Oct 15, 2026
Only src/cli/bundled-skill-guides.ts conflicted; it is generated, so it was
regenerated rather than hand-resolved. Upstream's guidance changes land around
this branch's edits without touching them: the circuit-breaker and retry-release
paragraphs in references/recovery-and-cleanup.md (stablyai#27795), and the orca-cli
launch-flag note in the kernel's role table (stablyai#27794, stablyai#27796).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011nnNsG3p4Do9eiyfXGr2rB
brennanb2025 added a commit that referenced this pull request Oct 15, 2026
…live agents (#27795)

* fix(orchestration): stop retried failed worker starts from piling up live agents

A failed worker-start keeps the terminal it created (a pane the user typed
into is theirs), so a coordinator retrying a start that can never succeed
left one more live agent behind on every retry, with nothing to stop it.

- A --retry-of start now releases the failed attempt's still-owned terminal
  through the normal worker-release path (output archived, user takeover
  kept, recovery finishes it after a restart).
- A failed start now counts toward the Task's existing three-failure circuit
  breaker, carried across retries; a retry of a circuit-broken Dispatch is
  refused with a plain error.

Linear: STA-7113

* test(orchestration): type the failed-start retry fixtures without casts

* fix(orchestration): carry failed-start count only along --retry-of; plain breaker refusal

- Only a --retry-of start inherits its predecessor's failure count, so worker
  exits across separate starts keep the old behaviour.
- The circuit-broken refusal carries failureCount and next steps that say to
  stop retrying, read the last attempt, and that its pane stays open.
- A repeated failed report on a circuit-broken Dispatch is a duplicate.

Linear: STA-7113

* fix(orchestration): breaker refusal only points at a terminal that is still open

Linear: STA-7113

* fix(orchestration): log a retry's release that could not prove the old terminal closed

Linear: STA-7113

* Preserve worker diagnostics before terminal release and mask wrapped tokens

(cherry picked from commit b70f13f)

Backport to 1.4.224: kept both sides of the sqlite vitest file list (1.4.224 ssh tests + the new archive tests); applied the recovery-and-cleanup.md text change to 1.4.224's generated ORCHESTRATION_FULL_MARKDOWN constant instead of taking main's regenerated copy.
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