Commit Graph

2053 Commits

Author SHA1 Message Date
gsxdsm
5848606a9a feat(engine): post-session branch attribution audit
Contamination on fusion/<id> branches (FN-5233 was the recent example:
two untrailered feat(FN-5353): commits sitting on fusion/fn-5233) used
to be invisible until merge time, days after it happened. The executor
already runs assertCleanBranchAtBase at worktree acquisition and reclaim
— the gap was the active session window itself.

Add reportBranchAttribution(repoDir, branch, baseSha, taskId) which
walks base..branch and bins every commit into ownTrailed (healthy),
ownUntrailed (subject tag but commit-msg hook didn't fire), foreign
(different FN-id), or unattributed (no subject pattern, no trailer —
typically a hand-merge or plumbing commit). Wire it into the executor
right after captureModifiedFiles in the post-session path: when any
anomaly bucket is non-empty, emit a structured branch:attribution-
anomaly audit event and a task log entry. The audit itself is wrapped
in a try/catch so a probe failure never destabilizes a completing
session. New branch:attribution-anomaly and branch:auto-reattach-
authoritative GitMutationType variants accept the structured metadata
(the latter for the handoff re-attach added earlier this session).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:20:33 -07:00
Fusion (runfusion.ai)
a8715ed963 fix(FN-5335): enforce triple-proof gating for backward recovery
- Gate self-healing backward moves behind audited triple-proof predicates across reclaim paths
- Skip reclaim-pr-conflict mutations when proof checks fail and preserve no-action behavior
- Add broad unit and reliability-interaction coverage for triple-proof and cross-layer scenarios
- Document backward-move stage invariants, diagnostics, and add delivery changeset for @runfusion/fusion
2026-05-21 19:15:27 -07:00
gsxdsm
a2a5db8151 fix(engine): surface phantom-finalize cause and reset HEAD when branch is authoritative
commitOrAmendMergeWithFixes used to swallow every unexpected throw as
`reason: "unknown-phantom"` and the two callers re-threw a bare
"verification fix finalize failed (unknown phantom)" with no operator-
actionable signal. FN-5422-class wedges (preAttemptHeadSha == currentHead
but branchTip ahead with task-trailered commits) couldn't be diagnosed
without re-running.

The catch now records the original error and probes whether the branch
ref itself is authoritative for the task (tip carries Fusion-Task-Id
trailer, base..branch is foreign-contamination-free). When it is — i.e.
the work isn't lost, the integration worktree just didn't advance — the
catch resets rootDir to preAttemptHeadSha so the next merge attempt
starts from a known baseline instead of inheriting partial squash state,
and returns `reason: "branch-ref-ahead-reset"`. The two callers fold
`originalError=` and `branchAuthority=` into the thrown message so the
real cause (diff-volume gate, file-scope, transient git, etc.) is
visible in the run log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:10:24 -07:00
gsxdsm
d947197c2a fix(engine): auto-reattach HEAD at handoff when branch ref is authoritative
The merge handoff refused with head-branch-mismatch whenever the reused
worktree's HEAD wasn't on fusion/<id> (detached, recycled to main, or on
a sibling branch), even when the branch ref itself still held a clean,
task-attributed lineage. That wedged FN-5339-class tasks in review for
no good reason.

Add isBranchAuthoritativeForTask in branch-conflicts.ts (branch ref
exists, tip carries Fusion-Task-Id trailer, base..branch is foreign-
contamination-free) and use it in acquireReuseHandoff: when HEAD drifts
but the branch ref is authoritative, run a plain `git checkout <branch>`
inside the already-asserted-clean worktree, re-read HEAD, and emit a
branch:auto-reattach-authoritative audit. Refusal still fires unchanged
when the branch ref is missing, missing the trailer, or contaminated,
so FN-5363 strict-lease and foreign-commit guards remain authoritative.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:03:35 -07:00
Fusion (runfusion.ai)
025683ca60 feat(FN-5438): add manual merge blocker bypass mode for queued tasks
Adds a manual merge blocker mode (FN-5438) that prevents automatic merging and provides a bypass mechanism to resume, wired through the merger, project engine, and task workflow API routes. Includes tests across core, engine route registration, and project engine layers, plus a changeset and documen

Fusion-Task-Id: FN-5438
2026-05-21 18:29:03 -07:00
Fusion (runfusion.ai)
921e0e616f feat(FN-5358): add smart pull API route with stash conflict detection and r
Implements stash conflict detection and resolution with a new smart pull API route, resolution endpoints, and a dedicated conflict modal UI — backed by extended git audit taxonomy and route tests.

Fusion-Task-Id: FN-5358
2026-05-21 17:46:54 -07:00
Fusion (runfusion.ai)
41c94a326a feat(FN-5420): add PR-mode worktree invariant backstop tests
Adds PR-mode worktree invariant backstop tests (`pr-mode-worktree-invariants.test.ts`) covering cross-package import patterns, stale-registration branch mapping in audit scenarios, and PR invariants, with refinements per review feedback.

Fusion-Task-Id: FN-5420
2026-05-21 17:31:59 -07:00
Fusion (runfusion.ai)
f6f38676b4 feat(FN-5226): add scope auto-widen layer 2.5 to merger for attribution-bas
Merges the Layer 2.5 scope-auto-widen feature (FN-5226) into the merger: a new evaluator module that automatically widens a task's declared file scope based on git attribution prior to the existing scope partition gate, wired into `merger.ts` with full audit taxonomy, persisted task metadata, and re

Fusion-Task-Id: FN-5226
2026-05-21 16:30:31 -07:00
Fusion (runfusion.ai)
a3ace52995 feat(FN-5440): test merger cwd-fallback guards for fn-5440
Test coverage hardening for FN-5440: adds stronger interaction tests across three steps covering the cwd-integration-fallback-removed path and the merge-reuse-task-worktree early fast-path, including expanded fallback audit tripwires and hardened metadata literal guards. No production code changes.

Fusion-Task-Id: FN-5440
2026-05-21 15:56:14 -07:00
Fusion (runfusion.ai)
8df21a6b68 feat(FN-5353): fix merge-reuse handoff race by gating reacquire and strict
Fixes merge handoff stalls by enforcing strict queue targeting and self-enqueue in the merger (FN-5353 Step 4), forcing reacquire before reuse handoff gates (Step 5), and aligning integration-root contract tests (Steps 1 & 7). Consolidates two prior changesets into `fn-5353-merge-reuse-stall-fix.md`

Fusion-Task-Id: FN-5353
2026-05-21 15:30:13 -07:00
Fusion (runfusion.ai)
b8147dd3b1 feat(FN-5405): remove broad-scope triage heuristics and UI advisory chips/b
Removes the broad-scope detection feature end-to-end: the TaskCard chip and TaskDetailModal advisory banner are gone from the dashboard, the triage heuristic that flagged tasks as broad-scope has been deleted from the engine along with its associated run-audit events, and documentation references ha

Fusion-Task-Id: FN-5405
2026-05-21 15:07:15 -07:00
Fusion (runfusion.ai)
5a76a89071 feat(FN-5351): add merge audit telemetry with typed events and integration
FN-5351 adds structured telemetry for merge audit events and integration worktree state, including typed ref-advance tracking, terminal handoff fallback audit, and integration state probes with corresponding reliability backstop tests and documentation updates.

Fusion-Task-Id: FN-5351
2026-05-21 14:34:59 -07:00
Fusion (runfusion.ai)
caeb6a7e00 feat(FN-5350): switch merge integration advance to ref-only git update-ref
Implements ref-only integration branch advancement via `git update-ref` instead of checkout+commit, including a new `merger-ref-update-advance.ts` helper, a reduced and clarified `merger.ts`, comprehensive unit and real-git regression coverage, and audit event wiring.

Fusion-Task-Id: FN-5350
2026-05-21 13:56:27 -07:00
Fusion (runfusion.ai)
0c2416903f feat(FN-5363): enforce strict target lease to prevent merge queue pollution
Enforces strict target-lease behavior on merge queue rows, gates and scrubs polluted entries, enriches no-lease handoff diagnostics, and adds regression tests covering leased-target no-lease and polluted queue reuse paths, with audit registration and docs updates.

Fusion-Task-Id: FN-5363
2026-05-21 13:40:25 -07:00
Fusion (runfusion.ai)
b3f995c857 feat(FN-5348): remove cwd-main integration mode fallback
Removes the `cwd-main` integration fallback mode (FN-5348), eliminating the legacy shortcut path where the merger would operate directly on the project root instead of a dedicated worktree. Steps normalize the `reuse-task-worktree` integration mode as the sole path, wire stricter mode invariants in

Fusion-Task-Id: FN-5348
2026-05-21 12:49:50 -07:00
Fusion (runfusion.ai)
79850b233f feat(FN-5349): add integration branch resolver with auto-recovery fallback
FN-5349 adds a dedicated integration branch resolution module (`packages/engine/src/integration-branch.ts`) replacing ad-hoc dynamic fallbacks, routes merger branch conflict resolution through it, wires auto-recovery handlers (branch-worktree, contamination) to use integration branch fallback, and w

Fusion-Task-Id: FN-5349
2026-05-21 12:04:58 -07:00
Fusion (runfusion.ai)
e0d8600ae6 feat(FN-5434): silence queued-status stale-clear branch in self-healing
Fixes a stale queued-status recovery branch in self-healing and updates the corresponding test assertions to match the corrected behavior.

Fusion-Task-Id: FN-5434
2026-05-21 11:13:39 -07:00
gsxdsm
933cea434a feat(FN-5256): merge fusion/fn-5256 2026-05-21 11:06:26 -07:00
Fusion (runfusion.ai)
a2a643844d feat(FN-5436): skip step retries when review is pending
Added executor logic to skip retries when a review is pending for a task, introducing a `pendingReviewBlockHelper` in the task-done path and updating the retry-gate to consult it; two new reliability-interaction test suites cover the feature behavior and composition with existing retry/backstop laye

Fusion-Task-Id: FN-5436
2026-05-21 10:58:28 -07:00
gsxdsm
7d25d98b2f fix(FN-5256): await disposal across task:moved-away and task:deleted
Close the last fire-and-forget gap from the previous fixes: the task:moved
(away from in-progress) and task:deleted listeners no longer call the
synchronous fire-and-forget `abortInFlightTaskWork`. Instead they track an
awaited disposal promise per task in `pendingTaskDisposals`. The task:moved
(to in-progress) dispatch path awaits any in-flight disposal for the same
task before calling `execute()`, so a fast bounce (in-progress → todo →
in-progress) no longer races the conflict-cleanup path against a still-live
shell.

`awaitAbortInFlightTaskWork` now claims each session surface (activeSessions,
activeStepExecutors, activeWorkflowStepSessions, activeSubagentSessions)
synchronously before awaiting any async abort. This lets concurrent disposal
calls for the same task dedupe naturally — the second call finds the maps
empty and no-ops, preserving the existing single-abort/single-dispose
contract that the soft-delete and user-cancel tests assert.

Adds a regression test in executor-user-cancel covering the re-dispatch
ordering: an immediate task:moved-to-in-progress that follows a still-running
task:moved-away must wait for abort to complete before execute() runs.

The legacy `abortInFlightTaskWork` is removed (no callers).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:14:38 -07:00
gsxdsm
b4fc54bb20 fix(FN-5256): route merger-handoff reconcile through hardened gates
Code-review follow-up to cf0101be7. The merger integration worktree path
was still calling bare `activeSessionRegistry.reconcileStaleSelfOwned` for
same-task entries, bypassing the minIdleMs window introduced by the main
fix. A merger-handoff that races a warming-down session could clear a
registry entry < 5s old. Route through `reconcileSelfOwnedActiveSessionForRemoval`
with the `executingTaskLock` process probe so all reconcile sites enforce
the same liveness contract. Test updated to backdate `registeredAt`,
matching the pattern used for the other reliability-interactions tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 09:17:54 -07:00
gsxdsm
cf0101be7c fix(FN-5256): keep live task worktrees through pause/resume races
Three independent reliability fixes that all surfaced as the same bug:
live tasks losing their worktrees mid-execution and emitting
`wrong_toplevel` errors.

Fix A — executor stale-self-owned classifier:
`reconcileSelfOwnedActiveSessionForRemoval` now takes a process-active
probe (`executingTaskLock.has`) and a minimum-idle window (default 5s)
in addition to the existing in-memory `activeWorktrees` binding probe.
Recently-registered or still-running entries are refused with
`process-active-refuses` / `too-recent-refuses`, with audit-grade
log lines. Both the pre-remove path
(`reconcileSelfOwnedBeforeRemove`), the post-throw retry in
`removeOwnWorktreeWithReconcile`, and the defensive reconcile in
`removeWorktree` route through the same hardened gates.

Fix B — pause synchronously reaps the agent session:
New `awaitAbortInFlightTaskWork` mirrors the existing fire-and-forget
abort but awaits each `session.abort()` /
`stepExecutor.terminateAllSessions()` /
`workflowSession.abort()`. `parkTaskAfterWorkflowStepPause` calls it
before `moveTask("todo")`, and the `task:updated` user-pause handler
routes through it, so a fast re-dispatch can no longer race a still-
live shell.

Fix C — self-healing realpath + active-task skip:
`reconcileTaskWorktreeMetadata` now realpath-normalizes both sides of
the registry comparison (handling macOS `/private/var/...`) and
refuses to clear `worktree`/`branch` on in-progress or in-review
tasks. The skip emits a new
`task:auto-recover-worktree-metadata-skipped-active` audit event;
executor-level recovery paths remain in charge of active tasks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 09:06:23 -07:00
Fusion (runfusion.ai)
ef5dd7ba25 feat(FN-5435): reset fallback retry counter on success in reviewer
Adds a fallback retry counter to the reviewer that resets on successful step completion, preventing premature escalation when earlier steps exhaust retries while later ones succeed; also aligns dashboard trace buffer types and adds comprehensive coverage for the reset semantics.

Fusion-Task-Id: FN-5435
2026-05-21 08:43:57 -07:00
Fusion (runfusion.ai)
f236dc3982 feat(FN-5433): suppress no-op blockedBy refresh in self-healing
Fixed self-healing to suppress unnecessary blocked-by refreshes when there are no changes (no-op), preventing spurious requeues. Added a regression test covering this scenario in the self-healing test suite.

Fusion-Task-Id: FN-5433
2026-05-21 07:59:46 -07:00
Fusion (runfusion.ai)
5f9f777630 feat(FN-5374): raise room transcript defaults and align compaction settings
Raised room transcript defaults (`messagesBefore` and `daysBefore`) in the core settings schema and updated project-level setting defaults, with corresponding documentation refresh in the settings reference. Added full test coverage for room compaction defaults, pinned room default settings in Setti

Fusion-Task-Id: FN-5374
2026-05-21 07:05:48 -07:00
gsxdsm
ad8fa7be0d Merge commit '6fdfb1ad5cedc12afec1300d39a9a1d445d7b6f7' 2026-05-21 00:17:33 -07:00
Fusion (runfusion.ai)
6fdfb1ad5c feat(FN-5425): add coordination notice system for multi-agent room task fil
Adds a `room-coordination.ts` helper module for multi-agent coordination messaging, wires coordination notices into the agent heartbeat path, and ships tests plus documentation for the feature. A changeset prepares the `@runfusion/fusion` package for release.

Fusion-Task-Id: FN-5425
2026-05-21 00:17:33 -07:00
Fusion (runfusion.ai)
59bebf0806 feat(FN-5430): gate task update invalidation in scheduler
Scheduler now gates task update invalidation, preventing spurious invalidations when engine lifecycle changes (soft-delete, lease recovery) touch task metadata, with coverage via new scheduler invalidation tests and a small dashboard server test adjustment.

Fusion-Task-Id: FN-5430
2026-05-20 23:48:57 -07:00
Fusion (runfusion.ai)
f798378693 feat(FN-5346): add post-completion defensive backstop and shared reconcile
The merge adds a post-completion defensive backstop that probes and removes stale same-task `activeSessionRegistry` entries on `done`/`archived` transitions, completing FN-5346 with a shared reconcile helper, a defensive ownership probe wired into paused cleanup, audit event alignment, and regressio

Fusion-Task-Id: FN-5346
2026-05-20 21:53:02 -07:00
gsxdsm
b936ab9bb5 feat(FN-5414): merge fusion/fn-5414 2026-05-20 20:15:43 -07:00
Fusion (runfusion.ai)
2baaad743a feat(FN-5407): add paired central backup support to backup command and stor
FN-5407 adds paired central backup support to the Fusion task management system, with both the core backup engine and CLI commands updated to handle central database backup pairs. Documentation was updated to reflect the new capability, and two stabilization fixes were included to handle central bac

Fusion-Task-Id: FN-5407
2026-05-20 20:05:08 -07:00
Fusion (runfusion.ai)
1a5aff9c44 feat(FN-5337): remove speculative orphan requeue from self-healing sweep
Removes the speculative orphan requeue mutation path from self-healing, replacing it with an observation-only sweep that no longer attempts to re-enqueue orphaned tasks — a conservative regression that eliminates noisy false-positive recovery attempts. The change includes rewritten unit coverage, a

Fusion-Task-Id: FN-5337
2026-05-20 18:49:38 -07:00
Fusion (runfusion.ai)
e814ba9508 fix(FN-5345): address third-pass review findings
Follow-up to c64884c24 addressing three review findings, including one
real interaction bug caught by a new test.

MEDIUM

- Re-indented and rewrote 'if (directReuseEligible) try { ... } catch'
  as 'if (directReuseEligible) { try { ... } catch { ... } }' with the
  whole body at one consistent indent level. No behavior change \u2014 fixes
  the mismatched indentation from c64884c24 where the body sat one level
  deeper than its containing block.

LOW

- Two new backstop tests in merge-reuse-task-worktree.test.ts:
  * 'preserves worktrees with uncommitted tracked changes' \u2014 asserts the
    fast-path leaves a tracked-dirty worktree alone (result.worktreeRemoved
    is false, dir still exists). Without this, a future refactor could
    silently re-enable destructive cleanup.
  * 'cleans up worktrees with only untracked noise' \u2014 asserts untracked
    junk (.DS_Store, editor swap files) does NOT block cleanup. Also caught
    a real interaction bug: 'git worktree remove' without --force refuses
    on untracked files, so the LOW finding's intent (drop noise, preserve
    tracked dirt) needs --force on the removal call. Restored --force with
    a comment explaining why it's safe (the tracked-only dirty check above
    already refused if there was real work to preserve).

