When the AI merge agent reported a build failure via fn_report_build_failure,
executeMergeAttempt immediately ran `git reset --merge` and threw. The catch
handler then spawned an in-merge fix agent on a clean main and called
amendMergeCommitWithFixes, which blindly amended HEAD — the *previous* task's
merge commit — silently dropping the current task's branch and inheriting
the prior task's stats. The dashboard then reported the new task as merged
with completely unrelated files.
- Drop the immediate reset at the build-failure throw site so the squash
state survives for the in-merge fix path.
- Capture preAttemptHeadSha at each mergeAttempt and refuse to amend when
HEAD never moved past it; instead, create a fresh commit from the squash
+ fix changes. If neither HEAD moved nor anything is staged, abort the
merge instead of fabricating success.
- Move the cleanup reset into the mergeAttempt catch handler (with a
labeled resetMergeWithWarn helper) so it still fires when the fix path
is exhausted or disabled.
- Replace the AI-authored commit body with a deterministic body built from
the branch's actual step-commit subjects after every successful AI merge.
Stops the recurring problem of merge messages describing files that are
not in the diff.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>