# Sweep recovery

The workflow owns one private, bounded (1 MiB), atomically replaced, versioned file per canonical worktree:

```text
<agent-dir>/config/pi-pr/sweep/<worktree-id>/state.json
```

It contains frozen PR authority, original head and exact lease, complete feedback, disposition ledger, owned paths, and mutation attempts. Run `/pr` for fresh route discovery: absent recovery selects `start`; matching valid recovery selects `resume`. Direct skill or tool calls cannot establish route authority.

Resume rechecks worktree, local changes, PR linkage, and remote head under lock, reconciles attempted mutations, then issues a new epoch and run ID. Movement of the same base branch's tip alone does not block initial planning, scoped commits/publication, or recovery: base repository/ref, PR identity, destination, and the exact expected remote head/lease must still match. The frozen feedback/base, ledger, and owned paths remain intact. This does not permit replaying an uncertain mutation. After publication, `refresh` rechecks authority around complete feedback collection and binds the current base; later resolution/finalization cannot inherit a base-drift exception. A base that moves during collection preserves recovery and stops that refresh.

Before publication, `resume` reconciles attempts and records `pendingScope: {head, exactOutsidePaths}` for a clean descendant with committed outside paths. Inspect all commits and the full original-head-to-reviewed-HEAD diff against user intent and recorded scope. All intended work is adopted together with guarded `adopt`; unrelated or unclear work blocks the entire publication. Adoption repeats guard, clean exact HEAD, outside-path set, ancestry, PR identity, and original-lease checks under lock. It changes owned paths only and invalidates validation, preserving ledger, feedback generation, original authority, and mutation history. Pending scope blocks commit/validate/publish. Dirty outside work, unresolved mutations, and published scope remain blocked; never edit recovery or rewrite history.

Unpublished v1/v2 state migrates to v3 with `validation: null`. `validate` runs mandatory `git diff --check` and chosen non-destructive checks against a clean exact HEAD, rechecks authority/HEAD/worktree, and saves `{head, checks}`. `commit` and `adopt` invalidate validation; publication of changed HEADs requires a match. An unchanged original HEAD needs no push or validation. Published legacy state retains its version, saved checks, and mutation obligations. Known check failures retry only the saved check set; unknown checks require explicit safe-repeat confirmation in a later `/pr`. Invocation guards prevent check execution twice on the same HEAD, even across resume. v3 finalization runs no new checks.

The invocation's configured publication/repair limits, frozen checks, executed HEADs, and completed route/entry-head keys persist across helper resumes and continuations. Budget or no-progress stops do not remove recovery. Publication exhaustion still allows published cleanup and readiness/merge; only a later explicit `/pr` or reload resets limits.

A recorded sweep with no pending or uncertain mutation may resume after a manual publication. Read-only discovery verifies unchanged PR/repository/ref linkage, a clean local HEAD equal to the live remote, descent from the original HEAD, and changes confined to owned paths. `resume` repeats those checks under lock and records the observed head as published without pushing, deleting recovery, or discarding the ledger. Continue with `refresh` before resolving; a moved base is rebound there. Dirty, unowned, divergent, or uncertain outcomes still block and preserve recovery.

A post-publish `refresh` retains decisions for identical items, classifies new or edited actionable items as blocked for the next fix cycle, and saves an exact projection. Existing `refresh-pending` recovery can still use `show` and `record` to cover its frozen snapshot. No repeat approval is required. Resuming a recorded plan uses its saved ledger and owned paths, never a reconstructed plan; new sweeps start at the original clean HEAD.

The `commit` action saves its parent HEAD and staged tree before running Git. A lost result blocks further commits and publication until `resume`: an unchanged HEAD permits a fresh commit attempt, while exactly one commit with the saved parent and tree is accepted without replay. A different history or committed tree (including hook changes) preserves recovery and stops for inspection. Older recovery without a commit attempt remains resumable.

A returned reply ID is saved before the verifying fetch; recovery can verify that exact ID and body without replaying the mutation. A lost response without a saved ID remains ambiguous even if a matching comment appears: stop without replaying or resolving. Malformed, oversized, obsolete, wrong-worktree, or route-mismatched recovery is preserved and blocks dispatch. Never repair, move, replace, or delete it automatically; report its path and blocker.
