Commit Graph

2 Commits

Author SHA1 Message Date
gsxdsm
dc944949b1 fix(engine,dashboard): close 7 review findings on merger auto-sync
Data-loss fixes in syncWorktreeToHead:
  - Untracked-restore checks `git ls-tree -r --name-only HEAD` to skip
    paths the new tip added as tracked files; user bytes stay in the
    stage dir instead of clobbering merged content.
  - Apply-failure on a deleted/renamed file: conflictedFiles falls back
    to parsing `diff --git a/<p> b/<p>` headers when --diff-filter=U
    returns nothing.
  - All git invocations pass `-c core.quotePath=false` so non-ASCII
    paths round-trip through copyFileSync.
  - Stash-and-ff re-verifies rev-parse HEAD === newSha right before
    each `reset --hard HEAD` (TOCTOU). On mismatch we bail with patch
    preserved on disk.
  - Stage dir lifecycle moved into try/finally with preserveStageDir
    flag — kept whenever the user's edits live only in patchPath; rm'd
    on all clean exits.
  - Patch written to disk before the apply attempt, not only on
    failure, so a crash between snapshot and apply doesn't lose edits.

Multi-worktree-same-branch fix:
  - New getRegisteredWorktreeBranches returns Array<{branch,path}>
    instead of collapsing into a Map. Multiple worktrees can share a
    branch via `git worktree add --force -b`; merger now syncs all of
    them rather than silently skipping all but the last.

Contract + surfacing fixes:
  - JSDoc on merge:auto-sync GitMutationType now lists the actually-
    emitted outcome strings + stage enum.
  - GET /api/tasks/merge-advance-events joins merge:auto-sync events
    within ±5min of the advance and returns them in a new
    `autoSync: AutoSyncOutcome[]` field; useMergeAdvanceNotice exposes
    the same shape so the banner can surface pop-conflicts (including
    patchPath) instead of dropping them.

Hygiene:
  - Merger now reads the setting via normalizeMergeAdvanceAutoSyncMode
    instead of an inline check + `as unknown` cast.

New tests:
  - Untracked-collides-with-tracked preserves merged content.
  - Apply failure on deleted file populates conflictedFiles from
    patch header.
  - Route surfaces autoSync outcomes (clean-sync + pop-conflict)
    joined within the time window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:13:17 -07:00
gsxdsm
4c31e885bd feat(engine): merger auto-syncs project-root checkout after ref advance
After advanceIntegrationBranchRef ff-updates refs/heads/<integrationBranch>,
the merger now enumerates other worktrees on that branch and reconciles
each one's index + working tree to the new tip via syncWorktreeToHead.

Not a git pull — origin may still be at the previous tip without
pushAfterMerge, so pull --ff-only is a no-op and a naive stash/pull/pop
ends with the worktree restored to the old state. Instead the new
worktree-ref-sync helper:

  1. Diffs the worktree against the previous tip to isolate real edits
     from the stale-index "phantom diff" against the new HEAD.
  2. Snaps clean worktrees forward via reset --hard HEAD.
  3. In stash-and-ff mode with real edits, captures them as a binary patch
     against the previous tip, snaps to HEAD, then git apply --3way to
     restore. Untracked files are saved + restored separately. Patch
     conflicts surface as synced-with-pop-conflict with the patch left on
     disk for manual recovery.

Per-worktree outcome emitted as merge:auto-sync (new GitMutationType).
Per-step pull:fast-forward / stash:push / stash:pop / stash:pop-conflict
that pass through the auditor are tagged metadata.autoSync=true.

Isolated in its own try-catch so an auto-sync failure can't fail the
already-landed merge. Default behavior is mergeAdvanceAutoSync="stash-and-ff";
"off" preserves the legacy surprise behavior.

Backstopped by merger-auto-sync.slow.test.ts: clean-sync snaps both index
and files forward, ff-only with real edits is a no-op, stash-and-ff
preserves untracked locals across the snap, task worktrees on fusion/fn-*
are skipped, empty branch map emits nothing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 14:41:11 -07:00