- Switched 'git status' check from '--untracked-files=normal' to
  '--untracked-files=no'. Tracked modifications and staged changes still
  block cleanup; untracked junk is correctly ignored. Dirty-skip warn log
  now includes the first 5 dirty paths for operator diagnosability.

Tests
  - Full @fusion/engine suite: 448 files / 5883 tests / 9 skipped, all green
  - pnpm lint green, pnpm build green
2026-05-20 18:21:14 -07:00
Fusion (runfusion.ai)
c64884c24a 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
2026-05-20 18:06:02 -07:00
Fusion (runfusion.ai)
8e67404680 fix(FN-5345): address code-review findings on engine fixes
Follow-up to 1983dac6e addressing nine findings from a code review of the
FN-5345/FN-5377 engine fixes. Includes a real bug fix (commit-message bypass
of the amend detection), two reliability invariant restorations (FN-4811 +
FN-4954 in the new D3 reuse-fallback path), a resource-leak cleanup, plus
test/audit/taxonomy polish.

HIGH

- D3 reuse-fallback now respects FN-4811 active-session safety: matches whose
  path is currently owned by a different task in activeSessionRegistry are
  skipped, never silently rebound. Skipped owners are recorded in audit
  metadata for forensics.
- D3 reuse-fallback now respects FN-4954 pool-lease bookkeeping: when
  recycleWorktrees=true AND a worktree pool is attached, the direct-reuse
  shortcut is bypassed and the existing acquireTaskWorktree path is used so
  WorktreePool.acquire/.release stays consistent. Without this guard the
  new path could trip PoolDoubleLeaseError.
