How Branch Sync Handles Custody Recovery for Terminal Runs with Unpublished Pipeline Commits
When a run terminates in a terminal state without publishing its pipeline-generated commits, the branch sync subsystem locks the branch in custody and offers a guarded recover_custody action that fast-forwards the branch to the preserved pipeline head while recording the recovery in the database.
In the kunchenguid/no-mistakes repository, pipeline runs that end terminally can leave unpublished commits stranded in the local gate. The branch sync custody recovery mechanism ensures these commits are never lost by preserving the pipeline state and providing a safe path to return branch control to the operator.
Understanding Terminal Runs and the Custody State
When a run enters a terminal state—such as failed or cancelled—without publishing its pipeline-generated commits, those commits remain preserved in the local gate. The system marks the branch as being in custody of the run, blocking further local operations that could accidentally discard the unpublished work.
This custody state prevents data loss by freezing the branch until the operator explicitly recovers the unpublished commits or acknowledges the terminal state.
State Detection in internal/branchsync/sync.go
The detection logic resides in internal/branchsync/sync.go. The system defines the StateCustodyReturned constant and monitors run status to identify when custody recovery is required.
When the code detects run.Status.IsTerminal() && !run.HasPublishedPipelineCommits(), it triggers the custody state by setting:
state.NextAction = &NextAction{
Code: "recover_custody",
Command: "no-mistakes axi sync --recover",
}
state.Safety = "custody_returned"
This assignment occurs at lines 41-45 in the sync implementation, ensuring the state machine transitions correctly when unpublished work remains in the gate.
The Recovery Workflow
CLI User Guidance
The CLI surfaces this state to users through internal/cli/sync.go. When custody is detected, the interface prints a specific instruction:
Run ended without publishing its pipeline commits; recover custody with `no-mistakes sync --recover`
This prompt appears at lines 262-266, ensuring operators know exactly which command to execute next.
Executing the Recover Command
Running no-mistakes axi sync --recover invokes the Recover function in internal/branchsync/sync.go. This function performs several critical operations:
- Validates worktree cleanliness (or accepts
--keep-localto preserve the current head) - Fast-forwards the branch to the preserved pipeline head
- Writes the custody timestamp to
custody_returned_atin the run record viainternal/db/run.go(lines 244-251) - Returns branch ownership to the operator for fresh runs
Safety Checks and Abort Conditions
The recovery path includes rigorous validation in internal/branchsync/sync.go (lines 512-578). It aborts with specific error codes if assumptions are violated:
blocked_recover_dirty: The local branch contains uncommitted changesblocked_recover_assumptions_changed: The preserved commits have changed since the run terminated- Gate branch modification: The gate branch was altered during the recovery attempt
Each condition generates a clear blocked plan explaining why recovery cannot proceed, preventing accidental data loss.
Database Persistence and Agent Guidance
Upon successful recovery, the system updates the database through internal/db/run.go, persisting the custody_returned_at timestamp to the run record. The state.Safety field is set to "custody_returned", and the CLI reports: "custody returned; the branch is yours – start a fresh run when ready" (lines 266-270 in internal/cli/sync.go).
Additionally, internal/skill/skill.go (lines 225-291) embeds this recovery flow into agent guidance text, ensuring automated systems recommend no-mistakes axi sync --recover when detecting terminal runs with unpublished commits.
Practical Usage Examples
To recover from a terminal run with unpublished commits:
# Run ends terminally; system hints at recovery
$ no-mistakes axi run --intent "fix bug"
# CLI output:
# Run ended without publishing its pipeline commits; recover custody with `no-mistakes sync --recover`
# Recover custody and fast-forward to preserved head
$ no-mistakes axi sync --recover
# → custody returned; the branch is yours – start a fresh run when ready
To keep the current local head without moving it:
$ no-mistakes axi sync --recover --keep-local
Summary
- Terminal runs with unpublished pipeline commits trigger a custody state that preserves commits in the local gate and prevents local operations
- The branch sync subsystem detects this via
StateCustodyReturnedininternal/branchsync/sync.goand offers arecover_custodyaction - Recovery requires a clean worktree (or the
--keep-localflag) and fast-forwards the branch to the preserved pipeline head - The system records recovery via the
custody_returned_attimestamp ininternal/db/run.go - Multiple safety checks prevent data loss, with specific error codes like
blocked_recover_dirtyfor blocked recovery scenarios
Frequently Asked Questions
What happens to unpublished commits when a run fails or is cancelled?
When a run terminates in a terminal state without publishing its pipeline-generated commits, those commits remain preserved in the local gate. According to the source code in internal/branchsync/sync.go, the branch enters a custody state that prevents local operations from overwriting the unpublished work until custody is explicitly recovered via the Recover function.
How do I know if a branch is in custody and needs recovery?
The CLI displays a specific message generated in internal/cli/sync.go (lines 262-266): "Run ended without publishing its pipeline commits; recover custody with no-mistakes sync --recover". This appears when the state machine detects StateCustodyReturned and sets NextAction to recover_custody with the command no-mistakes axi sync --recover.
Can I recover custody if I have local uncommitted changes?
No, the recovery aborts with error code blocked_recover_dirty unless you use the --keep-local flag. The Recover function in internal/branchsync/sync.go validates worktree cleanliness at lines 512-578 before allowing the fast-forward to the preserved pipeline head, ensuring you do not accidentally lose local work.
Where does the system record that custody has been returned?
The Recover function writes to the custody_returned_at field in the run record via internal/db/run.go (lines 244-251). This timestamp confirms the branch has been returned to the operator and is safe for fresh runs, while the CLI sets state.Safety to "custody_returned" to reflect the completed recovery.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →