Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config/scripts/orchestration-skill-guidance.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ describe('orchestration kernel', () => {
'`worker-list --run <run_id> --terminal-state reclaimable --json`'
)
expect(squash(kernel)).toContain('do not follow it with `task-update --status completed`')
expect(squash(kernel)).toContain(
'If `worker-start` recorded `created_child`, capture `<worktreePath>` from that start receipt **before** `worker-release`'
)
})

it('treats long waits and release uncertainty as safe checkpoints', () => {
Expand Down Expand Up @@ -403,6 +406,13 @@ describe('owned orchestration references', () => {
expect(reference).toContain('worker-release --dispatch')
expect(squash(reference)).toContain('`release_pending` or `release_unknown`')
expect(squash(reference)).toContain('Never substitute `terminal close`')
expect(reference).toContain('ORCA worktree rm --force --worktree path:<worktreePath> --json')
expect(squash(reference)).toContain('Capture `<worktreePath>` **before** `worker-release`')
expect(squash(reference)).toContain('`worker-show` returns `terminal: null`')
expect(squash(reference)).toContain('`terminal.worktreePath` is not a path source')
expect(squash(reference)).toContain(
'Unpushed local commits exist for **any** outcome (succeeded, failed, or STOP)'
)
})

it('owns the lost-response question and the request-show verdicts', () => {
Expand Down
8 changes: 6 additions & 2 deletions skill-guides/orchestration.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ After an accepted success or failure report, immediately do exactly one:

Release is post-settlement cleanup, not cancellation. Only an accepted
settlement authorizes it; no other observation does. If release is uncertain,
follow its exact recovery receipt and never substitute `terminal close`.
follow its exact recovery receipt and never substitute `terminal close`. If
`worker-start` recorded `created_child`, capture `<worktreePath>` from that
start receipt **before** `worker-release`. After a confirmed released state,
load `references/recovery-and-cleanup.md` and remove the leftover child unless
fail-closed.

A valid `worker_done` settles the Task and Dispatch automatically; do not follow
it with `task-update --status completed`. Enumerate the terminals still owing a
Expand All @@ -189,7 +193,7 @@ older CLI rejects `--full`, keep this kernel's safety floor, use that command's
| You are a dispatched worker and the live preamble does not answer your question, or `check` returned an error | `references/worker-contract.md` |
| New worktree, exact workspace, SSH, WSL, or connected-server placement | `references/placement-and-remote.md` |
| Inbox replay, follow-up messages, group addresses, or decision gates | `references/messaging-and-gates.md` |
| Failed/stopped/unknown attempts, retry, stop, abandon, retain, or uncertain release | `references/recovery-and-cleanup.md` |
| Failed/stopped/unknown attempts, retry, stop, abandon, retain, uncertain release, or leftover `created_child` | `references/recovery-and-cleanup.md` |
| Custom argv or terminal topology that `worker-start` cannot express | `references/low-level-topology.md` |
| Any legacy label, adopted Run, compatibility receipt, or takeover | `references/legacy-contract-migration.md` |

Expand Down
45 changes: 44 additions & 1 deletion skill-guides/orchestration/references/recovery-and-cleanup.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Recovery and cleanup

Load this reference only after a failed/stopped/unknown attempt, explicit retry
decision, stop/abandon request, retention request, or uncertain release.
decision, stop/abandon request, retention request, uncertain release, or a
confirmed `worker-release` of a leftover `created_child` worktree.

| Proven state | Safe action |
| ----------------------- | ------------------------------------------------------------------ |
Expand Down Expand Up @@ -155,5 +156,47 @@ escalation, or stale/rejected completion. If the receipt says `release_pending`
or `release_unknown`, follow its exact recovery action. Never substitute
`terminal close`.

## Worktree cleanup after release

`worker-release` closes the agent terminal only. A `--worktree new-child`
checkout stays on disk. Remove it only after `worker-release` returns a
confirmed released state, and only when that Dispatch's own `effects`
recorded `{ "kind": "worktree", "action": "created_child" }`.

Capture `<worktreePath>` **before** `worker-release` from the `worker-start`
receipt: the path after `::` in `effects[].id`, or `residualResources` of kind
`worktree`. After release, `worker-show` returns `terminal: null` because
`observation.exact` fails once the process incarnation no longer matches, so
`terminal.worktreePath` is not a path source.

```text
ORCA worktree rm --force --worktree path:<worktreePath> --json
```

`--force` maps to `git worktree remove --force` and waives PTY-stop proof; it
is not permission to delete while terminal-stop state is unverified. It does
not force-delete the GitHub branch.

Leave the worktree in place and report it instead when any of the following
hold:

- `worker-release` did not complete successfully (`release_pending`,
`release_unknown`, retained, or error).
- The worker was reused for a follow-up Dispatch.
- The user asked to keep the workspace, or the Dispatch recorded
`worker-retain`.
- The terminal was user-taken-over.
- The recorded start effect was `reused`, or the worker started with
`--worktree current` or an exact pre-existing workspace — never delete a
checkout this Dispatch did not create.
- Unpushed local commits exist for **any** outcome (succeeded, failed, or
STOP): dirty `git status --porcelain`, a nonzero
`git rev-list --count @{upstream}..HEAD`, or no upstream / unknown
comparison.
- `worktree rm` itself errors — a locked worktree or unverifiable Git state.

Run this before the next wait or the end of the turn. It is coordinator
hygiene on top of release, not a substitute for it.

`orchestration reset` is destructive recovery. Do not run it during active
coordination unless the user explicitly abandons that state.
Loading