Skip to content

fix(branchsync): recover reviewed equal-tree rewrites - #854

Open
janustsen wants to merge 2 commits into
kunchenguid:mainfrom
janustsen:fix/terminal-equal-tree-recovery-upstream
Open

fix(branchsync): recover reviewed equal-tree rewrites#854
janustsen wants to merge 2 commits into
kunchenguid:mainfrom
janustsen:fix/terminal-equal-tree-recovery-upstream

Conversation

@janustsen

Copy link
Copy Markdown

Summary

Terminal custody recovery currently refuses a live gate head when a pipeline rewrites commit history, even if the reviewed terminal commit and live commit produce the same Git tree.

This change permits that narrow recovery case. It requires the recorded terminal head to match the durable review-approved head, proves that reviewed head preserves the submitted work, verifies that the live head has the same tree, and then uses ref and database compare-and-swap checks before returning custody.

Synthetic reproduction

Given:

  • L: the submitted local commit
  • A: the reviewed terminal commit, which preserves L
  • B: the live gate commit after a history-only rewrite
  • tree(A) == tree(B)
  • neither A nor B is an ancestor of the other

A terminal axi sync --recover currently returns blocked_recover_unverified_head. With this change, it adopts B, preserves the pre-recovery local head under refs/no-mistakes/recover-local/<run>, and remains idempotent on a repeated recovery.

Safety

The ordinary descendant recovery path is unchanged. The new path also requires:

  • a terminal run and clean worktree
  • exact tree equality between the reviewed recorded head and live gate head
  • durable review authority for the recorded head
  • proof that the reviewed head preserves the submitted local work
  • create-only recovery anchors and atomic live-branch verification
  • a database CAS over status, recorded head, reviewed head, and unstamped terminal custody
  • final branch, HEAD, cleanliness, anchor, and custody checks from the existing adoption path

Different trees, dropped local work, rewritten operator content, unreviewed recorded heads, conflicting or symbolic refs, active runs, dirty worktrees, and branch races all refuse without mutating refs, the worktree, remotes, or the run row.

Compatibility

There is no schema, CLI, configuration, or protocol change. Existing descendant recovery behavior stays intact. The added database operation only tightens the terminal equal-tree verification transaction.

Validation

  • go test ./internal/branchsync -run '^TestRecoverTerminalUnverified(EqualTreeRewriteAdoptsLiveGateHead|RewriteNegativeControls)$' -count=1 -v
  • go test ./internal/db -run '^TestVerifyTerminalRunHeadRewriteUsesRecordedReviewCAS$' -count=1 -v
  • isolated public-command recovery, repeated idempotency, and mutation-free different-tree refusal
  • make lint
  • GOFLAGS='-count=1 -p=1' make test
  • clean isolated full e2e: bash scripts/e2e.sh -tags=e2e -count=1 -timeout 20m -p=1 ./internal/e2e/... ./internal/pipeline/steps/...
  • candidate build SHA-256: c302eaf66dade1f01eddf1f8ea6e7456d06fe03b0ca24f6f7516ab32b8e27697

Review order

  1. internal/branchsync/sync.go and internal/db/run.go for the proof and CAS boundaries.
  2. internal/branchsync/recover_test.go and internal/db/run_test.go for positive, negative, anchor, and race coverage.
  3. internal/e2e/axi_journey_test.go for the public recovery and idempotency journey.
  4. internal/git/git.go for atomic stdin-backed git update-ref support.

@greptile-apps

greptile-apps Bot commented Aug 26, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge with its new recovery path constrained by matching review authority, exact tree equality, submitted-work preservation, atomic ref verification, and database compare-and-swap checks.

No concrete changed-code failure remains; the implementation fails closed when its Git, worktree, review-authority, or database assumptions change and retains the existing final adoption checks.

Reviews (1): Last reviewed commit: "fix(branchsync): trust reviewed head bef..." | Re-trigger Greptile

@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate:

First look at HEAD 987dc37f (internal/branchsync/sync.go Recover equal-tree path, VerifyTerminalRunHeadRewrite CAS in internal/db/run.go, git.RunWithInput for atomic update-ref --stdin). First-time fork CI approved (CI / Guard / Require).

Diff review: only recovers when recorded head equals durable review_approved_head_sha, trees match, submitted local work is preserved, worktree clean, live branch not symbolic, create-only/verify recovery anchor, then DB CAS (status+head_sha+review_approved_head_sha+terminal_head_verified_at IS NULL+custody_returned_at IS NULL). Different trees / missing review authority / races refuse without mutating. Ordinary descendant recovery unchanged. Corrective for "never lose work" stuck recoveries; not a default gate-pass change and not a security risk. Greptile 5/5.

VISION.md:

  • R1: aligns. Narrow recovery path; core pipeline order unchanged.
  • R2: aligns. Unblocks equal-tree rewrite custody return with fail-closed proofs and CAS.
  • R3: aligns. No judgment transfer; mechanic recovery only.
  • R4: aligns.
  • R5: aligns. Refuses loudly when proofs fail; stamps only after verified adoption.
  • R6: aligns.
  • R7: aligns. Dogfood recovery regression.

Require failed "not raised through no-mistakes" (opened-event; not ruleset-required). Waiting on hosted CI before merge.

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.

2 participants