- prepare-commit-msg amend detection tokenizes the parent command line and
  stops at the first message-supplying flag (-m/-F/--message/--file/=variants)
  so a commit message containing the substring '--amend' cannot bypass the
  guard. New regression test in prepare-commit-msg-empty-guard.real-git.test.ts.

MEDIUM

- Early empty-own-diff fast-path extracted into tryEarlyEmptyOwnDiffFinalize()
  helper. Removes the exception-as-control-flow sentinel ('skip-early-fast-path:
  not-reuse-mode') in favor of a plain if (eligible) { try { ... } catch {} }
  block.
- Fast-path best-effort cleans up the stranded fusion/<id> worktree and branch
  before completeTask(), so empty-own-diff residuals do not accumulate in
  .worktrees/ or the branch namespace. FN-4811 guard ensures we never remove
  a foreign-owned worktree.
- Two new audit subtypes in run-audit.ts replace the prior overloading of
  merge:reuse-fallback-new-worktree:
    - merge:reuse-fallback-pruned-stale-registration
    - merge:reuse-fallback-reused-existing-registration
  merge:reuse-fallback-new-worktree is now reserved for actual new-worktree
  creation. Local emitReuseHandoffAuditEvent type union updated to match.
- New direct classifier test in merger-finalize-unproven.real-git.test.ts
  ('classifies proven-no-op for empty-own-diff branches') covers the new
  branch in classifyOwnedLandedEvidence that self-healing and post-handoff
  paths also depend on.

LOW

- Alpine/busybox ps fallback: prepare-commit-msg hook reads /proc/$PPID/cmdline
  if 'ps -o args=' returns empty (busybox ps often lacks '-o args=' support).
- New backstop test variant 'FN-5345: empty-own-diff fast-path fires even
  when branch is registered to two worktrees' reproduces the actual FN-5345
  production wedge geometry where fusion/<id> was double-registered to two
  worktrees.

Tests
  - Full @fusion/engine suite: 448 files / 5881 tests / 9 skipped, all green
  - pnpm lint green, pnpm build green
2026-05-20 17:54:26 -07:00
Fusion (runfusion.ai)
1983dac6e4 fix(FN-5345): refuse empty commits + early empty-own-diff finalize
Three engine-level fixes for the in-review wedge class identified via FN-5345
(verification-only task with empty handoff commit + drifted worktree mapping
escalating to 'merge-deadlock-detected: verified content not on main' after
FN-4999 completion-handoff-limbo recovery exhausts).

D1 — prepare-commit-msg empty-commit guard
  Fusion task worktrees install a prepare-commit-msg hook that refuses
  'git commit --allow-empty' and other zero-staged-diff commits. Amend
  (detected via $2==commit source arg or '--amend' in 'ps -o args= -p $PPID')
  and merge/squash/cherry-pick/revert/rebase ceremonies are allowed.

D5 — early empty-own-diff fast-path in aiMergeTask
  In reuse-task-worktree integration mode, BEFORE any reuse-handoff acquisition,
  detect branches with own_commit_count >= 1 but zero net diff vs merge-base
  (git diff --quiet <mergeBase>..<branch>) and finalize as no-op with
  mergeDetails.noOpMerge=true + task:auto-recover-finalize-already-on-main
  audit (reason: empty-own-diff-early-fast-path). cwd-main integration mode
  is unchanged. classifyOwnedLandedEvidence also detects empty-own-diff so
  self-healing and post-handoff finalize paths benefit too.

D3 — reuse-fallback consults existing branch registration
  Before creating a fresh worktree in merger's reacquireReuseIntegrationWorktree,
  consult 'git worktree list --porcelain' for existing registrations of
  fusion/<id>. Reuse extant usable registrations directly. Prune stale
  registrations first. Eliminates FN-5083-class double-registration where
  'git worktree add -f' on an already-registered branch produced two worktrees
  both claiming the branch and wedged the next handoff gate.

Tests
  - New real-git backstop: prepare-commit-msg-empty-guard.real-git.test.ts
  - New reliability interaction backstop in merge-reuse-task-worktree.test.ts
    ('FN-5345: empty-own-diff branch auto-finalizes via early fast-path')
  - commit-msg-trailer.real-git.test.ts updated to use real commits (it was
    relying on --allow-empty, which the new guard now refuses)
  - Full @fusion/engine suite: 448 files / 5879 tests / 9 skipped, all green
  - pnpm lint green, pnpm build green
2026-05-20 17:31:48 -07:00
Fusion (runfusion.ai)
fd202e9356 feat(FN-5329): remove orphan rescue and branch-recovery primitives from eng
Removes the branch-recovery CLI surface, orphan-rescue engine primitives, and their associated tests (over 1,500 lines deleted), while restoring a minimal prune-only orphan branch sweep with proper git audit mutation types. Documentation across `cli-reference.md`, `task-management.md`, and `AGENTS.m

Fusion-Task-Id: FN-5329
2026-05-20 16:43:27 -07:00
Fusion (runfusion.ai)
b06cf64cd4 feat(FN-5321): add evidence gap detector for external integration manifests
Implements external integration validation (FN-5321) with a manifest validator scaffold, worktrunk manifest wiring, and an evidence gap detector that runs during spec validation and triage; the reviewer also gates on external integration readiness. Includes tests for manifest, evidence gap, and tria

Fusion-Task-Id: FN-5321
2026-05-20 15:54:44 -07:00
Fusion (runfusion.ai)
c60045df22 feat(FN-5223): anchor staleness and stall detectors to engine activation ti
The merge introduces an engine-activation timestamp as the staleness floor for task age calculations, replacing arbitrary wall-clock thresholds with a runtime-relative anchor. Step 1 adds settings defaults, Steps 2–4 wire the floor helper through project engine, in-process runtime, and task store hy

Fusion-Task-Id: FN-5223
2026-05-20 14:29:07 -07:00
Fusion (runfusion.ai)
62f11e69d3 feat(FN-5325): priority-aware overlap deferral and merge integration worktr
The merge delivers several meaningful features and fixes: a **priority-aware overlap deferral fix** (FN-5325) in the scheduler that aligns the queued-overlap helper with the priority-sortable type, preventing inversion; a **merge integration worktree feature** (FN-5279) with settings UI, reusable wo

Fusion-Task-Id: FN-5325
2026-05-20 14:28:45 -07:00
Fusion (runfusion.ai)
8f2d5e7e61 feat(FN-5220): guard explicit duplicate markers in triage and self-healing
Adds an explicit duplicate-marker guard (FN-5220) spanning core helper, dashboard API endpoint, triage short-circuit, and self-healing sweep to detect and handle duplicate task creation attempts; includes comprehensive test coverage across unit, API, and integration layers plus documentation.

Fusion-Task-Id: FN-5220
2026-05-20 14:28:45 -07:00
Fusion (runfusion.ai)
6fb4b9ee47 feat(FN-5362): add heartbeat executor sparse-cache reports-health diagnosti
The merge fixes a stale cache-miss path in the heartbeat executor and adds `reports-health` diagnostics for cache-state reporting, with a regression test covering a sparse-cache false-positive scenario. It also adds a two-line tweak to the merger and updates the diagnostics documentation.

Fusion-Task-Id: FN-5362
2026-05-20 14:28:45 -07:00
gsxdsm
c824810181 fix(FN-5279): apply reuse-mode squash to local main and guard executor-lease race
In reuse-task-worktree mode the merger detaches HEAD in the task worktree so
the squash commit lands on detached HEAD; nothing previously advanced the
project root's local integration branch, so changes never appeared on main.
Step 5c now applies the squash to projectRootDir via git merge --ff-only,
falling back to a regular merge with AI conflict resolution if main has
diverged. pushAfterMerge (when enabled) now runs from projectRootDir where
the branch was just advanced, so parsePushRemoteTarget can resolve a branch
instead of failing on the worktree's detached HEAD.

Also tightens acquireReuseHandoff: the executor-lease check above the
queue-lease acquisition was non-atomic, letting a local executor grab the
task between checks. Re-check after acquisition and release the queue
lease with a precise diagnostic instead of proceeding into a generic
failure later.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:28:19 -07:00
gsxdsm
d6196a8665 fix(FN-5363): implement targetTaskId in store SQL so lease targets correct task
The previous commit wired targetTaskId through the engine caller but the
store's acquireMergeQueueLease SQL still grabbed the queue head unconditionally,
leaving the no-lease loop intact. This lands the store-side change: when
targetTaskId is provided it attempts a direct-match UPDATE first; only falls
back to queue-head ordering if that row isn't available (backward-compatible).

Adds regression test covering the polluted-queue-head scenario (FN-5363).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 12:05:41 -07:00
gsxdsm
b8918b83b0 fix(FN-5363): target mergeQueue lease to specific task ID instead of queue head
The merge handoff path in acquireReuseHandoff called acquireMergeQueueLease
without a targetTaskId, which grabbed the priority/FIFO-sorted queue head
instead of the specific in-review task. When the queue head was a different
task (e.g. a polluted non-review entry), the returned lease had a mismatched
taskId and triggered 'no-lease' for every in-review task.

Fix:
- Pass targetTaskId: input.task.id to acquireMergeQueueLease so the merge
  lane targets its specific task instead of grabbing the queue head.
  MergeQueueAcquireOptions.targetTaskId is already wired in store.ts.
- Replace the broken typeof check (typeof object !== 'object' is always false
  for plain JSON objects returned by RETURNING *) with a proper 'taskId' in
  lease guard.
- Add acquiredTaskId to the no-lease error payload for better observability.

Reliability backstop: merge-reuse-task-worktree.test.ts guards this path.

Fixes: FN-5363
2026-05-20 12:02:05 -07:00
gsxdsm
480db25de0 fix(FN-5353): remove stale merge:reuse-fallback-cwd-main type entries
The behavioral cwd-main fallback is gone (fresh-acquire on refusal
replaces it), but the type string was left as a dead entry in the
emitReuseHandoffAuditEvent union (merger.ts) and the
DatabaseMutationType union (run-audit.ts). Remove both so the dead
string cannot be accidentally reintroduced.
2026-05-20 10:58:29 -07:00
gsxdsm
1b7f492227 feat(FN-5353): wire fresh-worktree-acquire to ActivityLogModal 2026-05-20 10:58:29 -07:00
gsxdsm
7df11bc2cf fix(FN-5353): reacquire fresh worktree when reuse handoff fails instead of falling back to main
Before: when reuse-task-worktree was configured but task worktree was missing/unusable,
merger fell back to cwd-main, losing the task worktree isolation benefit.

After: merger creates a fresh worktree for the task branch inline (using the standard
git worktree add pattern with identity guard installation) and retries the reuse handoff.
Only falls back to cwd-main if fresh acquisition also fails.

Three new audit events track the recovery path:
- merge:reuse-worktree-fresh-acquire — fresh acquisition started
- merge:reuse-worktree-fresh-acquired — fresh worktree created and bound to task
- merge:reuse-fallback-cwd-main — only when fresh acquisition itself fails (last resort)

Behavior:
- Missing/unusable task worktree → fresh worktree created, merge continues from it
- Fresh acquisition fails → cwd-main fallback (last resort, fully audited)
- Genuine liveness conflict (usable worktree but lease refused) → re-thrown, not masked

Regression test covers the missing-worktree case: verifies fresh acquisition + handoff
succeeds without any cwd-main fallback event.
2026-05-20 10:58:29 -07:00
gsxdsm
6d66559eb3 fix(FN-5353): reacquire fresh worktree on reuse-handoff refusal
After merge:reuse-handoff-refused with no usable task worktree:
- Acquire a fresh worktree and restore the fusion/<task-id> branch
  from baseCommitSha before continuing merge
- Hard-fail only if fresh acquisition itself fails (not cwd-main fallback)
- Emit merge:reuse-worktree-fresh-acquire / merge:reuse-worktree-fresh-acquired
  audit events around the acquisition lifecycle

Replaces the incorrect cwd-main fallback (499784581) with correct
reacquire path. Updates regression test in merge-reuse-task-worktree.test.ts
to assert fresh-acquire audit trail instead of cwd-main fallback.

Refs: FN-5353
2026-05-20 10:47:35 -07:00
gsxdsm
a03a5de235 fix(FN-5353): re-acquire fresh task worktree instead of cwd-main fallback
When mergeIntegrationWorktree=reuse-task-worktree but the task has no
worktree or the worktree classifies as unusable, the merger now:
1. Creates a fresh worktree at the standard path with the fusion/<id> branch
2. Installs identity-guard hooks
3. Updates task.worktree + task.branch in the store
4. Emits merge:reuse-worktree-fresh-acquire / merge:reuse-worktree-fresh-acquired
5. Retries the handoff from the new worktree

Only falls back to cwd-main as last resort when fresh acquisition also
fails. Lease/liveness conflicts (worktree exists and classifies OK but
handoff refused on active-session or lease grounds) are re-thrown — not
masked with cwd-main.

New audit event types: merge:reuse-worktree-fresh-acquire,
merge:reuse-worktree-fresh-acquired
2026-05-20 10:46:33 -07:00