Closes a "non-fast-forward ref overwrite" path where a subsequent merger
could orphan a previously-merged squash by advancing the integration
branch to a sibling commit.
Symptom (observed on fusion/fn-5419): main reflog shows
385b6e93 -> f6358ce4 (FN-5551 squash) -> 63ec7098 (FN-5552 squash)
with f6358ce4 and 63ec7098 both parented at 385b6e93. The FN-5551 squash
was correctly committed to main, then the FN-5552 merger built its own
squash off the stale 385b6e93 base and the CAS update-ref blindly moved
main sideways, orphaning f6358ce4 onto whichever feature branch had
already branched from it.
Two coupled fixes uphold the missing invariant — local <integrationBranch>
only advances via fast-forward, and the merger never builds a squash off
a stale base sha:
1. advanceIntegrationBranchRef: add a `merge-base --is-ancestor` check
before update-ref. Non-FF attempts now return
reason: "non-fast-forward-advance" instead of overwriting the ref.
The existing concurrent-advance CAS guard is retained.
2. runMerge: resolve the integration-branch tip via
`git rev-parse --verify refs/heads/<integrationBranch>` instead of
`git rev-parse HEAD` in rootDir. In reuse-task-worktree mode rootDir's
HEAD can lag behind the shared ref after a sibling merger advanced it
via update-ref without re-checking-out.
Adds regression coverage in merger-ref-update-advance.test.ts: a
sibling-commit advance with a matching expectedCurrentSha is now refused
with the new reason, and multi-commit fast-forwards still succeed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>