feat(FN-5633): standalone AI merge path (clean-room merge + AI reviewer)
New default merge path (merger.mode="ai"), self-contained in merger-ai.ts and dispatched from ProjectEngine.onMerge instead of the legacy aiMergeTask pipeline (kept for merger.mode="deterministic"). Flow: clean-room detached worktree at the target branch tip → AI agent merges the task branch + squashes (resolving conflicts) → fresh read-only AI reviewer audits with corrective retries (blocking vs advisory; advisory lands, unfixable correctness hard-fails via AiMergeBlockedError; fail-safe verdict parsing) → land via `git merge --ff-only` when the checkout is on the target (else update-ref CAS) → sync the local checkout (stash → ff → restore; AI reconciles a conflicting restore and keeps the original edits in a backup stash; un-stashable dirt advances the ref + warns) → finalize (delete task branch — never the integration branch — task→done, remove temp worktree). - Per-task target branch honored (falls back to the default integration branch); local checkout synced only when on that target. - Structurally immune to the dirty-clobber and stale-base/non-FF bug classes of the legacy path (clean room + FF-by-construction). - Progress surfaced on the task status pill + task log stream. - Clear error when the target branch has no local ref. Settings: merger.mode / merger.reviewerModel / merger.maxReviewPasses, surfaced in Settings → Merge; legacy merge-mechanics settings hidden when AI mode is on. Tests: merger-ai.test.ts (verdict parser, clean merge, blocking hard-fail, advisory land, empty no-op, target-branch isolation, missing-target error, landSquash clean/other-branch/dirty-restore/AI-resolved). Legacy merge-orchestration tests pinned to deterministic mode. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
21
.changeset/fn-5633-standalone-ai-merge.md
Normal file
21
.changeset/fn-5633-standalone-ai-merge.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
feat(FN-5633): standalone AI merge path (clean-room merge + AI reviewer)
|
||||
|
||||
Adds a self-contained AI merge path (`merger.mode: "ai"`, the new default) that the engine dispatches to instead of the legacy `aiMergeTask` pipeline. It does not share the legacy scaffolding (prerebase / conflict-strategy ladder / post-merge audit / transient self-heal), which was buggy and error-prone.
|
||||
|
||||
How it works:
|
||||
- **Clean room**: a throwaway detached worktree is created at the target branch's current tip, so the user's real checkout is never the merge surface — dirty files cannot be clobbered and the landing is a fast-forward by construction.
|
||||
- **AI merge**: an AI agent merges the task branch into the clean room and produces one squash commit, resolving conflicts in favor of the task's intent.
|
||||
- **AI reviewer with retries**: a fresh read-only reviewer audits the squash (completeness / collateral / conflict-soundness) and classifies any veto blocking vs advisory. It drives up to `merger.maxReviewPasses` corrective re-merges. After the budget, advisory concerns land with a logged warning; an unfixable BLOCKING (correctness) concern hard-fails (`AiMergeBlockedError`) rather than ship wrong code. Verdict parsing fails safe to blocking.
|
||||
- **Per-task target branch**: each task merges into its own target branch (or the default integration branch). The local checkout is only synced when it is on that target.
|
||||
- **Local checkout sync**: when the checkout is on the target branch, the ref + working tree advance together via `git merge --ff-only` (dirty state read accurately before the move); dirty edits are stashed, fast-forwarded, and restored — and if the restore conflicts the AI merger reconciles them (the original edits are also kept in a stash as a backup). A checkout on a different branch is advanced via `update-ref` and left untouched. Un-stashable dirty state advances the ref and leaves the working tree with a warning. Concurrent advances trigger a bounded rebuild on the new tip.
|
||||
- **Status + logs**: progress (merging / reviewing / corrective passes / landing / blocked / landed) is written to the task status pill and the task log stream.
|
||||
|
||||
Settings: `merger.mode` (`ai` default / `deterministic` legacy), `merger.reviewerModel`, `merger.maxReviewPasses` (default 3), surfaced in Settings → Merge. When AI merge is on, the legacy merge-mechanics settings (integration worktree, conflict strategy, overlap guard, post-merge audit, direct-commit routing) are hidden since they do not apply.
|
||||
|
||||
The legacy `aiMergeTask` pipeline is retained unchanged and used when `merger.mode: "deterministic"`.
|
||||
|
||||
Tests: `merger-ai.test.ts` covers the verdict parser, clean merge, blocking hard-fail (no advance), advisory land, empty no-op, per-task target branch isolation, missing-target-branch error, and `landSquash` (clean ff, other-branch update-ref, dirty stash-restore, AI-resolved restore conflict). Engine merge-orchestration tests that assert the legacy path are pinned to `merger.mode: "deterministic"`.
|
||||
Reference in New Issue
Block a user