Commit Graph

6447 Commits

Author SHA1 Message Date
Fusion (runfusion.ai)
27dd927213 feat(FN-4830): complete Steps 4-7 stale lock recovery delivery
Fusion-Task-Id: FN-4830
Fusion-Task-Lineage: d9b8ad72-669f-488e-8e85-be2dce9b8341
2026-05-16 20:54:39 -07:00
Fusion (runfusion.ai)
161cb565e6 feat(FN-4830): complete Step 3 — executor stale-lock recovery
Fusion-Task-Id: FN-4830
Fusion-Task-Lineage: d9b8ad72-669f-488e-8e85-be2dce9b8341
2026-05-16 20:54:34 -07:00
Fusion (runfusion.ai)
753068482e feat(FN-4830): complete Step 2 — backend stale-lock recovery
Fusion-Task-Id: FN-4830
Fusion-Task-Lineage: d9b8ad72-669f-488e-8e85-be2dce9b8341
2026-05-16 20:54:33 -07:00
Fusion (runfusion.ai)
9e2a2e37d0 feat(FN-4830): complete Step 1 — add stale lock helper
Fusion-Task-Id: FN-4830
Fusion-Task-Lineage: d9b8ad72-669f-488e-8e85-be2dce9b8341
2026-05-16 20:54:33 -07:00
Fusion (runfusion.ai)
a11bd0719e feat(FN-4822): complete Step 8 — document central claim authority
Fusion-Task-Id: FN-4822
Fusion-Task-Lineage: 08cc29e8-114a-48dc-80de-8d7fd2ce0e69
2026-05-16 20:48:00 -07:00
Fusion (runfusion.ai)
199f317813 feat(FN-4822): complete Step 6 — enforce central-claim race coverage
Fusion-Task-Id: FN-4822
Fusion-Task-Lineage: 08cc29e8-114a-48dc-80de-8d7fd2ce0e69
2026-05-16 20:48:00 -07:00
Fusion (runfusion.ai)
ad4b236985 test(FN-4822): complete Step 5 — add cross-node claim mutex integration race test
Fusion-Task-Id: FN-4822
Fusion-Task-Lineage: 08cc29e8-114a-48dc-80de-8d7fd2ce0e69
2026-05-16 20:48:00 -07:00
Fusion (runfusion.ai)
3190eac88b test(FN-4822): complete Step 4 — add AgentStore central-claim wiring tests
Fusion-Task-Id: FN-4822
Fusion-Task-Lineage: 08cc29e8-114a-48dc-80de-8d7fd2ce0e69
2026-05-16 20:48:00 -07:00
Fusion (runfusion.ai)
9d862d17a5 feat(FN-4822): complete Step 1 — add central task claim schema and API
Fusion-Task-Id: FN-4822
Fusion-Task-Lineage: 08cc29e8-114a-48dc-80de-8d7fd2ce0e69
2026-05-16 20:48:00 -07:00
Fusion (runfusion.ai)
bb9e93faba fix(FN-4818): align owning-node interaction assertions with landed behavior
Fusion-Task-Id: FN-4818
Fusion-Task-Lineage: 1619844a-3945-4681-af58-ca32e5533514
2026-05-16 20:27:40 -07:00
Fusion (runfusion.ai)
5c5b922d79 test(FN-4818): complete Step 2 — add owning-node handoff interaction coverage
Fusion-Task-Id: FN-4818
Fusion-Task-Lineage: 1619844a-3945-4681-af58-ca32e5533514
2026-05-16 20:27:40 -07:00
Fusion (runfusion.ai)
003b343b4e test(FN-4818): complete Step 1 — add claim mutex interaction coverage
Fusion-Task-Id: FN-4818
Fusion-Task-Lineage: 1619844a-3945-4681-af58-ca32e5533514
2026-05-16 20:27:40 -07:00
Fusion (runfusion.ai)
2617ae659f test(FN-4818): complete Step 1 — add multi-node claim mutex interaction coverage
Fusion-Task-Id: FN-4818
Fusion-Task-Lineage: 1619844a-3945-4681-af58-ca32e5533514
2026-05-16 20:27:39 -07:00
gsxdsm
4d5e296049 feat(FN-4801): merge fusion/fn-4801 2026-05-16 20:13:30 -07:00
Fusion (runfusion.ai)
9a249dfe2b fix(FN-4789): avoid bundling optional keytar native module
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:48 -07:00
Fusion (runfusion.ai)
937bed90b9 feat(FN-4789): complete Step 6 — changeset and resolver polish
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:48 -07:00
Fusion (runfusion.ai)
90cd39ebd2 feat(FN-4789): complete Step 2 — export manager and add optional keytar
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:48 -07:00
Fusion (runfusion.ai)
1a527fa753 fix(FN-4789): harden rotation semantics for active backend
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:47 -07:00
Fusion (runfusion.ai)
10e44eda3a feat(FN-4789): complete Step 1 — implement master key resolver
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:47 -07:00
Fusion (runfusion.ai)
e49c41185b test(FN-4789): add initial master key manager tests
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:47 -07:00
Fusion (runfusion.ai)
ff5f24f5e9 feat(FN-4789): complete Step 1 — implement master key manager
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:47 -07:00
Fusion (runfusion.ai)
338b1940f6 feat(FN-4810): complete Step 6 — finalize truncation docs and changeset
Fusion-Task-Id: FN-4810
Fusion-Task-Lineage: b7080f83-96b0-4106-9742-e14b20afeab1
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:47 -07:00
Fusion (runfusion.ai)
c3d1f7a95c feat(FN-4810): complete Step 3 — update scope-leak truncation docs
Fusion-Task-Id: FN-4810
Fusion-Task-Lineage: b7080f83-96b0-4106-9742-e14b20afeab1
Fusion-Task-Id: FN-4789
Fusion-Task-Lineage: cef0d12e-556e-43d8-9ce0-e4962c2d091b
2026-05-16 20:06:46 -07:00
Fusion (runfusion.ai)
1c7d49c5eb test(FN-4827): recover FN-4774 triage duplicate-detection regression block (orphan fusion/fn-4817; supersedes FN-4815) 2026-05-16 20:02:35 -07:00
Fusion (runfusion.ai)
8e3a635d3d feat(FN-4825): complete Step 4 — add changeset for node-unreachable audits
Fusion-Task-Id: FN-4825
Fusion-Task-Lineage: dc4e633e-fe46-47a8-9ecc-f032073caee9
2026-05-16 19:58:46 -07:00
Fusion (runfusion.ai)
14cf263bc6 feat(FN-4825): complete Step 3 — add scheduler unreachable-owner audits
Fusion-Task-Id: FN-4825
Fusion-Task-Lineage: dc4e633e-fe46-47a8-9ecc-f032073caee9
2026-05-16 19:58:44 -07:00
Fusion (runfusion.ai)
ee121a9f79 feat(FN-4825): complete Step 2 — emit mesh lease unreachable-owner audits
Fusion-Task-Id: FN-4825
Fusion-Task-Lineage: dc4e633e-fe46-47a8-9ecc-f032073caee9
2026-05-16 19:58:44 -07:00
Fusion (runfusion.ai)
2db5c10f07 feat(FN-4825): complete Step 1 — extend run-audit taxonomy
Fusion-Task-Id: FN-4825
Fusion-Task-Lineage: dc4e633e-fe46-47a8-9ecc-f032073caee9
2026-05-16 19:58:44 -07:00
Fusion (runfusion.ai)
cb9f4e4cd7 docs(FN-4814): complete Step 3 — wire readiness brief into docs
Fusion-Task-Id: FN-4814
Fusion-Task-Lineage: f73b5fce-6c97-4ba3-b7ae-81d85abf4834
2026-05-16 19:23:07 -07:00
Fusion (runfusion.ai)
2a8e3e5f0c fix(FN-4812): stabilize hoisted update-cache test fixture
Fusion-Task-Id: FN-4812
Fusion-Task-Lineage: 9877a784-5320-410c-82fa-3f6a6d9b5358
2026-05-16 19:16:48 -07:00
Fusion (runfusion.ai)
ec8d1f5246 test(FN-4812): assert mobile FileMentionPopup anchoring rule
Fusion-Task-Id: FN-4812
Fusion-Task-Lineage: 9877a784-5320-410c-82fa-3f6a6d9b5358
2026-05-16 19:16:48 -07:00
Fusion (runfusion.ai)
02713ee45e fix(FN-4812): anchor FileMentionPopup above input on mobile
Fusion-Task-Id: FN-4812
Fusion-Task-Lineage: 9877a784-5320-410c-82fa-3f6a6d9b5358
2026-05-16 19:16:47 -07:00
Fusion (runfusion.ai)
7cd5554641 feat(FN-4810): complete Step 6 — finalize truncation docs and changeset
Fusion-Task-Id: FN-4810
Fusion-Task-Lineage: b7080f83-96b0-4106-9742-e14b20afeab1
2026-05-16 18:57:58 -07:00
Fusion (runfusion.ai)
bd1c585b05 feat(FN-4810): complete Step 3 — update scope-leak truncation docs
Fusion-Task-Id: FN-4810
Fusion-Task-Lineage: b7080f83-96b0-4106-9742-e14b20afeab1
2026-05-16 18:57:58 -07:00
Fusion (runfusion.ai)
e68b448ce3 feat(FN-4810): complete Step 4 — document scope-leak truncation
Fusion-Task-Id: FN-4810
Fusion-Task-Lineage: b7080f83-96b0-4106-9742-e14b20afeab1
2026-05-16 18:57:58 -07:00
Fusion (runfusion.ai)
ea6501bed7 test(FN-4810): complete Step 2 — cover truncation behavior
Fusion-Task-Id: FN-4810
Fusion-Task-Lineage: b7080f83-96b0-4106-9742-e14b20afeab1
2026-05-16 18:57:58 -07:00
Fusion (runfusion.ai)
af4607ed54 feat(FN-4810): complete Step 1 — truncate scope-leak log rendering
Fusion-Task-Id: FN-4810
Fusion-Task-Lineage: b7080f83-96b0-4106-9742-e14b20afeab1
2026-05-16 18:57:58 -07:00
Fusion
8bef30655d fix(FN-4811): close concurrent-execute race that produced parallel runs
TaskExecutor.execute() had a classic JS async race window. Original:

  async execute(task) {
    if (this.executing.has(task.id)) return;                       // check
    const assignedAgentId = task.assignedAgentId;
    if (assignedAgentId && await this.shouldDeferForHeartbeat(...)) // AWAIT yields
      return;
    this.executing.add(task.id);                                   // add (too late)
    ...
  }

