Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ff4af29
fix(branchsync): settle wedged custody records via --keep-local
hmcdaniel03 Aug 28, 2026
ced6c28
fix(branchsync): close settlement edge cases found in review
hmcdaniel03 Aug 28, 2026
abc623e
no-mistakes(review): fail-close keep-local settlement advertisement; …
hmcdaniel03 Aug 28, 2026
6d9d16a
fix(branchsync): fail-close settlement advertisement and scope abort …
hmcdaniel03 Aug 28, 2026
b1a9a22
no-mistakes(review): fail-close settlement advertisement on unreadabl…
hmcdaniel03 Aug 28, 2026
3db517c
no-mistakes(review): close settlement dead end after lost gate compar…
hmcdaniel03 Aug 28, 2026
684a4aa
no-mistakes(review): name an exit on every keep-local recovery refusal
hmcdaniel03 Aug 28, 2026
e59c7c1
no-mistakes(review): name a completable exit on every recovery refusal
hmcdaniel03 Aug 28, 2026
7867fc2
no-mistakes(review): narrow refusal-exit claims and name conflicting …
hmcdaniel03 Aug 28, 2026
39fc187
no-mistakes(review): correct settlement guidance and name stranded an…
hmcdaniel03 Aug 28, 2026
7a4be00
no-mistakes(review): scope stranded-anchor guidance and custody abort…
hmcdaniel03 Aug 28, 2026
1ace9ce
fix: scope run-abort custody help and align anchor probe with its write
hmcdaniel03 Aug 28, 2026
7a0e7a7
fix(branchsync): make custody-settlement refusals leave nothing behind
hmcdaniel03 Aug 29, 2026
87d8c11
no-mistakes(review): make keep-local refusals name the anchor they wrote
hmcdaniel03 Aug 29, 2026
24c96a4
no-mistakes(review): keep lost-swap refusal local-scoped; drop daemon…
hmcdaniel03 Aug 29, 2026
711ca05
no-mistakes(review): condition axi sync keep-local flag help on gate …
hmcdaniel03 Aug 29, 2026
45a2a79
no-mistakes(document): document TUI custody settlement and run-refusa…
hmcdaniel03 Aug 29, 2026
c247762
fix(branchsync): make every custody refusal true of its own code path
hmcdaniel03 Aug 29, 2026
f84fd42
no-mistakes(review): isolate keep-local help surfaces; drop false cus…
hmcdaniel03 Aug 29, 2026
6901b9c
no-mistakes(review): scope post-swap no-change claims by anchor store…
hmcdaniel03 Aug 29, 2026
af8f5a9
no-mistakes(review): scope swap-failure disclaimer; wire complete_cus…
hmcdaniel03 Aug 29, 2026
cbc0796
no-mistakes(review): condition gate-move promise across all surfaces;…
hmcdaniel03 Aug 29, 2026
7c62035
no-mistakes(review): keep cleanup note off success path; guard consen…
hmcdaniel03 Aug 29, 2026
67c333c
no-mistakes(document): scope keep-local no-change claim; drop duplica…
hmcdaniel03 Aug 29, 2026
7354a3a
fix(branchsync): stop default recovery denying the anchor it just wrote
hmcdaniel03 Aug 29, 2026
1cc5840
no-mistakes(review): disclose gate-side recovery anchor in default re…
hmcdaniel03 Aug 29, 2026
ceb4f56
no-mistakes(review): disclose anchors in keep-local gate-unavailable …
hmcdaniel03 Aug 29, 2026
308b4d2
no-mistakes(document): scope recovery anchor-note docs to whole attempt
hmcdaniel03 Aug 29, 2026
144d7fb
fix(branchsync): disclose the recovery anchor on mid-recovery failures
hmcdaniel03 Aug 29, 2026
d7a7fc4
no-mistakes(review): disclose every recovery anchor an attempt writes
hmcdaniel03 Aug 29, 2026
69caed2
no-mistakes(document): generalize recovery anchor disclosure docs to …
hmcdaniel03 Aug 29, 2026
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
11 changes: 7 additions & 4 deletions .agents/skills/branch-sync-and-push-safety/SKILL.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/src/content/docs/guides/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ no-mistakes axi abort --run <id>
Before any post-pipeline local commit or fresh run, read `branch_sync`.
Only when its structured `next_action.code` is `sync`, run `no-mistakes axi sync` first.
When `next_action.code` is `recover_custody` - a terminal run left unpublished pipeline commits preserved in the local gate - run `no-mistakes axi sync --recover` to return custody, or `no-mistakes rerun` to resume validating the preserved head.
When `next_action.code` is `return_custody_keep_local` - a terminal run whose recorded pipeline head cannot be verified, either because no reachable object store still has it or because the run's own recovery evidence names a different commit - run `no-mistakes axi sync --recover --keep-local` to return custody at your current head and point the gate branch at it where that branch still names a different head.
When `next_action.code` is `complete_custody_return` - an earlier recovery already applied its Git changes and only the custody record is missing - re-run the exact command it names, `no-mistakes axi sync --recover` or `no-mistakes axi sync --recover --keep-local`, to complete the record; every Git step it repeats is idempotent once applied.
A `branch_sync.state` of `user_owned` means the run went terminal before changing the submitted head and cancellation released the branch: it is immediately usable and needs no sync action.
When `next_action.code` is `continue_active_run`, run the reported command and keep driving the active run.
If synchronization is blocked, process that state instead of improvising reset, stash, merge, rebase, force, or branch replacement.
Expand Down
4 changes: 3 additions & 1 deletion docs/src/content/docs/guides/tui.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ Pressing `u` explicitly refreshes the configured upstream or fork target, then o
Confirm with `u` or Enter, or cancel with Escape.
The apply path rechecks every mutable assumption and can only perform the same exact strict fast-forward or anchored equivalent-diverged advance as `no-mistakes sync`; blocked states never trigger destructive Git recovery.
When the owning run ended without publishing its pipeline commits, the same box offers `u recover custody` instead: `u` opens a confirmation naming the terminal status, the local head, and the preserved head, and applying routes through the guarded recovery documented in [`no-mistakes axi sync`](/no-mistakes/reference/cli/#no-mistakes-axi-sync).
When the state instead carries `next_action.code: return_custody_keep_local` - the terminal run's recorded pipeline head can no longer be verified, so there is nothing to recover - the box offers `u settle custody at local head`, and its own separate confirmation names the kept local head and the unverifiable recorded head before applying. Settlement keeps your head where recovery takes the preserved one, so the two never share a confirmation; applying routes through the same `--recover --keep-local` settlement documented in [`no-mistakes axi sync`](/no-mistakes/reference/cli/#no-mistakes-axi-sync).
When the state instead carries `next_action.code: complete_custody_return` - an earlier custody return applied its Git changes but could not record the custody return - the box offers `u complete custody return`, and its own confirmation says that the record is what is missing rather than repeating the settlement's claim that the recorded head cannot be verified. Applying re-runs the exact recovery the state names, `--recover` or `--recover --keep-local`, because every Git step it repeats is idempotent once applied; a command shape the TUI does not recognize offers no key at all rather than guessing which head to keep.

### Footer

Expand Down Expand Up @@ -193,7 +195,7 @@ When the instruction editor is open, press `Ctrl+s` or `Ctrl+enter` to save, or
| `?` | Toggle help overlay |
| `y` | Toggle yolo mode, which auto-resolves paused steps |
| `r` | Retry a failed fix-review state or diff load; otherwise start a rerun after a failed or cancelled run |
| `u` | Refresh and confirm local branch synchronization, or confirm custody recovery, when offered |
| `u` | Refresh and confirm local branch synchronization, or confirm custody recovery, custody settlement at the local head, or completion of an unrecorded custody return, when offered |
| `q` | Detach from TUI (or quit if run is done) |

In diff view, `n`/`p` jumps the viewport to the file and line of the next/previous finding.
Expand Down
22 changes: 16 additions & 6 deletions docs/src/content/docs/reference/cli.md

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions internal/branchsync/claims.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package branchsync

import "strings"

// SettlementGateMoveQualifier is the condition under which the keep-local
// custody return actually moves the gate branch. Every path that returns
// before recoverKeepLocal's swap leaves the gate untouched: the equal/ahead
// branch stamps custody directly, recoverSettleInconsistent returns early when
// the gate branch is PROVEN ABSENT or no gate is configured, and
// recoverKeepLocal skips its whole block when the gate already names the kept
// head. A record whose gate branch was deleted is admitted by the
// advertisement predicates on purpose, so a surface promising the settlement
// points the gate branch anywhere is telling that operator something false.
const SettlementGateMoveQualifier = "still names a different head"

// settlementGateMovePromises are the ways a surface states that promise. The
// list lives beside the code whose behavior makes the promise conditional, not
// beside any one surface, because the drift this guards against was never
// confined to a single file: a correction applied to the four cobra help
// strings left the identical claim standing on the structured branch_sync
// error, the TUI confirmation, the agent guidance, the skill and the agents
// guide.
var settlementGateMovePromises = []string{
"points the gate branch at",
"point the gate branch at",
"points that branch at",
"point that branch at",
"points the gate branch to",
"moves the gate branch to",
"move the gate branch to",
"moving the gate branch to",
"moving the local gate branch to",
"moving that branch to",
"compare-and-swaps onto the kept head",
"the gate follows the kept head",
"points it at the kept head",
}

// UnqualifiedGateMovePromise returns the first sentence of text that promises
// the keep-local custody return moves the gate branch onto the kept head
// without conditioning it on SettlementGateMoveQualifier, or "" when the
// invariant holds. Sentences are the unit because the qualifier has to travel
// with the promise an operator reads, not merely appear somewhere in the same
// document.
func UnqualifiedGateMovePromise(text string) string {
for _, sentence := range claimSentences(text) {
promised := false
for _, promise := range settlementGateMovePromises {
if strings.Contains(sentence, promise) {
promised = true
break
}
}
if !promised || strings.Contains(sentence, SettlementGateMoveQualifier) {
continue
}
return sentence
}
return ""
}

// claimSentences normalizes whitespace before splitting so a claim stays one
// sentence across hard-wrapped help text, TUI box lines, and Go string
// concatenation.
func claimSentences(text string) []string {
var out []string
for _, part := range strings.Split(strings.Join(strings.Fields(text), " "), ". ") {
if trimmed := strings.TrimSpace(part); trimmed != "" {
out = append(out, trimmed)
}
}
return out
}
Loading
Loading