fix(FN-5345): address second-pass review findings

Follow-up to 8e6740468 addressing six review findings, including one real
regression (combined short flags bypass amend detection).

HIGH

- Combined short flags ('-am', '-vm', '-sm', '-aF', ...) now count as
  message-supplying tokens in the prepare-commit-msg empty-commit guard.
  Previously, an agent could bypass the guard with
    git commit --allow-empty -am 'fix --amend handling'
  because '-am' did not match the literal '-m' case, so the token loop
  continued past the message text and matched the '--amend' substring inside
  it. The new pattern -[!-]*[mF]* matches any short combined flag containing
  'm' or 'F' while leaving '--amend' (starts with '--') untouched.
  Verified locally with two regression tests for '-am' and '-vm' plus one
  positive test confirming legitimate '-am' with a real tracked modification
  still succeeds.

MEDIUM

- Early empty-own-diff fast-path cleanup no longer uses 'git worktree remove
  --force'. We now run 'git status --porcelain --untracked-files=normal'
  first; dirty worktrees (or status-check failures) are left alone for the
  self-healing sweep to reconcile later. Prevents silent loss of uncommitted
  scratch in the no-op finalize path.
- MergeResult.task is now kept in sync with the DB after early-fast-path
  cleanup. After 'store.updateTask(taskId, { worktree: null, branch: null })'
  succeeds, the in-memory task.worktree/.branch are also cleared to undefined
  so the returned result.task does not advertise a removed path or deleted
  branch.

LOW

- Branch deletion in the fast-path cleanup only fires when 'task.branch' was
  non-null on entry. If the task did not explicitly own a branch on entry,
  we never invoke 'git branch -D'; orphan refs are left for
  cleanupOrphanedBranches to handle. Prevents deleting a stray ref that
  happened to share the canonical name.
- Inverted the empty 'if (poolBypassRequired) {} else { ... }' block in
  reacquireReuseIntegrationWorktree to 'if (directReuseEligible) try { ... }'
  with the pool-bypass note above it. No behavior change \u2014 just removes the
  awkward empty branch and the one-level-deeper indent on the direct-reuse
  logic.

Tests
  - Full @fusion/engine suite: 448 files / 5881 tests / 9 skipped, all green
  - pnpm lint green, pnpm build green
This commit is contained in:
Fusion (runfusion.ai)
2026-05-20 18:06:02 -07:00
parent 8e67404680
commit c64884c24a
3 changed files with 97 additions and 29 deletions

View File

@@ -45,7 +45,7 @@ describe("prepare-commit-msg empty-commit guard (real git, FN-5345/FN-5377)", ()
expect(empty.stderr).toContain("refusing empty commit");
expect(empty.stderr).toContain("FN-5345/FN-5377");
// Review-finding regression: a commit message containing the substring
// Review-finding regression #1: a commit message containing the substring
// '--amend' must NOT trick the parent-cmd tokenized check into allowing
// the empty commit. The original glob pattern (*' --amend'*) would have
// matched this; the tokenized check rejects it.
@@ -56,6 +56,31 @@ describe("prepare-commit-msg empty-commit guard (real git, FN-5345/FN-5377)", ()
expect(sneaky.status).not.toBe(0);
expect(sneaky.stderr).toContain("refusing empty commit");
// Review-finding regression #2: combined short flags like '-am', '-vm',
// '-sm' must also count as message-supplying tokens, otherwise the
// tokenized scan continues past them and hits '--amend' in user-controlled
// message text. The combined-short-flag pattern -[!-]*[mF]* catches these
// while leaving '--amend' (starts with --) untouched.
const sneakyAm = git(
worktreeDir,
"git commit --allow-empty -am 'feat(FN-5345): fix --amend handling via -am'",
);
expect(sneakyAm.status).not.toBe(0);
expect(sneakyAm.stderr).toContain("refusing empty commit");
const sneakyVm = git(
worktreeDir,
"git commit --allow-empty -vm 'feat(FN-5345): fix --amend handling via -vm'",
);
expect(sneakyVm.status).not.toBe(0);
expect(sneakyVm.stderr).toContain("refusing empty commit");
// Legitimate combined short flag with -a and a modified TRACKED file:
// should succeed (not blocked by the message-flag detection — -a stages
// the tracked modification, the resulting commit is non-empty).
writeFileSync(join(worktreeDir, "real.txt"), "real-modified\n");
const legitAm = git(worktreeDir, "git commit -am 'feat(FN-5345): legit -am commit'");
expect(legitAm.status).toBe(0);
// --amend --no-edit (no staged changes, amend HEAD) is ALLOWED.
const amendNoEdit = git(worktreeDir, "git commit --amend --no-edit");
expect(amendNoEdit.status).toBe(0);