Two concurrent execute(task) calls (scheduler dispatch + task:moved event
handler + restart-recovery) both:
  1. Pass the synchronous has() check (Set is empty).
  2. Enter the awaited shouldDeferForHeartbeat call (yields the event loop).
  3. Resume and both call this.executing.add(task.id).
  4. Both proceed to create the same worktree path.

Production failure shape (FN-4814 + FN-4811, observed within minutes):

  01:30:56  [runA-caoe]  Worktree created at /...worktrees/bright-mesa
  01:30:56  [runB-w23q]  Worktree created at /...worktrees/bright-mesa
  01:30:58              worktree liveness assertion failed: not_usable_task_worktree
  01:31:48              [thirdRun] also fires liveness assertion fail
  01:37:48              In-review stall surfaced [no-worktree-no-merge-confirmed]

This is the root cause of the entire FN-4781/FN-4804/FN-4814/FN-4811
cascade. Every other guard added today (FN-4811 active-session gate,
self-healing reclaim defer, validation-failed recovery, silent reclaim
recovery, integrity-warning dedup) was patching SYMPTOMS of the
duplicate-run race. With this fix, the symptoms stop appearing.

Fix: claim the slot synchronously immediately after the has() check,
release it on the heartbeat-defer early-return path. No await happens
between check and claim, so the race window is closed.

