Commit Graph

82 Commits

Author SHA1 Message Date
gsxdsm
f9f06a4fb7 engine tail: nine files to zero — incl. a census-INVISIBLE requeue into a lane that does not exist (−13) (#2797)
Follow-up to #2785. Nine engine files to **zero**, all one question —
*"is this task finished?"* — asked in nine places, wrong in every one on
a renamed board.

## Census, per file (measured, `--strict` verified)

| file | main | here |
| --- | ---: | ---: |
| `agent-reflection.ts` | 2 | **0** |
| `merger-scope-auto-widen.ts` | 2 | **0** |
| `worktree-pool.ts` | 2 | **0** |
| `cli-agent/state-machine.ts` | 2 | **0** (reclassified — see below) |
| `auto-recovery-handlers/branch-worktree.ts` | 1 | **0** |
| `cli-agent/task-session.ts` | 1 | **0** (reclassified) |
| `merger-integration-worktree.ts` | 1 | **0** |
| `merger-orphan-rehome.ts` | 1 | **0** |
| `plugin-runner.ts` | 1 | **0** |
| **net** | | **−13** |

## The one worth reading: `branch-worktree` had TWO defects, and the
census could only see one

```ts
if (task.column === "in-progress") { …clear branch… }        // counted
await this.deps.taskStore.moveTask(task.id, "todo", { … });  // INVISIBLE
```

The census scores **comparisons**. The requeue *destination* is a call
argument, so nothing in the backlog ever pointed at it — and it is the
worse of the two: a board with no `todo` column was requeued into a lane
**that does not exist**. The counted literal is the smaller half (a
renamed wip lane meant the stale branch was never cleared, so the card
carried a dead branch back into execution).

Converting the comparison alone would have dropped a census count and
left the board requeuing into nowhere. Destination now resolves through
`resolveReboundTarget` (KTD-10 ordering: hold → intake → first column).

Reverted **independently**: destination restored → 2 fail (`moveTask`
called with `"todo"`, not `"backlog"`); wip test restored → 1 fail
(`updateTask` never called).

## The rest

- **`plugin-runner`** — `onTaskCompleted` never fired on a renamed
board. Every plugin that closes an issue, posts a notification, or
records a metric on completion **silently stopped**, with nothing
logged. Resolved *asynchronously* inside the existing fire-and-forget
seam, not via `resolveTaskWorkflowIrSync` — per
`sync-workflow-ir-callsite-allowlist` that reader returns the DEFAULT
workflow for every task in production, so a sync guard here would read
as converted and still be wrong. The listener is already
`void`-dispatched, so awaiting inside it changes no observable ordering
(the shape `NotificationService` already uses).
- **`merger-orphan-rehome`** — a renamed complete lane made every source
task read as unfinished, so orphaned commits were never rehomed and
stayed stranded off the integration branch. Resolves by the **trailer
id**, not `sourceTask.id`, which the fake store does not populate.
- **`agent-reflection`** — `classifyOutcome` returned `null` for every
finished task, so both callers treated completed work as nothing to
reflect on: one recorded `reflection:skipped` with reason
`"not-completed"`, the other silently `continue`d. Reflection captured
**nothing at all** on a custom board.
- **`worktree-pool`** — shipped tasks' worktrees stayed in the ACTIVE
set, so the reclaim pass never returned them and the board walks into
worktree exhaustion — a stall whose cause is invisible from the symptom.
- **`merger-scope-auto-widen`** — finished cards counted as active
claimants, so a merge was blocked by a task that no longer exists in any
meaningful sense.
- **`merger-integration-worktree`** — a shipped task still counted as a
live worktree user, so the integration worktree could never be reused
and the merge path took the slower rebuild every time.

## The census OVERSTATED the engine backlog by 3

`cli-agent/state-machine.ts` and `cli-agent/task-session.ts` compare
against `done` — but that is a **`CliMachineState`**
(`ready`/`busy`/`waitingOnInput`/`done`/`resuming`/`idle`) tracking one
CLI agent process. It never reads a board column. The census matches the
bare string.

Marked `DELIBERATE-LITERAL` rather than left for a later sweep to
"convert" a process state into a workflow role. Worth flagging
fleet-wide: the backlog total includes at least these three non-columns.

## Revert results (measured, each run)

| conversion | reverted → |
| --- | --- |
| `plugin-runner` complete gate | RENAMED case fails — `onTaskCompleted`
never invoked |
| `merger-orphan-rehome` source gate | RENAMED case fails —
`orphan:false, reason:"source-task-not-done"` |
| `branch-worktree` destination | 2 fail — `moveTask` called with
`"todo"` |
| `branch-worktree` wip test | 1 fail — `updateTask` never called |

Each has a **non-vacuous companion** (renamed board, non-complete lane /
mid-flight source / non-wip column) so a guard that fired
unconditionally would not pass.

**Four are NOT revert-proven, and I am not claiming otherwise:**
`agent-reflection`, `merger-scope-auto-widen`,
`merger-integration-worktree`, `worktree-pool`. Their suites omit a
workflow and therefore assert the legacy fallback — they pass before and
after. `merger-scope-auto-widen` has no test file at all;
`scanIdleWorktrees` is mocked in every suite that touches it and driving
it for real needs git worktrees on disk. All four strictly **widen** the
finished set (resolved roles ∪ the legacy ids), so default boards are
byte-identical. That is the argument for shipping them, not a substitute
for coverage.

## Examined and deliberately NOT converted

- **`backlog-pressure-reporter:173`** — fed by `listTasks({ column:
"todo" })`, a hardcoded **query** filter. On a renamed board `todoFull`
is empty and the predicate never runs. Converting it drops a census
count and changes nothing observable; the fix belongs at the query
layer.
- **`auto-merge-finalization:28`** — the catch-arm legacy fallback,
which must stay for the same reason `columnRoles.ts` keeps its id
fallback.
- **`auto-merge-finalization:84`** — only selects between two diagnostic
reason strings that are **both** `ok: false`, on a pure validator with
no store in scope. Converting it would thread a store through a pure
function to change a label.

## Merge resolution note

Merging main brought conflicts in `agent-assignment.ts` and
`ephemeral-worker-manager.ts`. **Main's versions won both** and mine are
dropped: main threads an optional `activeColumns` from
`scheduler.ts:2340` (a cleaner seam than widening the store type to
resolve internally), and its `isAgentIdle` carries a greptile P1 fix
mine lacked — `columnsWithFlag` membership rather than first-per-role,
so a workflow declaring two wip lanes has both recognised. That is the
fourth time in this program main's version of a contested file was the
better one.

## Verification

- `pnpm test:gate` — 161 + 487 + 13 + 71, green
- `npx tsc -p packages/engine/tsconfig.json --noEmit` — clean
- `pnpm lint` — clean
- `--strict` exits 0


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Workflow-dependent task completion now recognizes custom lifecycle
columns, including renamed boards.
* Recovery requeues tasks to the configured destination and clears
branch details only from the appropriate work-in-progress column.
* Improved handling of completed tasks, orphaned work, shared worktrees,
and scope evaluation across custom workflows.
* Plugin completion hooks now trigger for any column configured as
complete.
* **Tests**
* Added coverage for renamed workflow columns and custom completion,
recovery, and rehoming behavior.
* **Documentation**
  * Clarified CLI state terminology in internal developer comments.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 11:28:54 -07:00
gsxdsm
90f6319b79 batch-engine tail: re-land the ASYNC half; the sync-resolved half was inert (engine −15) (#2785)
Tail of `batch-engine` (#2773). That PR merged as a squash while later
engine work was still in flight, so `self-healing.ts`, `executor.ts` and
`worktree-pool.ts` landed at their pre-conversion counts. This re-lands
**only the half that is real**, and the reason the other half is not
here is the substance of this PR.

## Census, per file (measured, `--strict` verified)

| file | main | here |
| --- | ---: | ---: |
| `engine/src/self-healing.ts` | 107 | 97 |
| `engine/src/executor.ts` | 15 | 12 |
| `engine/src/worktree-pool.ts` | 3 | 2 |
| `engine/src/ephemeral-worker-manager.ts` | 1 | 0 |
| `engine/src/agent-tools.ts` | 5 | **0** |
| `engine/src/gridlock-detector.ts` | 3 | **0** |
| `engine/src/triage.ts` | 4 | 1 |
| `engine/src/mission-execution-loop.ts` | 2 | **0** |
| **net** | | **−28** |

Baseline re-recorded; `--strict` tightened exactly these 4 entries and
no others.

## Finding: a whole class of conversions in this program is INERT, and
the census scores it as progress

`resolveTaskWorkflowIrSync` returns the **default** workflow IR for
every task in production. The sync selection reader behind it is a
PostgreSQL-cutover stub:

```ts
// packages/core/src/task-store/workflow-definitions.ts:505
export function getTaskWorkflowSelectionImpl(_store, _taskId) {
  return undefined;   // "Backend mode cannot synchronously read PostgreSQL"
}
```

So a guard written as
`resolveLifecycleColumns(store.resolveTaskWorkflowIrSync(id))?.hold`
resolves an IR, asks for a trait, and answers **from the default
workflow for every custom board** — silently. It reads as converted and
the census counts it as converted. `main` gained
`sync-workflow-ir-callsite-allowlist.test.ts` for exactly this after my
branch point; it is what caught me.

I had built three sync resolvers on that reader — `resolveMoveLanesSync`
(self-healing, executor) and a widened `resolveTaskParkedColumnsSync`
(scheduler) — reasoning that a *synchronous* `task:moved` listener needs
a *synchronous* reader. That reasoning was sound about the shape and
never checked whether the reader reads anything.

**Dropped from this PR, deliberately, and NOT re-landed anywhere:**

- `scheduler.ts` 12 → 1 (the widening; the pre-existing narrow helper on
main is untouched)
- the executor `task:moved` handler, incl. the Move-Task hard-cancel
lane comparison
- self-healing's `task:moved` fan-out,
`classifyPausedAbortWorkflowRecovery`, `reconcileInReviewBranchRebind`,
`recoverWedgedActiveMerge`, `recoverPausedAbortFailures`, and 12
single-row lane conversions

Those sites are back to their literals. The allow-list's own guidance is
the standard I applied:

> An unconverted `=== "todo"` is strictly better, because it is at least
honest about being a literal.

I did not add my call sites to the allow-list. Six entries would have
turned the gate green in two minutes and buried the defect; the list's
contract requires proving the async resolver is genuinely unreachable,
and for a fire-and-forget listener it is not — the listener can `void`
an async lane resolution the same way `NotificationService` already
does. That is the correct fix and it is a behaviour-shaped change, so it
is out of scope here.

**Fleet-wide consequence:** any conversion routed through
`resolveTaskWorkflowIrSync` is fake progress, and the census cannot see
the difference. `pnpm test:gate` can: the allow-list test is the
detector. Its passing here (161/161) is this PR's evidence that nothing
inert survived the split.

## What IS in this PR — all async-resolved

1. **`self-healing.clearStaleBlockedBy`** — lanes resolved per
**REFERENCED** task, not per iterated task. A blocker's own workflow
decides whether it is still blocking.
2. **`executor` dependency satisfaction** — resolved per **DEPENDENCY**
via `columnsWithFlag`. Preserves the load-bearing asymmetry that a
dependency in *review* already satisfies a dependent; a bulk sweep
flattens that to complete-only and deadlocks the board.
3. **`agent-tools` — the agent task tools listed FINISHED cards as
active.** `fn_task_list` says it lists "tasks that aren't done or
archived"; `fn_task_search` offers `includeDone: false`. Both filtered
on `task.column !== "done"`, so a renamed complete lane returned
finished cards as outstanding work **to an agent**, which then reasons
and acts on them. `includeArchived` was always enforced by the QUERY and
survived a rename; `"done"` was only ever a TS predicate, which is why
exactly that half broke.

Plus the two **dedup** guards in the same file. The cross-parent
diagnostic filter kept a *shipped* card as a candidate on a renamed
board, so the guard adopted it as canonical and returned `wasDuplicate:
true` — absorbing new diagnostic work into a task nobody is working on
(the eval-followup defect shape again). The defined-feature bootstrap
preflight is **not** the query-filter class: its query passes
`includeArchived: true`, so the TS predicate is the *only* archived
guard there; on a renamed archive lane the archived sibling became the
bootstrap canonical and `claimDefinedFeatureTask` then rejects the
non-live row, so a valid first task fails to be created at all.

Both dedup invariants **already had tests** — asserted against the
legacy ids only, so both passed for the very comparison being replaced.
Extended in place into vocabulary differentials rather than added as
parallel files. Two helpers rather than one parameterised one: "is this
finished?" and "is this archived?" are different questions, and merging
them would make the archived-only guard also reject completed rows.

The list/search half re-landed **with the test it originally shipped
without.** No suite exercised either tool, so the original commit's
"304/304 green" said nothing about the change — the optional-flags
failure mode exactly. Both call sites are covered; converting two copies
and testing one is the Surface Enumeration failure this program has
already hit twice.

4. **`gridlock-detector` — FALSE dependency alarms.** The gate compared
each blocker against `done`/`in-review`/`archived`; on a renamed board
all three are true for a *finished* blocker, so no dependency ever
counted as met and the detector reported dependency gridlock for tasks
that are not blocked — `notifyGridlock` then pages the operator.
Resolved per dependency using the **same five flags** as the executor's
gate (`complete`, `archived`, `mergeOrchestration`, `mergeBlocker`,
`humanReview`) — `review` is not a trait, and two gates answering "is
this dependency satisfied?" differently is a split brain. Every
pre-existing case in that file omits a workflow, so none could detect
the change; added the renamed case plus a non-vacuous companion.

5. **`triage` — its OWN copies of the same two tools.**
`createTriageTools` carries a `fn_task_list` and `fn_task_search`
byte-identical in intent to the agent-tools pair, plus a third site
filtering duplicate candidates. Same defect on all three. Reused the
(now exported) agent-tools helper rather than adding a third copy —
deliberately stronger than the two-parallel-tests reading of Surface
Enumeration, since the copies now share one implementation and cannot
drift. **Not claiming call-site coverage:** `createTriageTools` is
private and not drivable without standing up a TriageAgent; the helper
is revert-proofed, those two call sites are covered only through it.

6. **`mission-execution-loop` — a finished fix task read as LIVE,
stalling remediation.** The comment above that line states the rule it
implements: *only an open task makes duplicate triage safe to suppress.*
On a renamed board the rule inverts — a finished fix task is not
`done`/`archived`, so it reads as live, remediation for a fresh
validation failure is suppressed indefinitely, and the mission stalls
with no error surfaced.

**Not revert-proven, and I am not claiming it is.** No test reaches the
`hasLiveFixTask` branch, and the only case that mints a fix feature is
git-gated and heavyweight; building that fixture is larger than the
conversion. The change strictly *widens* the finished set (resolved
roles ∪ the two legacy ids), so default boards are byte-identical — that
is the argument for shipping it unproven, not a substitute for coverage.

7. **Four census-invisible membership guards**, each inverted on a
renamed board — `worktree-pool` (merger-managed branch reclaim could
delete a branch out from under an in-flight merge), `agent-assignment`
(assignment load counted nothing), `ephemeral-worker-manager`
(`isAgentIdle` inverted on both sides), and the dead constants their
conversion orphaned. These are `SET.has(task.column)` shapes the census
does not count, so the −15 understates them.

## Revert results (measured, each run)

| conversion | reverted → |
| --- | --- |
| `clearStaleBlockedBy` per-referenced lanes | renamed-vocabulary case
fails; stale `blockedBy` never clears |
| executor dependency satisfaction | dependent never unblocks on a
renamed review lane |
| `worktree-pool` merger-managed set | reclaim proceeds against an
in-flight merge |
| `ephemeral-worker-manager.isAgentIdle` | idle agent reads busy on a
renamed board |
| `fn_task_list` terminal filter | RENAMED case fails — shipped card
listed as active |
| `fn_task_search` terminal filter | RENAMED case fails — same,
independently |
| cross-parent diagnostic dedup | RENAMED case fails — `wasDuplicate:
true`, new work absorbed |
| bootstrap preflight archived guard | RENAMED case fails — `validate`
called with the archived sibling |
| gridlock dependency gate | RENAMED case fails — false gridlock raised
for an unblocked task |

`agent-assignment`'s widened `taskStore` type is compile-time; its
revert is a tsc failure, not a test failure — stated rather than claimed
as coverage.

## Verification

- `pnpm test:gate` — 161 + 487 + 13 + 71, all green (161 includes
`sync-workflow-ir-callsite-allowlist`)
- `npx tsc -p packages/engine/tsconfig.json --noEmit` — clean
- `pnpm lint` — clean

One commit is a pure import restore: `columnsWithFlag` arrived in a
sibling commit that built on the inert resolver and was left behind. The
engine tsconfig excludes `src/__tests__/**`, so the gate was green while
tsc was not — worth knowing that on this package a green gate is not a
green build.


## Verified NOT a gap — measured, so the next worker does not re-open
them

- **`restart-recovery-coordinator` (5 counted).** Four already take an
optional `reviewColumns` set and the counted literals are the documented
**fallback** arm, which must stay for the same reason `columnRoles.ts`
keeps its id fallback. The sole production caller
(`self-healing.ts:12151-12154`) already passes the resolved set. The
fifth is documented at the site as a re-assertion behind a `listTasks({
column: "in-progress" })` query filter. Nothing to convert.
- **`notification/notification-service` (5 counted).** Already
documented in-file as deliberately counted with no exemption marker: the
wedge-episode site needs per-task serialisation of wedge handling (a
delivery-semantics change to operator notifications), and
`isManualMergeHold` needs a pre-resolved `LifecycleColumns` threaded
through `handleTaskUpdated`, which would pay resolution on every task
update. Both are behaviour/placement judgements, not conversions.
- **`planner-overseer` (3 counted).** `resolveWatchedStage`'s two
literals are fed by `pollPlannerOverseer`, which calls `listTasks({
column: "in-progress" })` and `{ column: "in-review" }` — hardcoded
**query** filters. On a renamed board those queries return no rows, so
the predicate never sees a renamed column. Converting it alone would
drop 3 from the census and change nothing an operator can observe. The
real fix is at the query layer; that is the tracked query-filter-bounded
class, not this PR.
- **`triage:695`** reads `resolvePlannerLanes` → the allow-listed sync
IR reader. Left as an honest literal per the rule above.

**Still open in `packages/engine`, deliberately not in this PR:**
`self-healing.ts` (97, of which ~31 are the query-filter-bounded class
and the rest need per-site classification in a 13k-line file),
`scheduler.ts` (12, blocked on the sync reader above), `executor.ts`
(12), and a tail of ~13 more copies of the "is this task finished?"
question across eight small files (`agent-reflection`,
`auto-merge-finalization`, `merger-scope-auto-widen`,
`backlog-pressure-reporter`, `merger-orphan-rehome`,
`merger-integration-worktree`, `plugin-runner`, `cli-agent/*`). That
tail is a clean follow-up: one question, eight call sites, and the
exported `resolveTerminalColumnsForTasks` helper already exists for it.

That is the same discipline as the sync-resolver finding: a census
number that drops without a behaviour change is not progress, and four
of these files would have handed over exactly that.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 10:47:44 -07:00
gsxdsm
a00f2633ce fix(engine): demote more TUI chatter across merger, self-heal, and ntfy
Route foreach/merger/worktree/self-healing skips, ntfy send bookkeeping, session-purpose runtime picks, planning using-model, and checkpoint rewind lines to debug so recoveries and failures stay visible in the operator log.
2026-07-26 10:15:18 -07:00
gsxdsm
0c85613313 fix(engine): address code-review findings on the planner/worktree recovery fixes
Review of 2dbfe3d31 + 05b704dc6 surfaced real defects in both fixes:

- The unusable-worktree probe composed two helpers across an unnecessary
  self-healing -> step-runner import edge, and the directory check added no
  discriminating power over the `.git` probe. Replaced with one canonical
  hasUsableWorktreeShape beside classifyTaskWorktree, which also applies the
  repo-root gate (FN-6861) when a rootDir is available; both call sites pass one.
  Its narrower guarantee vs the canonical classifier is now documented and
  pinned by tests, including the de-registered shape it cannot see.
- REPLAN_PARK_STATUSES is derived from PLANNING_STAGE_STATUSES instead of
  re-listed, so a new durable park status cannot be added to one set only.
- The preserve/clear decision no longer pretends to steer `worktree`: the rebound
  is a reopen move, which clears it regardless. Documented, and the test now
  asserts the durable row rather than only the updateTask argument.
- `branch` is cleared only when it is the re-derivable canonical fusion/<id>;
  a non-canonical branch survives so a card's only commit pointer is not dropped.
- The recovery log named the recorded worktree even when the session had targeted
  an AI-merge clean room. It now names the refused path and says whether the
  recorded worktree was gone too.
- Added task:auto-recover-worktree-session-metadata so the decision is legible to
  agents, not only in human log prose.
- isTaskStillInPlanningStage's parameter type now includes the execution stamps
  its implementation reads.
- Test hygiene: real-fs fixtures wrapped in try/finally; changeset dev note
  corrected; FN-8361 asserted at the discovery surface, not only in the guard
  table.

Also captures the shared bug class in docs/solutions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:24:10 -07:00
gsxdsm
7cf030ddca fix(FN-8400): normalize preserved worktree recovery
Relocate idle native checkouts into the configured root across executor and self-healing recovery while preserving live, Worktrunk-managed, and task-pinned paths. Cover the invariant with real Git and focused recovery tests.

Fusion-Task-Id: FN-8400
2026-07-19 23:47:53 -07:00
gsxdsm
478f226a54 test: green full-suite CI after main drift (#2229)
## Summary
Restores green **Full Suite (non-blocking)** runs on `main`. Recent main
merges left i18n key parity, schema baseline bookkeeping (0011→0012),
heartbeat tool inventory (FN-8058 `fn_task_logs_read`), and merger
whitespace-classification mocks (execFile `git diff -p -w :2: :3:`) out
of date, so all four test shards failed.

## Root causes observed on main
- **Shard 4 / `@fusion/i18n`**: missing `skipConfirmationDialogs*` +
`reviewBudgetExhausted` in non-en locales; orphan
`awaitingApprovalPlanReviewReplanCap`
- **Shard 3 / `@fusion/core`**: `SCHEMA_BASELINE_VERSION` advanced to
`0012` while tests still equated it with
`OWNER_PROJECT_ID_SPLIT_VERSION` (`0011`) and omitted `0012` from
applied-migration lists
- **Shards 1–2 / `@fusion/engine`**: tool count/snapshot drift for
`fn_task_logs_read`; merger tests still mocked `git diff-tree` for
trivial classification after the execFile `:2:`/`:3:` cutover; mock
provider `updateTask` arity drift

## Changes
- Locale catalogs: add missing keys, drop orphan key
- Schema applier tests: immutable 0011 identity + baseline 0012 lists
- Heartbeat + gating snapshots: include `fn_task_logs_read`
- Merger unit mocks: recognize `git diff -p -w :2:path :3:path`
- Mock provider: accept optional third `updateTask` arg

## Test plan
- [x] `pnpm --filter @fusion/i18n exec vitest run` — 23/23
- [x] `pnpm --filter @fusion/core exec vitest run
src/__tests__/postgres/schema-applier.test.ts` (immutable + automation
upgrade) — pass
- [x] `pnpm --filter @fusion/core exec vitest run` project-identity +
satellite-fusiondir — pass
- [x] Engine suites from failed CI shards (file-scoped,
hermes/openclaw/paperclip/grok, reliability post-finalize/mission,
heartbeat, gating, merger recovery/prompt, mock-provider, etc.) — pass
- [ ] Full Suite workflow green on merge to main

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Improved project data isolation across backend operations.
- Added safer optional toast handling when UI components render outside
the full application shell.
  - Added support for reading task logs during agent heartbeat sessions.

- **Bug Fixes**
- Prevented runtime probes from hanging and avoided scanning large
binary files.
  - Improved path handling for workspaces with missing descendants.
- Corrected task retry state resets and GitHub import/issue-close
behavior.

- **Style**
  - Improved chat, terminal, and settings spacing.
  - Added clearer accessibility labeling for the auto-merge control.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-16 16:01:29 -07:00
gsxdsm
725ce45c5d FN-7799: fix false-negative Git repository detection blocking task execution
Replace the boolean isGitRepository() check with a tri-state Git detection so environmental git failures (dubious ownership, missing git binary, timeouts) are no longer misreported as "not a Git repository", which previously blocked all task execution in valid repos and survived engine restarts.

- Add detectGitRepository() in worktree-pool.ts returning repo / not-repo / error (with reason: dubious-ownership, git-missing, timeout, unknown), classified from git's stderr; bound the git rev-parse call with a 10s timeout and maxBuffer; keep isGitRepository() as a backward-compatible wrapper
- Route the executor dispatch preflight guard through detectGitRepository(): only emit the original "not a Git repository / run git init" fatal on a positive not-repo verdict; on error, throw a distinct accurate error naming the real git failure, including the safe.directory remedy for dubious ownership
- Route the in-process runtime startup warning through the same tri-state detection so it only warns "not a Git repository" on a positive not-repo verdict
- Add a regression test locking extractWorktreeConflictInfo() to NOT misclassify a dubious-ownership git worktree add failure as not-git-repo
- Add targeted tests across worktree-pool, executor-worktree, and in-process-runtime test suites covering repo/not-repo/dubious-ownership/git-missing/timeout classifications on Windows OneDrive-style and POSIX paths
- Add changeset and a docs/solutions/logic-errors write-up of the false-negative root cause and fix

Files changed:
 .changeset/fn-7799-git-detection-false-negative.md |  7 +++
 .../logic-errors/git-detection-false-not-repo.md   | 54 ++++++++++++++++
 .../engine/src/__tests__/executor-worktree.test.ts | 61 +++++++++++++++++++
 .../engine/src/__tests__/worktree-pool.test.ts     | 71 +++++++++++++++++++---
 packages/engine/src/executor.ts                    | 38 +++++++++---
 .../runtimes/__tests__/in-process-runtime.test.ts  | 53 ++++++++++++++--
 packages/engine/src/runtimes/in-process-runtime.ts | 16 ++++-
 packages/engine/src/worktree-pool.ts               | 66 ++++++++++++++++++--
 8 files changed, 334 insertions(+), 32 deletions(-)

Fusion-Task-Id: FN-7799
Fusion-Task-Lineage: 25a84283-bf47-472b-8a98-a10bf7e494de
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-10 21:19:22 -07:00
gsxdsm
ec1d29e818 FN-6922: guard worktree acquisition returns from repo root
Prevent task worktree acquisition from handing the project root back to executors.

- Add a repo-root return guard across resume, pool, and fresh acquisition paths.
- Clear invalid repo-root task assignments and create a fresh worktree fallback when safe.
- Share repo-root canonicalization and expand regression coverage for acquisition liveness.
- Document the acquisition guard and add a patch changeset.

Files changed:
 .changeset/fn-6922-repo-root-acquisition-guard.md  |   5 +
 .../repo-root-task-worktree-requeue-loop.md        |   9 +-
 .../__tests__/executor-worktree-liveness.test.ts   |  35 +++
 .../worktree-acquisition-secrets-env.test.ts       |   9 +-
 .../src/__tests__/worktree-acquisition.test.ts     |  91 ++++++-
 packages/engine/src/worktree-acquisition.ts        | 272 +++++++++++++--------
 packages/engine/src/worktree-pool.ts               |   8 +-
 7 files changed, 304 insertions(+), 125 deletions(-)

Fusion-Task-Id: FN-6922

Fusion-Task-Lineage: c16cee1b-de16-4d5f-90e0-132f94fa8377
2026-06-22 19:11:08 -07:00
gsxdsm
7ee1fec22c FN-6861: reject repo-root task worktrees
Prevent stale task metadata from treating the project repository root as a reusable task worktree.

- Classify root-equal task worktree paths as repo-root before registered-worktree checks.
- Clear stale resumed repo-root assignments so acquisition creates a fresh configured task worktree.
- Add structured executor audit metadata and regression coverage for repo-root liveness collisions.
- Document the repo-root requeue-loop invariant and recovery behavior.

Files changed:
 docs/architecture.md                               |  2 +-
 .../repo-root-task-worktree-requeue-loop.md        | 49 ++++++++++++++++
 .../__tests__/executor-worktree-liveness.test.ts   | 23 +++++++-
 .../src/__tests__/worktree-acquisition.test.ts     | 67 +++++++++++++++++++++-
 .../src/__tests__/worktree-pool-liveness.test.ts   | 25 ++++++++
 packages/engine/src/executor.ts                    | 22 ++++++-
 packages/engine/src/worktree-acquisition.ts        |  4 ++
 packages/engine/src/worktree-pool.ts               | 13 ++++-
 8 files changed, 198 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-6861

Fusion-Task-Lineage: d6a4922e-5a21-4037-b2c2-86ff53d8e9e3
2026-06-21 14:28:58 -07:00
gsxdsm
7e7eb6299d Harden orphan-worktree/stale-task-dir cleanup (code-review follow-up)
Addresses findings from a multi-agent review of the two prior fixes.

P0 (executor.ts): the stale-conflict recovery force-removed worktreePath with
no bounds check; that path can come from a git admin entry resolving outside
.worktrees/. Now refuses unless the path is inside the worktrees dir, not a
symlink (realpathSync), not a registered worktree, and not actively owned, and
re-verifies liveness in the catch instead of trusting the error string. Also
excludes spawn failures (spawn git ENOENT) from the stale-path classification.

worktree-pool.ts: resolveGitdirPointer -> dotGitPointerIsDangling. Reaps only
when a .git link's gitdir target is confirmed missing; a real .git dir,
unparseable pointer, or any read/stat failure is treated as NOT dangling
(conservative) so a transient read error on a live worktree can't trigger rm.
Drops the string|"directory"|null sentinel union.

core store.ts: bypass the reconcile recency window when the live task table is
empty (corruption/restore: surviving task.json keep old mtimes) and when
fusion.db was auto-recovered on startup, so .recover row loss isn't stranded.
Adds an ignoreRecencyWindow option.

Tests: executor recovery + out-of-bounds refusal, unparseable .git skip,
recency boundary, empty-DB/forced bypass. engine 135 + core 12 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 12:46:34 -07:00
gsxdsm
438cd75eaf Fix leaked orphan worktree dirs failing execute node
Directories under .worktrees/ that survive with a dangling .git pointer
(present on disk, but their .git/worktrees/<name> admin entry is gone) are
invisible to `git worktree list`/`prune` yet collide with freshly generated
worktree names. The executor's conflict cleanup then fails with
"is not a working tree", failing the workflow graph at node 'execute' after
3 attempts.

- executor.ts: extend FN-4813 stale-conflict recovery to also treat
  "is not a working tree" and ENOENT (not just "validation failed, cannot
  remove working tree") as "no live worktree here" — prune the admin entry,
  force-remove the leftover dir, and proceed with fresh creation.
- worktree-pool.ts: reapOrphanWorktrees skipped any dir on mere .git-file
  presence, contradicting its own documented invariant. Resolve the .git
  pointer and only skip when the gitdir target exists; reap dangling
  pointers like any other orphan so they stop accumulating across runs.
- Tests for both the dangling (reaped) and valid (skipped) .git cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 09:58:23 -07:00
gsxdsm
283adce4d0 FN-6295: move AI merge clean rooms into worktrees
Move AI-merge clean-room worktrees into the configured worktrees directory while preserving legacy cleanup.

- Resolve AI-merge roots through the configured worktrees directory using a hidden .ai-merge container.
- Keep local git excludes and stale cleanup compatible with legacy .fusion/ai-merge and tmpdir locations.
- Exclude the .ai-merge container from worktree pool and self-healing one-level sweeps.
- Add regression coverage for path resolution, cleanup, orphan reap, and cap enforcement behavior.
- Update architecture and agent guidance for the relocated clean-room root.

Files changed:
 AGENTS.md                                          |  2 +-
 docs/architecture.md                               |  4 +-
 .../engine/src/__tests__/merger-ai-cleanup.test.ts | 50 +++++++++----
 .../__tests__/self-healing-tempdir-sweep.test.ts   | 87 +++++++++++++++++++---
 .../engine/src/__tests__/worktree-paths.test.ts    | 24 ++++++
 .../engine/src/__tests__/worktree-pool.test.ts     | 55 ++++++++++++++
 packages/engine/src/merger-ai.ts                   | 27 +++++--
 packages/engine/src/self-healing.ts                | 25 +++----
 packages/engine/src/worktree-paths.ts              | 17 +++++
 packages/engine/src/worktree-pool.ts               | 10 +--
 10 files changed, 247 insertions(+), 54 deletions(-)

Fusion-Task-Id: FN-6295
Fusion-Task-Lineage: d95d32c2-3253-4964-b68a-252b4cb65109
2026-06-12 12:49:34 -07:00
gsxdsm
0b1c8fb56b fix(ci): widen Column to ColumnId in plugins + drop unused import after #1403 widening
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 08:40:10 -07:00
gsxdsm
afc72b6bb0 fix(core): widen Task.column to ColumnId across packages; v1-preserving IR persistence for rollback safety (#1403 #1405) 2026-06-04 08:00:33 -07:00
gsxdsm
b154844286 FN-5772: re-anchor nested task worktree paths
Fix executor worktree invariant handling by re-anchoring nested task worktree paths to the actual git top-level.

- add nested worktree root detection that only re-anchors when the top-level is a registered worktree inside the configured worktrees directory
- update executor liveness gating and verifyWorktreeInvariants to persist re-anchored task.worktree values and retry checks safely
- emit a new run-audit git mutation (worktree:reanchored) and add reliability tests/docs coverage plus a patch changeset

Files changed:
 .changeset/fn-5772-worktree-reanchor.md            |  7 +++
 docs/architecture.md                               |  4 +-
 packages/engine/src/__tests__/reliability-interactions/executor-liveness-gate.test.ts                 | 33 ++++++++++
 packages/engine/src/__tests__/verify-worktree-invariants-missing.test.ts     | 62 +++++++++++++++++-
 packages/engine/src/__tests__/worktree-reanchor-nested-root.test.ts          | 73 ++++++++++++++++++++++
 packages/engine/src/executor.ts                    | 54 ++++++++++++++--
 packages/engine/src/run-audit.ts                   |  1 +
 packages/engine/src/worktree-pool.ts               | 63 +++++++++++++++++++
 8 files changed, 290 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-5772

Fusion-Task-Lineage: 475de161-7bc1-4359-bb76-20c4c07196d9
2026-05-31 08:32:01 -07:00
gsxdsm
4fee2c1324 FN-5671: add branch-strategy selection to new task creation
Add branch-strategy based task branch handling from modal through task creation routes.

- add branch strategy dropdown + validation in New Task modal and TaskForm, including required branch-name handling for existing/custom-new modes
- send structured branchSelection payload from dashboard API client and cover UI/API behavior with new tests
- add server-side branch selection mode parsing, auto-new branch derivation (fusion/<task-id>-<slug>), and response updates when auto branch is generated
- update engine/worktree and dashboard route tests plus dashboard guide documentation
- add a changeset for @runfusion/fusion patch release

Files changed:
 .changeset/fn-5671-branch-strategy-dropdown.md     |  7 ++
 docs/dashboard-guide.md                            | 16 +++++
 packages/dashboard/app/__tests__/api-tasks.test.ts | 21 ++++++
 packages/dashboard/app/api/legacy.ts               |  9 +++
 packages/dashboard/app/components/NewTaskModal.css |  8 +++
 packages/dashboard/app/components/NewTaskModal.tsx | 41 +++++++++---
 packages/dashboard/app/components/TaskForm.tsx     | 30 ++++++++-
 .../app/components/__tests__/NewTaskModal.test.tsx | 77 +++++++++++++++++++---
 .../src/__tests__/branch-selection.test.ts         | 13 ++++
 .../dashboard/src/__tests__/routes-tasks.test.ts   | 72 ++++++++++++++++++++
 packages/dashboard/src/routes/branch-selection.ts  | 45 ++++++++-----
 .../src/routes/register-task-workflow-routes.ts    | 22 +++++--
 .../engine/src/__tests__/worktree-pool.test.ts     | 41 ++++++++++++
 packages/engine/src/worktree-pool.ts               |  2 +-
 14 files changed, 361 insertions(+), 43 deletions(-)

Fusion-Task-Id: FN-5671
Fusion-Task-Lineage: 7f2e7b68-050d-4a2c-af0b-cb895de35576
2026-05-29 09:44:17 -07:00
gsxdsm
dc944949b1 fix(engine,dashboard): close 7 review findings on merger auto-sync
Data-loss fixes in syncWorktreeToHead:
  - Untracked-restore checks `git ls-tree -r --name-only HEAD` to skip
    paths the new tip added as tracked files; user bytes stay in the
    stage dir instead of clobbering merged content.
  - Apply-failure on a deleted/renamed file: conflictedFiles falls back
    to parsing `diff --git a/<p> b/<p>` headers when --diff-filter=U
    returns nothing.
  - All git invocations pass `-c core.quotePath=false` so non-ASCII
    paths round-trip through copyFileSync.
  - Stash-and-ff re-verifies rev-parse HEAD === newSha right before
    each `reset --hard HEAD` (TOCTOU). On mismatch we bail with patch
    preserved on disk.
  - Stage dir lifecycle moved into try/finally with preserveStageDir
    flag — kept whenever the user's edits live only in patchPath; rm'd
    on all clean exits.
  - Patch written to disk before the apply attempt, not only on
    failure, so a crash between snapshot and apply doesn't lose edits.

Multi-worktree-same-branch fix:
  - New getRegisteredWorktreeBranches returns Array<{branch,path}>
    instead of collapsing into a Map. Multiple worktrees can share a
    branch via `git worktree add --force -b`; merger now syncs all of
    them rather than silently skipping all but the last.

Contract + surfacing fixes:
  - JSDoc on merge:auto-sync GitMutationType now lists the actually-
    emitted outcome strings + stage enum.
  - GET /api/tasks/merge-advance-events joins merge:auto-sync events
    within ±5min of the advance and returns them in a new
    `autoSync: AutoSyncOutcome[]` field; useMergeAdvanceNotice exposes
    the same shape so the banner can surface pop-conflicts (including
    patchPath) instead of dropping them.

Hygiene:
  - Merger now reads the setting via normalizeMergeAdvanceAutoSyncMode
    instead of an inline check + `as unknown` cast.

New tests:
  - Untracked-collides-with-tracked preserves merged content.
  - Apply failure on deleted file populates conflictedFiles from
    patch header.
  - Route surfaces autoSync outcomes (clean-sync + pop-conflict)
    joined within the time window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:13:17 -07:00
Fusion (runfusion.ai)
1bffa22ca9 feat(FN-5479): fix identity-guard merger bypass on detached HEAD and gate l
The merge delivers the FN-5483 identity-guard bypass for merger-driven commits on detached HEAD, plus Steps 2 and 6 of FN-5479 which gate the limbo counter by enqueue acceptance and document the associated invariant. It also restores the dashboard's PWA and theme-boot contract in index.html. New reg

Fusion-Task-Id: FN-5479
2026-05-22 08:31:12 -07:00
gsxdsm
2d661df870 fix(engine): harden worktree-pool branch creation and auto-reanchor foreign-only contamination
WorktreePool.prepareForTask now rejects empty/"HEAD" base values and verifies
that the worktree's HEAD actually landed at the resolved base SHA after
`git checkout --detach`. This closes the FN-5432 / FN-5255 contamination
pattern where a recycled worktree branched from a stale HEAD (reflog:
"branch: Created from HEAD") and pinned the new task's tip to the previous
occupant's commit.

SelfHealingManager.tryReanchorForeignOnlyContamination is invoked from both
PR-conflict and self-owned-branch-conflict catch sites before the
unrecoverable-pause path. When the conflicted branch carries only foreign
commits (no own work), the branch is reset to base via the existing
recoverForeignOnlyContamination flow instead of being escalated for human
adjudication.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 04:13:15 -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)
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)
c56e0cf814 feat(FN-5083): complete Step 3 — canonicalize fusion branch naming 2026-05-18 18:26:52 -07:00
gsxdsm
46d09285d5 feat(FN-5058): merge fusion/fn-5058 2026-05-18 11:01:32 -07:00
Fusion (runfusion.ai)
d702231adc feat(FN-4938): complete Step 2 — add helper and wire cleanup
Fusion-Task-Id: FN-4938
Fusion-Task-Lineage: 8b53a5da-1321-4796-9775-ff043efdcef3
2026-05-18 01:50:22 -07:00
Fusion (runfusion.ai)
48caf28148 test(FN-4912): complete Step 9 — add env materialization verification coverage
Fusion-Task-Id: FN-4912
Fusion-Task-Lineage: 943d0651-052a-41b5-8069-4c60f4db1ba7
2026-05-17 23:29:21 -07:00
Fusion (runfusion.ai)
59023b7f50 feat(FN-4912): complete Step 7 — add orphan cleanup env teardown
Fusion-Task-Id: FN-4912
Fusion-Task-Lineage: 943d0651-052a-41b5-8069-4c60f4db1ba7
2026-05-17 23:29:20 -07:00
Fusion (runfusion.ai)
7e90bce8bb feat(FN-4954): harden pool leasing invariants and wire runtime auditing
Fusion-Task-Id: FN-4954
Fusion-Task-Lineage: b3dd2d2f-3aa3-48f1-8a56-56e66518d139
2026-05-17 21:17:38 -07:00
Fusion (runfusion.ai)
40f9aa99e6 feat(FN-4962): complete Step 3 — reconcile stale worktree metadata
Fusion-Task-Id: FN-4962
Fusion-Task-Lineage: de4ce54b-c5e4-40f9-a048-677adac3e1a0
2026-05-17 15:55:18 -07:00
Fusion (runfusion.ai)
3bbc5077b8 feat(FN-4935): complete Step 7 — testing and verification
Ref: Runfusion/Fusion#601
Fusion-Task-Id: FN-4935
Fusion-Task-Lineage: 8c842b69-1427-47be-9ba5-8ec66449cc7c
2026-05-17 15:02:35 -07:00
Fusion (runfusion.ai)
0f69412c20 feat(FN-4935): complete Step 1 — structured liveness classifier
Ref: Runfusion/Fusion#601
Fusion-Task-Id: FN-4935
Fusion-Task-Lineage: 8c842b69-1427-47be-9ba5-8ec66449cc7c
2026-05-17 15:02:35 -07:00
Fusion (runfusion.ai)
2cb141a511 feat(FN-4917): complete Step 2 — add worktree classification helper
Fusion-Task-Id: FN-4917
Fusion-Task-Lineage: 1422a545-f4b5-4e1f-a347-8be2a4202f45
2026-05-17 14:10:42 -07:00
Fusion
86237c9a50 fix(FN-4811): unblock @fusion/engine typecheck so verification bootstrap can run
Symptom found while investigating 'tasks are still struggling': every
in-review task hitting pre-merge deterministic verification failed with

  [verification:bootstrap] bootstrap preamble failed (exit 2):
  [test-bootstrap] FAILED: workspace dist artifact rebuild did not complete.
  [test-bootstrap] command: pnpm --filter @fusion/engine build

Because pnpm --filter @fusion/engine build hit 17 TS errors from a prior
autonomous-agent refactor introducing a RemovalReason enum-like object
and two new audit event types. The bootstrap preamble is run by the
merger before every direct-merge verification, so a broken engine
typecheck blocked EVERY task from merging.

Fixes:

1. Duplicate RemovalReason re-export in worktree-pool.ts

   Both  and
    were present for the same identifier,
   producing TS2300 'Duplicate identifier'. RemovalReason is a const
   object with derived type (typeof-keyof pattern), so a single value
   export covers both kinds; the type-only re-export was redundant.

2. GitMutationType union missing the FN-4811 audit event types

   merger.ts and worktree-backend.ts were emitting
   'worktree:removal-refused-active-session' and
   'worktree:removal-forced-over-active-session' audit events, but the
   union in run-audit.ts didn't include them. Added both.

3. self-healing.test.ts vi.mock had wrong RemovalReason keys

   The mock only exposed 5 keys (SelfHealing*) but production code
   references HardCancel, Executor*, Merger*, PoolPrune, etc. Calls
   like removeWorktree({ reason: RemovalReason.MergerPostMerge }) were
   getting reason=undefined, producing confusing 'cannot remove
   worktree: [vitest] No RemovalReason export is defined on mock'
   error messages. Updated the mock to mirror the production const
   exactly.

4. worktree-backend.test.ts removeWorktree calls missing required reason

   The new contract makes reason: RemovalReason a required field on
   removeWorktree's input. Five existing test cases were missing it;
   added reason: RemovalReason.MergerCleanup to each.

5. integrity-warning-persisted-dedup.test.ts Settings cast

   The test's makeStore helper cast a partial settings object to
   Settings; TS rejected the narrowed type. Cast through unknown.

Verification:

  - pnpm --filter @fusion/engine build: clean
  - pnpm lint: clean
  - pnpm build (full workspace): clean
  - pnpm --filter @fusion/engine test: 5045 pass, 1 pre-existing
    aiMergeTask real-git timeout flake, 1 skipped

With this fix, the verification bootstrap can complete and the merger
can finalize tasks again.

Fusion-Task-Id: FN-4811
2026-05-16 17:23:15 -07:00
Fusion (runfusion.ai)
8fd47b619f feat(FN-4811): complete Step 3 — update removeWorktree call sites
Fusion-Task-Id: FN-4811
Fusion-Task-Lineage: f3dac123-cb46-4d31-8a7e-dfc664bfdc5f
2026-05-16 16:55:04 -07:00
Fusion (runfusion.ai)
e2de8fed6d feat(FN-4742): complete Step 4 — migrate pool and self-healing removals
Fusion-Task-Id: FN-4742
Fusion-Task-Lineage: 59bca56e-c9d9-4066-9f5a-6d8ee252a100
2026-05-16 10:08:02 -07:00
Fusion (runfusion.ai)
36645bdb84 fix(FN-4717): complete Step 4 — align worktrunk source union types
Fusion-Task-Id: FN-4717
Fusion-Task-Lineage: a2533cd8-52c4-43a0-9daf-e0a49745306b
2026-05-16 01:58:16 -07:00
Fusion (runfusion.ai)
156392410a feat(FN-4678): add removeWorktree helper to worktree-backend
Adds a `removeWorktree` helper to the worktree backend with corresponding unit tests, and wires it into the worktree pool.

Fusion-Task-Id: FN-4678
2026-05-15 22:49:36 -07:00
Fusion (runfusion.ai)
3defcbe849 feat(FN-4706): complete Step 2 — disable worktrunk auto-install path
Fusion-Task-Id: FN-4706
Fusion-Task-Lineage: 00e9207c-d2dc-4bc4-ae92-4604339bcbc2
2026-05-15 21:23:05 -07:00
Fusion (runfusion.ai)
5e6d420d71 fix(FN-4624): fix scheduler test mocks for createLogger and lint in worktree-pool
Fusion-Task-Id: FN-4624
Fusion-Task-Lineage: 854e6033-bc17-45be-8d04-18bcb66b31c4
2026-05-15 20:24:58 -07:00
Fusion (runfusion.ai)
af93673bda feat(FN-4624): complete Step 4 — wire getWorktrunkBinary into worktree-pool
Fusion-Task-Id: FN-4624
Fusion-Task-Lineage: 854e6033-bc17-45be-8d04-18bcb66b31c4
2026-05-15 20:24:57 -07:00
Fusion (runfusion.ai)
bf97042b61 feat(FN-4687): complete Step 3 — export backend selector surface
Fusion-Task-Id: FN-4687
Fusion-Task-Lineage: d646a4dc-e28e-4b1f-ac07-c4ab79e893d5
2026-05-15 18:23:50 -07:00
Fusion (runfusion.ai)
332fab63a1 feat(FN-4686): complete Step 3 — add backend selector and exports
Fusion-Task-Id: FN-4686
Fusion-Task-Lineage: a1e58bd8-fd94-471a-b164-c396c5512fea
2026-05-15 17:52:54 -07:00
Fusion (runfusion.ai)
3ddbbea991 feat(FN-4684): complete Step 3 — add selector surface and audit types
Fusion-Task-Id: FN-4684
Fusion-Task-Lineage: 142e512b-8189-4029-9df4-4bd40b69ed2a
2026-05-15 16:44:49 -07:00
Fusion (runfusion.ai)
58aa411077 test(FN-4682): add worktree liveness regression coverage
Fusion-Task-Id: FN-4682
Fusion-Task-Lineage: f37fb4a1-878b-4d0c-85c8-0f005ab0fe7b
2026-05-15 15:59:34 -07:00
Fusion (runfusion.ai)
3af4cb77ee fix(FN-4682): make worktree liveness assertion language-agnostic
Fusion-Task-Id: FN-4682
Fusion-Task-Lineage: f37fb4a1-878b-4d0c-85c8-0f005ab0fe7b
2026-05-15 15:59:34 -07:00
Fusion
2799c101ac feat(FN-4606): complete Step 3 — route engine call sites
Ref: Runfusion/Fusion#321
Fusion-Task-Id: FN-4606
Fusion-Task-Lineage: 94b23f37-944e-4bcd-bfa1-67d0a8c0a267
2026-05-15 09:19:58 -07:00
Fusion
f00df58eb7 feat(FN-4606): complete Step 2 — add worktree path resolver
Ref: Runfusion/Fusion#321
Fusion-Task-Id: FN-4606
Fusion-Task-Lineage: 94b23f37-944e-4bcd-bfa1-67d0a8c0a267
2026-05-15 09:19:58 -07:00
Fusion
473ea373b8 feat(FN-4508): complete Step 2 — handle tip-already-merged recovery paths
Fusion-Task-Id: FN-4508
Fusion-Task-Lineage: 948a9cae-3975-4f15-bd47-2f88b379171d
2026-05-14 16:33:27 -07:00
Fusion
e01d2ef04f feat(FN-4485): complete Step 2 — tighten branch conflict classifier
Fusion-Task-Id: FN-4485
Fusion-Task-Lineage: 034088dc-ebc4-4e12-8314-39419d41b23f
2026-05-14 11:23:43 -07:00
Fusion
d8255c2bb0 fix(FN-4476): handle fully-subsumed branch conflicts across reclaim paths
Fusion-Task-Id: FN-4476
Fusion-Task-Lineage: 8673c1d9-f47e-4d02-89e6-646040b9be32
2026-05-14 08:49:37 -07:00
gsxdsm
86f8caf14e chore(FN-4428): import dependency content from fusion/fn-4410
Squash-imported the working tree of fusion/fn-4410 as a single commit so this branch carries the dep's content without inheriting its individual commits. If the dep is later squash-merged to main, this commit's patch-id should match the merge and rebase cleanly.

Fusion-Task-Id: FN-4428
Fusion-Task-Lineage: ea174f50-49ac-4105-b6cf-db3bab0984fd
2026-05-14 02:28:56 -07:00