branch-sync-and-push-safety
SkillDev toolsUse when changing local branch synchronization, custody recovery, post-review head binding, rebasing, or force-push safety.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the branch-sync-and-push-safety skill
What this skill tells your AI
The instructions your AI receives, as published by kunchenguid/no-mistakes in .agents/skills/branch-sync-and-push-safety/SKILL.md and read by ahel’s review.
Guarded Local Branch Synchronization (internal/branchsync)
sync,axi sync, and the TUIuaction share one service whose only ordinary worktree mutation is a clean guarded move to an exact freshly verified pipeline push binding: strict fast-forward for behind branches, or an anchored reset to an equivalent diverged pipeline head when local unique work is already represented there. Under--recover, the worktree can only strict-fast-forward to the gate-preserved head, or adopt a diverged preserved head thatpreservedContainsLocalWorkproves carries every local change. Passive status never fetches, and blocked states never reset, stash, merge, rebase, force, switch, delete, or update an external remote.- Give each network remote operation its own bounded child context derived from the caller:
Refreshmust not share one deadline across sequentialgit.LsRemoteandgit.FetchRemoteBranchToPrivateRefcalls, andApplyuses the same per-operation budget for its final live check. The per-operation budget isService.RemoteTimeout, sourced only from the operator's globalbranch_sync_remote_timeoutsetting (defaultconfig.DefaultBranchSyncRemoteTimeout, 60s);RepoConfigdeliberately has no matching field.Recover's local-gate fetch is outside this network deadline contract. Regressions:TestRefreshSlowSuccessfulLsRemoteDoesNotStealFetchBudget,TestRefreshSlowButSuccessfulLsRemoteAloneExceedsItsOwnBudgetReportsOffline,TestRefreshRaisedRemoteTimeoutAcceptsTheSameLegitimateSlowLsRemote,TestRefreshParentCancellationStopsFetchAfterLsRemoteSucceeds,TestServiceRemoteTimeoutDefaultsToConfigDefault,TestLoadGlobal_InvalidBranchSyncRemoteTimeout,TestLoadRepo_BranchSyncRemoteTimeoutIsNotARepoSetting. - Successful pipeline pushes persist the exact SHA, credential-free target fingerprint/ref, and generation; legacy rows remain nullable and must never infer provenance from mutable
head_sha. Structured PR lifecycle retires merged/closed branches. The service rechecks the invoking worktree, target, live remote equality, ancestry or equivalent-divergence proof, generation, and all mutable assumptions immediately before apply. - A TERMINAL run with unpublished pipeline commits (moved head) is recoverable only from verified, non-conflicting evidence: inspection and
Recovershare one eligibility model. Equal/ahead local ancestry can create the local anchor without requiring gate access, but available gate evidence must agree; importing a locally missing preserved head requires exact or safely anchorable gate evidence, a clean worktree, and either ancestry or the content-preservation proof below. Only then does inspection reportblocked_pipeline_owned_recoverable+next_action recover_custodywith the exact submitted/current-head and relation facts (active runs keep the plain block). Non-commit, symbolic, or conflicting evidence, and import cases that are dirty or genuinely divergent, fail closed with manual reconciliation. A verified head absent from both the worktree and an accessible gate instead offers the explicit--recover --keep-localdiscard path described below. Plainsync --recoveranchors the preserved head atrefs/no-mistakes/recover/<run>before stampingruns.custody_returned_at. Cancellation RELEASES a terminal run that never changed the submitted head (head_sha == submitted_head_sha, no push, no custody stamp): selection keeps it visible so it never misreports asblocked_wrong_branch, and it classifiesuser_owned- nonext_action, non-blocking exit, never represented as recoverable custody,--recoverthere is an idempotent no-op that mutates nothing, and a freshaxi runor separately authorized direct push is never blocked. Equal/ahead worktrees anchor locally without requiring gate access, but an available gate's existing recovery ref must agree with the recorded head; behind/diverged worktrees verify and fetch the preserved head from the run-specific recovery ref, fast-forwarding only a clean behind worktree. A cancelled validation routinely leaves a preserved head that is a REBASE of the local branch, which equality and ancestry read as plain divergence, so a clean diverged worktree is adopted whenpreservedContainsLocalWorkproves containment. That proof is an executablemerge-treethree-way merge whose result must equal the preserved head's tree, anchored on the merge-base - neverruns.base_sha, the previous gate head. It deliberately does NOT use patch identity: patch IDs discard hunk locations and whitespace, so they cannot tell a genuine replay from a same-shaped edit to another identical block, and a containment claim built on them is not a proof. Everything undecidable escalates, including a rebase whose fix rounds also rewrote operator lines, where nothing separates a deliberate fix from a dropped change. Adoption anchors the pre-recovery local head atrefs/no-mistakes/recover-local/<run>, then moves the branch with Git operations that fail closed on their own rather than after an observation - an atomicupdate-refCAS plusread-tree -m -u, never check-then-act followed byreset --hard, which destroys anything landing in the gap.recoverAdoptPreservedowns the reasoning. Terminalization pins every verified unpublished head atrefs/no-mistakes/recover/<run>before the managed worktree can be removed. Recovery reads that run-specific ref rather than requiring the gate branch to match, so aborts, rebases, and pre-push failures remain recoverable while an independently moved gate branch is preserved. Legacy recorded heads that still exist as dangling gate objects are anchored on recovery. When an accessible gate confirms that a verified recorded head is truly missing and both recovery refs are compatible, status offersrecover_custodywithno-mistakes axi sync --recover --keep-local: that flag is the operator's explicit discard of unpublished pipeline commits. Unverified heads, inaccessible gates, and conflicting refs retain manual reconciliation, and plain--recoverstill refuses. A divergent later head can also prove preserved through exactly one append-onlyrecovery_archivesbinding, but only while its repository, run, branch, required/preserved heads, raw archive ref, and gate recovery ref all revalidate.recoverySourceAvailableremains the one discovery/classification owner and offers onlyrecover_custodywith--recover --keep-local; the archived head is never selected. Similar unbound refs and every stale, moved, symbolic, malformed, cross-bound, or ambiguous record fail closed. When the operator keeps a behind or diverged local head instead of taking the preserved head,--keep-localnever touches the worktree and CAS-moves the gate branch to the kept head, staging objects via gate-side fetch - never a push, which would fire the receive hook and start a run. The full relation matrix and fail-safe rules live in theRecoverdoc comment ininternal/branchsync/sync.go. - Public guidance is owned by
internal/skill/skill.goplus live AXI strings, then regenerated withmake skill. Core regressions live ininternal/branchsync(incl.recover_test.go),internal/cli/sync_test.go,internal/tui/branch_sync_test.go, and e2eTestAxiBranchSyncJourney/TestAxiCustodyRecoveryJourney/TestAxiCustodyRecoveryAfterRebaseJourney/TestAxiPrePushAbortUnmovedHeadCustodyJourney.
Post-Review Head Continuity and Push Binding
- Every step after Review in the fixed pipeline order (Test, Document, Lint, Push, PR, CI) calls
assertPipelineHeadContinuityat entry. The helper is the single semantic owner: equal or descendant live heads continue; backward, sibling, and unverifiable heads fail before the step performs work. Regression:TestPostReviewStepsRefuseHeadClobberAtEntry. - A successfully completed full review atomically records
runs.review_approved_head_sha; parked, failed, skipped, and legacy reviews carry no inferred authority. Push reads that durable binding, permits only the exact commit or a descendant, and pushes the verified immutable SHA rather than mutableHEAD. Never infer approval fromruns.head_sha, a worktree, gate ref, or remote branch. Regressions:TestPushStep_RefusesPostReviewClobberWithoutLaterPipelineCommit,TestPushStep_BindsRemoteAndDatabaseToVerifiedCommitWhenHEADMovesDuringPush,TestExecutor_FullRereviewReplacesApprovalWithoutAuthorizingParkedRound.
Rebase Base & Force-Push Safety (data-loss prevention)
- The whole job of this tool is to not lose people's code; favor refusing the push and surfacing a finding over any clever recovery. The comments in
internal/pipeline/steps/forcepush.goown the full reasoning; the invariants are the next three bullets. - Rebase bases come from the freshly fetched authoritative remote refs, never local or stale state; and a branch built on unpushed local-default-branch commits parks with
NeedsApproval+AutoFixable=falseinstead of silently widening the PR (detectBundledLocalDefaultCommits, #283). - Every force-push routes through
resolveForcePushDecision, which re-reads the live remote head and allows the push only for a new branch, an already-equal remote, an unchangedlastSeenSHA, or remote commits already incorporated by patch-id (excluding^baseSHAhistory the run knowingly rewrites). Anything else refuses, and a failed ls-remote/fetch fails closed; never degrade to a bare--force/--force-with-leasewithout an explicit anchor. lastSeenSHAmust stay the head the run last observed (from run/prior-run push provenance or the remote-tracking ref), never the live remote tip: the rebase step refreshesorigin/<branch>only on a normal push, NOT on a force push. CI repairs commit locally and restart validation at Review; the later Push step owns their remote update and force-push safety. Anchoring a lease to a SHA read immediately before pushing is the original #281 bug (it always passes and protects nothing); always-fetching the branch on force push recreates it. Never reintroduce either.- Regressions:
TestPushStep_RefusesToClobberAdvancedUpstreamBranch(#305),TestForcePushRun_RefusesToClobberOutOfBandBranchCommit,TestRebaseStep_DetectsUnpushedLocalDefaultBranchCommits(#283),TestResolveForcePushDecision_*,TestExecutor_CIRestartRevalidatesBeforePush,TestPushStep_AllowsForcePushAfterMidRunRebaseOverPriorPushedGeneration(#837),TestPushStep_AllowsForcePushOnRerunOverPriorRunPushedGeneration(#837).
Signals
- GitHub stars
- 8k
- Forks
- 855
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
branch-sync-and-push-safety- Source
- github.com/kunchenguid/no-mistakes