Test added under
packages/engine/src/__tests__/reliability-interactions/concurrent-execute-race.test.ts
verified to fail on the prior (a1b1f9aa0) executor.ts and pass on the
fixed version:

  - Two concurrent execute() calls produce the SAME number of
    createFnAgent invocations as one execute() call (no amplification).
  - A second sequential execute() after the first completes IS allowed
    (slot was released).

The task must have assignedAgentId set to exercise the race \u2014 without
it, the short-circuit `assignedAgentId && ...` evaluates the left side
to false synchronously, and no await happens.

Full engine suite: 5048+ tests pass. The 7 transient test-file failures
in the broad parallel run are pre-existing flaky real-git tests
(branch-conflicts-zero-unique, branch-conflicts-recovery,
merger-overlap-guard subprocess-guard contention) \u2014 all of them pass
when run alone or as a smaller group, none touch the executor.execute()
path.

Fusion-Task-Id: FN-4811
2026-05-16 18:55:03 -07:00
Fusion (runfusion.ai)
7147095060 docs(FN-4820): complete Step 4 — self-review and evidence expansion
Fusion-Task-Id: FN-4820
Fusion-Task-Lineage: 8f15714c-4733-4733-8f47-a9b8738b9bcd
2026-05-16 18:51:18 -07:00
Fusion (runfusion.ai)
637d5191d3 docs(FN-4820): complete Step 3 — file prioritized follow-up tasks
Fusion-Task-Id: FN-4820
Fusion-Task-Lineage: 8f15714c-4733-4733-8f47-a9b8738b9bcd
2026-05-16 18:51:15 -07:00
Fusion (runfusion.ai)
5b2b50e916 docs(FN-4820): complete Step 2 — author findings document
Fusion-Task-Id: FN-4820
Fusion-Task-Lineage: 8f15714c-4733-4733-8f47-a9b8738b9bcd
2026-05-16 18:51:14 -07:00
Fusion (runfusion.ai)
8405e1fce6 fix(FN-4786): align dashboard activity event typings
Fusion-Task-Id: FN-4786
Fusion-Task-Lineage: eb683ec8-8b9d-4e3d-852c-7076224afa6b
2026-05-16 18:40:05 -07:00
Fusion (runfusion.ai)
4863e3be8f feat(FN-4786): complete Step 6 — document planning loading fixes
Fusion-Task-Id: FN-4786
Fusion-Task-Lineage: eb683ec8-8b9d-4e3d-852c-7076224afa6b
2026-05-16 18:40:04 -07:00
Fusion (runfusion.ai)
825e5479f5 test(FN-4786): stabilize cli tmp-dir tests for workspace runs
Fusion-Task-Id: FN-4786
Fusion-Task-Lineage: eb683ec8-8b9d-4e3d-852c-7076224afa6b
2026-05-16 18:40:04 -07:00
Fusion (runfusion.ai)
ec169bf347 test(FN-4786): complete Step 4 — add first-turn loading regressions
Fusion-Task-Id: FN-4786
Fusion-Task-Lineage: eb683ec8-8b9d-4e3d-852c-7076224afa6b
2026-05-16 18:40:04 -07:00
Fusion (runfusion.ai)
560e35708a fix(FN-4786): complete Step 3 — replay first-turn thinking catch-up
Fusion-Task-Id: FN-4786
Fusion-Task-Lineage: eb683ec8-8b9d-4e3d-852c-7076224afa6b
2026-05-16 18:40:03 -07:00
Fusion (runfusion.ai)
84f914884a feat(FN-4786): complete Step 2 — globalize spin utility
Fusion-Task-Id: FN-4786
Fusion-Task-Lineage: eb683ec8-8b9d-4e3d-852c-7076224afa6b
2026-05-16 18:40:03 -07:00
gsxdsm
591e0b9e90 feat(FN-4819): merge fusion/fn-4819 2026-05-16 18:06:12 -07:00
Fusion
a1b1f9aa05 fix(FN-4811): defer self-healing reclaim when worktree has an active session
The reclaimSelfOwnedBranchConflicts sweep was force-pausing actively-running
tasks. Production failure shape on FN-4819:

  1. Self-healing sweep runs every cycle and inspects branch conflicts.
  2. For FN-4819, inspection classified the conflict as 'tip-already-merged'
     (the task's branch tip was already on main).
  3. Sweep called removeWorktree({ reason: SelfHealingBranchConflict }).
  4. The FN-4811 active-session gate correctly refused: the worktree was
     bound to FN-4819/executor (a live agent session was using it).
  5. The thrown ActiveSessionWorktreeRemovalError was caught by the outer
     reclaim catch block.
  6. The catch escalated to AutoRecoveryDispatcher with class
     'branch-conflict-unrecoverable'.
  7. decision.action === 'pause' marked the task failed + paused +
     pausedReason='branch-conflict-unrecoverable' + moved to in-review.

Net effect: the FN-4811 gate (which is correct \u2014 you can't yank a live
worktree) became a regression source because the self-healing sweep
interpreted the refusal as fatal. Tasks that were actively making progress
got paused with a misleading 'branch conflict unrecoverable' error.

Fix: at the top of the per-task reclaim loop in
reclaimSelfOwnedBranchConflicts, check
activeSessionRegistry.isPathActive(task.worktree) and continue for any
task whose worktree is currently bound to a live session. The reclaim
will retry on the next sweep (sweeps run every cycle) once the session
has finished using the worktree. No data is lost, no decision is forced.

Test added under
packages/engine/src/__tests__/reliability-interactions/reclaim-defers-on-active-session.test.ts
covering:
  - The skip path: when activeSessionRegistry has a registration for
    task.worktree, the sweep MUST NOT call inspectBranchConflict,
    removeWorktree, or isUsableTaskWorktree. The task MUST stay in
    in-progress, not be marked failed/paused, not be moved to in-review.
  - Control: with no registration, the sweep DOES proceed and reaches
    inspectBranchConflict (preserving existing behavior).

Full engine suite: 314 files, 5061 tests pass, 1 skipped. Lint clean.
Build clean.

Fusion-Task-Id: FN-4811
2026-05-16 17:59:03 -07:00
Fusion (runfusion.ai)
4691cbe199 fix(FN-4804): sync quick chat session and room selection
- Clear the active chat room when switching Quick Chat to a direct session
- Keep the hidden session dropdown value and initial-session state aligned with room selection changes
- Add dashboard regression coverage for switching from a room back to a direct chat and include a CLI patch changeset

Fusion-Task-Id: FN-4804
2026-05-16 17:47:48 -07:00