fix(engine): make merger autostash recovery resilient and AI-resolve conflicts

When rootDir is the developer's primary checkout, the merger stashes
uncommitted edits before its hard resets and applies them back at the
end. Previously a pop conflict logged a single warning and silently
left the stash in place — a subsequent merge would push another
autostash on top, burying the first. Recent FN-3299 work was lost this
way and surfaced two side-by-side fusion-merger-autostash entries in
the local stash list.

Three changes:

- AI auto-resolve on apply conflict. The new
  runAiAgentForAutostashConflict spawns the same createResolvedAgentSession
  path as the in-merge fix-agent, instructs it to clear conflict markers
  in place without committing, and verifies markers are gone post-run.
  On verified success the stash is dropped; on any failure or remaining
  markers the stash is left intact for manual recovery.
- Outcome surfaced via new MergeResult.autostash (AutostashOutcome)
  field so dashboard / CLI / daemon can show developers whether their
  work was reapplied cleanly, AI-resolved, or needs manual recovery.
- Deterministic stash identity. Replaced `git stash push` + label-grep
  (which races against concurrent stashing tools) with `git stash create`
  + `git stash store`, capturing SHA atomically with snapshot creation
  and using it for apply / drop. Untracked files captured via `git add
  -A` before create; cleanup via `git reset --hard` + `git clean -fd`.

Also surfaces orphaned `fusion-merger-autostash:*` entries from prior
runs at merge entry, so they can no longer be silently buried.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-05-05 20:45:37 -07:00
parent 12193d265c
commit aecc050ff1
4 changed files with 544 additions and 45 deletions

View File

@@ -0,0 +1,14 @@
---
"@fusion/engine": patch
"@fusion/core": patch
---
Make the merger's autostash recovery robust against silent data loss. When `rootDir` is the developer's primary checkout, the merger stashes uncommitted edits before running its hard resets and applies them back at the end. Previously a pop conflict logged a single warning and silently left the stash in place — and a subsequent merge would push another autostash on top, burying the first.
Three changes:
1. **AI auto-resolve on apply conflict.** When the autostash apply hits a conflict, the merger now spawns a focused fix-agent (same `createResolvedAgentSession` path used for the in-merge verification fix-agent) to resolve conflict markers in the working tree. On success the stash is dropped and the resolution is recorded in `MergeResult.autostash`. On failure the stash is left intact for manual recovery.
2. **Outcome surfaced on `MergeResult.autostash`** (new field of type `AutostashOutcome`). Consumers (dashboard, CLI, daemon) can now show the developer whether their work was reapplied cleanly, AI-resolved, or needs manual recovery — instead of relying on a buried log warning.
3. **Deterministic stash identity via `git stash create` + `git stash store`.** Replaces the previous `git stash push` + label-grep flow that raced against any other tool stashing concurrently. The stash SHA is captured atomically with snapshot creation and used for apply/drop, so the operation is robust to stash list reordering.
Also: orphaned `fusion-merger-autostash:*` entries from prior failed runs are now detected at merge entry and surfaced as a warning so they cannot be silently buried again.