Commit Graph

792 Commits

Author SHA1 Message Date
gsxdsm
dc834e582e fix(workflows): address lifecycle review follow-ups (#2380)
## Summary

- preserve workflow IR hashes in production column-transition audit
metadata
- centralize active workflow-continuation states across release,
runtime, and executor paths
- extract and test actionable planning-continuation selection
- expand Coding (Ideas) remapping/removal coverage and add required
lifecycle decision records

Follow-up to the review body on #2378 after that PR was merged.

## Validation

- `pnpm lint`
- 123 focused core/engine tests
- `pnpm verify:fast`
- `pnpm test:gate` (487 tests)


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

- **Bug Fixes**
- Improved workflow continuation handling by centralizing
“active/continuation-eligible” state selection across executor,
hold/release logic, and in-process runtime.
- Persisted richer task column-transition metadata (including `irHash`)
to preserve workflow provenance.
- Ensured planning continuations exclude paused/missing/invalid tasks
and that task resolution failures surface instead of being ignored.
- Corrected fresh-worktree step execution ordering to return expected
`baselineSha`/`checkpointId` behavior.

- **New Features**
- Added and exposed `ACTIVE_WORKFLOW_WORK_ITEM_STATES` for consistent
work-item “active” semantics.
- Introduced a shared planning-continuation candidate selector to
standardize dispatchable planning work filtering.

- **Documentation**
- Clarified the small coding-ideas workflow preset omits verification
while preserving a continuous executable path.

- **Tests**
- Added coverage for planning continuation filtering and fresh-worktree
ordering behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-21 13:36:05 -07:00
gsxdsm
83209e64dc fix(workflows): align stages with board columns (#2378)
## Summary

The Coding (Ideas) workflow now behaves like the board it presents:
Ideas stays inert, Todo owns planning and plan review, In progress owns
implementation, and In review owns code review and merge. The restored
preset is intentionally limited to that five-stage path, while the
existing Coding workflow remains unchanged.

Workflow execution now suspends at Todo→In progress instead of running
the implementation node early. A durable, single-owner continuation
records the exact resume node and survives process restarts; the
scheduler remains the only component allowed to admit the task into WIP.
Disabled optional review groups traverse the same boundary without
invoking a reviewer, avoiding the prior stuck-task behavior.

Workflow validation also rejects capacity holds with no reachable WIP
destination, so deterministic lifecycle deadlocks fail at authoring time
rather than after a task is running.

Session-settled decisions carried from planning: columns are execution
invariants, scheduler-owned WIP admission is preserved, the existing
Coding (Ideas) preset is restored and simplified, and invalid release
topology is rejected (user-approved).

## Validation

- `pnpm lint`
- `pnpm verify:fast`
- `pnpm test:gate` (296 engine, 128 PostgreSQL core, and 63 CI-shape
tests)
- Focused workflow lifecycle tests (106 assertions)
- PostgreSQL regression coverage proves atomic continuation replacement
and database rejection of a second active owner


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

* **New Features**
* Added durable, resumable workflow execution across capacity boundaries
(including explicit suspend/resume at the correct node).
* Introduced Todo “plan review” workflow continuations and automated
planning/capacity draining.
* Restored Coding (Ideas) as a selectable built-in and updated its lane
placement; improved optional-step group enablement support.
* **Bug Fixes**
  * User moves back to Todo now cancels active workflow continuations.
* Rejected workflow boundary transitions now surface as errors (instead
of silently continuing).
* Workflows with undriveable capacity-hold configurations are now
rejected.
* **Tests / Data**
* Expanded coverage for workflow suspension, continuations, and
continuation replacement; updated database schema to persist
continuation metadata and enforce single active continuation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-21 12:17:47 -07:00
gsxdsm
4c0dfbcfd6 fix(engine): preserve workflow completion summaries
Keep approved-contract retry instructions scoped to review nodes so advisory and completion-summary agents can produce their intended output.
2026-07-20 15:26:23 -07:00
gsxdsm
1d4e8afa7b FN-8444: include planning time in task metrics
Track active planning time alongside execution time for costs, analytics, and task displays.

- Persist planning timing state across task lifecycle transitions and recovery
- Include planning activity in token cost, analytics, and dashboard timing displays
- Add PostgreSQL migration support using the configured migration directory

Files changed:
 .changeset/fn-8444-planning-time-cost.md           |  7 +++
 docs/dashboard-guide.md                            |  3 ++
 docs/task-management.md                            |  5 ++
 packages/core/src/index.ts                         |  1 +
 .../migrations/0029_planning_active_timing.sql     |  3 ++
 packages/core/src/postgres/schema-applier.ts       | 14 ++++-
 packages/core/src/postgres/schema/project.ts       |  2 +
 packages/core/src/productivity-analytics.ts        | 29 +++++-----
 packages/core/src/store.ts                         |  2 +-
 .../core/src/task-store/archive-lifecycle-2.ts     |  2 +
 packages/core/src/task-store/moves.ts              |  7 +++
 packages/core/src/task-store/persistence.ts        |  4 ++
 packages/core/src/task-store/remaining-ops-2.ts    |  2 +-
 packages/core/src/task-store/serialization.ts      |  7 +++
 packages/core/src/task-store/task-row-mappers.ts   |  2 +-
 packages/core/src/task-store/task-update.ts        | 10 ++++
 packages/core/src/task-timing.ts                   | 35 ++++++++++++
 packages/core/src/types.ts                         | 12 +++++
 packages/dashboard/app/components/TaskCard.tsx     | 13 ++---
 .../app/components/TaskTokenStatsPanel.tsx         |  6 ++-
 .../app/components/__tests__/TaskCard.test.tsx     | 17 ++++++
 .../app/utils/__tests__/taskTiming.test.ts         |  9 +++-
 packages/dashboard/app/utils/taskTiming.ts         | 14 +++++
 packages/dashboard/app/utils/taskTokenCost.ts      |  2 +
 .../dashboard/src/task-planner-chat-metrics.ts     | 14 ++++-
 packages/engine/src/__tests__/self-healing.test.ts | 61 +++++++++++++++++++++
 packages/engine/src/executor.ts                    | 50 +++++++++++++++++
 packages/engine/src/runtimes/in-process-runtime.ts |  3 ++
 packages/engine/src/self-healing.ts                | 62 ++++++++++++++++++++++
 packages/engine/src/triage.ts                      | 10 ++++
 packages/i18n/locales/en/app.json                  |  2 +-
 packages/i18n/locales/es/app.json                  |  2 +-
 packages/i18n/locales/fr/app.json                  |  2 +-
 packages/i18n/locales/ko/app.json                  |  2 +-
 packages/i18n/locales/zh-CN/app.json               |  2 +-
 packages/i18n/locales/zh-TW/app.json               |  2 +-
 36 files changed, 384 insertions(+), 36 deletions(-)

Fusion-Task-Id: FN-8444

Fusion-Task-Lineage: 0178e0a7-3018-4ef4-be9b-6de5f964fb58

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-20 13:40:50 -07:00
gsxdsm
1b8b7f617e fix(FN-8426): wait for answers to agent questions
Convert supported runtime question-tool calls into Fusion's durable awaiting-user-input contract so workflow execution cannot continue while the operator question is unanswered.

Fusion-Task-Id: FN-8426
2026-07-20 13:12:22 -07:00
gsxdsm
71c0d0a970 fix(engine): recover completed triage tasks
Preserve workflow ownership across Plan Review replan moves and route advanced completed triage rows through legal lifecycle transitions before review. Clear only stale same-task session claims after live executor, planner, and merger ownership checks.
2026-07-20 08:46:34 -07:00
gsxdsm
876a278afd fix(engine): prevent workflow boundary restart loops (#2360)
## Summary

Workflow tasks no longer restart or become stranded in Planning when the
graph moves through replan and review boundaries. The executor now
distinguishes its own synchronous column transition from an external
cancellation, while preserving the existing hard-cancel behavior for
user and unrelated engine moves.

Existing advanced tasks left in Planning are recovered from durable
worktree and graph-pin evidence: completed work advances through the
normal review handoff, and incomplete remediation resumes at its pinned
execution column. A shared synchronous reservation keeps Planning and
recovery mutually exclusive, and Planning excludes advanced rows so they
cannot consume capacity in a repeated claim/skip loop.

## Validation

- 238 affected engine tests passed, including graph-boundary
cancellation, planner eligibility, ownership races, and advanced-task
recovery coverage.
- `pnpm --filter @fusion/engine typecheck`
- `pnpm verify:fast` — workspace build, CLI bundle, and real
`/api/health` boot smoke passed.


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

## Summary by CodeRabbit

* **Bug Fixes**
* Workflow graph tasks now continue running correctly when crossing
workflow column boundaries.
* Improved recovery of interrupted advanced-triage tasks, including
completed and in-progress work.
* Prevented duplicate triage dispatches and protected tasks from
competing recovery and planning actions.
* Added safeguards for task state changes during recovery and
maintenance operations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-20 00:18:06 -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
3b8220113f fix(FN-8400): recover preserved worktrees in configured root
Relocate same-task worktrees before returning them from branch-conflict recovery so executor liveness validation cannot reject the recovered path in a retry loop.

Fusion-Task-Id: FN-8400
2026-07-19 22:45:41 -07:00
gsxdsm
1f77935358 FN-8307: guard heartbeat task creation with mission lineage
Require autonomous heartbeat work to prove and retain approved mission lineage.

- Validate and persist mission lineage for created and delegated tasks
- Block off-mission heartbeat actions and reconcile roadmap failures without completion
- Renew and release mission symbol locks across workflow lifecycle transitions

Files changed:
 .changeset/fn-8307-heartbeat-mission-guard.md      |   7 ++
 docs/missions.md                                   |   4 +
 packages/core/src/__tests__/symbol-locks.test.ts   |  12 +++
 packages/core/src/task-store/task-update.ts        |  17 +++-
 .../engine/src/__tests__/agent-action-gate.test.ts |   9 +-
 .../src/__tests__/agent-tools-delegation.test.ts   |  41 +++++++-
 .../src/__tests__/gating-classifications.test.ts   |   7 +-
 .../src/__tests__/mission-feature-sync.test.ts     |  10 +-
 .../src/__tests__/mission-symbol-admission.test.ts |  25 +++++
 .../src/__tests__/permanent-agent-gating.test.ts   |   3 +-
 packages/engine/src/agent-action-gate.ts           |  28 +++++-
 packages/engine/src/agent-heartbeat-prompts.ts     |  14 +--
 packages/engine/src/agent-heartbeat.ts             |  34 +++++--
 packages/engine/src/agent-tools.ts                 | 103 +++++++++++++++++++--
 packages/engine/src/executor.ts                    |   2 +-
 packages/engine/src/gating-classifications.ts      |  11 ++-
 packages/engine/src/mission-feature-sync.ts        |  39 +++-----
 packages/engine/src/mission-symbol-admission.ts    |  35 ++++++-
 packages/engine/src/permanent-agent-gating.ts      |  22 +++++
 packages/engine/src/scheduler.ts                   |  21 +++--
 packages/engine/src/step-session-executor.ts       |   2 +-
 packages/engine/src/triage.ts                      |   2 +-
 22 files changed, 369 insertions(+), 79 deletions(-)

Fusion-Task-Id: FN-8307

Fusion-Task-Lineage: 4ca2ccac-db6e-4e5c-9cc6-d62a40d4f30a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-19 22:43:13 -07:00
gsxdsm
fc24e66f63 fix(engine): trust explicit task completion summaries
Stop inferring incomplete work from summary wording so scoped future-work notes cannot requeue completed tasks. Keep structural review and bulk-step completion guards intact.
2026-07-19 17:52:45 -07:00
gsxdsm
c77488e0fa FN-8370: enforce isolated task worktrees
Keep branch-scoped task work in registered worktrees while the primary checkout stays on its current branch.

- Document the executor and acquisition isolation invariant.
- Add real-Git coverage for fresh, unregistered, and reused task worktrees.
- Guard task worktree creation paths against root checkout switches.

Files changed:
 .../worktree-primary-checkout-invariant.test.ts    | 133 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |   7 ++
 packages/engine/src/worktree-acquisition.ts        |   5 +
 3 files changed, 145 insertions(+)

Fusion-Task-Id: FN-8370

Fusion-Task-Lineage: 5153b764-c474-4a52-823e-40b06b43d47c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-19 16:13:17 -07:00
gsxdsm
41f387b219 FN-8364: track task token usage from session deltas
Track only task-local deltas from cumulative session usage.

- Capture and reset baselines for reused, resumed, and heartbeat sessions
- Route executor prompt accounting through the shared per-session delta seam
- Cover token accounting behavior and document the analytics correction

Files changed:
 .changeset/fn-8364-session-token-deltas.md         |  7 +++
 docs/storage.md                                    |  2 +-
 .../src/__tests__/executor-token-usage.test.ts     | 48 +++++++++++++++++++-
 .../src/__tests__/heartbeat-executor.test.ts       | 42 +++++++++++++++++
 .../src/__tests__/session-token-usage.test.ts      | 53 +++++++++++++++++++++-
 packages/engine/src/agent-heartbeat.ts             | 10 +++-
 packages/engine/src/executor.ts                    | 44 +++++++++++-------
 packages/engine/src/session-token-usage.ts         | 20 ++++++++
 8 files changed, 205 insertions(+), 21 deletions(-)

Fusion-Task-Id: FN-8364

Fusion-Task-Lineage: 2b16a581-0d58-4c91-8903-6ce368b30a7c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-19 15:38:31 -07:00
gsxdsm
50454d8a59 fix(FN-7996): release Plan Review fallback lease
Unregister the exact workflow-step path after a repository-root fallback so later Plan Review tasks are not blocked by a stale active-session owner.
2026-07-19 15:28:33 -07:00
gsxdsm
3f7c32c95c refactor(cutover 2/3): engine — graph-owned lifecycle, legacy execution deleted (#2342)
Part **2 of 3** of the IR-driven lifecycle cutover (stacked on #2341;
top is #2335).

**Scope (80 files, packages/engine + cli/pi skill docs +
AGENTS/architecture):** graph-driven column moves via the
column-boundary controller (R1), single-mover scheduler/hold-release
trait cutover (KTD-2/KTD-9), trait re-keyed self-healing + merger with
the R7b confirmed-merge-must-finalize guarantee, graph-exclusive Plan
Review with leased dedup (R4/R5), the executeCore body-lift — zero
legacy re-entry — with fn_review_step + interceptor machinery deleted
and tombstone-ratcheted (R9), builtin workflow runtime fixes (missing
hold handler, unseamed-node column inheritance, no-merge completion
mover), the 6-column benchmark acceptance suite (11 tests) + 12-builtin
lifecycle sweep (94 assertions), and the executor test-harness
modernization. Also retires core's interpreter-cutover scaffolding whose
last consumer (the authoritative driver) dies here.

**Merge order:** #2341 → this → #2335. After #2341 merges, retarget this
to main.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:08:10 -07:00
gsxdsm
b4c1a1ac77 fix(FN-8350): keep tasks running through MCP outages
Retry MCP bootstrap with bounded backoff and request deadlines, then continue with healthy servers when an integration remains unavailable.

Exclude definitions with unresolved secrets so graceful degradation never connects a partially authenticated server.
2026-07-18 21:58:29 -07:00
gsxdsm
38891bfd81 FN-8296: add chat-requested task verification
Enable chat agents to queue and monitor executor-owned verification runs.

- Persist task verification requests through a new PostgreSQL migration.
- Expose action-gated chat request and status tools with executor processing.
- Show verification status in task and Command Center views.
- Advance the schema baseline to migration 0024 and keep chat mocks complete.

Files changed:
 .changeset/fn-8296-feature.md                      |  7 ++
 docs/agent-tool-surface-full-loop.md               | 10 +--
 docs/dashboard-guide.md                            |  4 +
 packages/core/src/index.ts                         |  2 +
 .../core/src/postgres/migrations/0000_initial.sql  | 20 +++++
 .../migrations/0024_task_verification_request.sql  | 20 +++++
 packages/core/src/postgres/schema-applier.ts       | 13 ++-
 packages/core/src/postgres/schema/project.ts       | 25 ++++++
 packages/core/src/store.ts                         | 16 +++-
 packages/core/src/task-store/reads.ts              | 14 +++-
 packages/core/src/task-store/remaining-ops-6.ts    | 49 ++++++++++-
 packages/core/src/types.ts                         | 30 +++++++
 packages/dashboard/app/api/legacy.ts               |  1 +
 packages/dashboard/app/api/task-content.ts         | 10 +++
 .../dashboard/app/components/TaskDetailModal.tsx   | 17 +++-
 .../app/components/TaskVerificationStatus.css      | 94 ++++++++++++++++++++++
 .../app/components/TaskVerificationStatus.tsx      | 39 +++++++++
 .../__tests__/TaskVerificationStatus.test.tsx      | 28 +++++++
 .../components/command-center/CommandCenter.css    | 33 ++++++++
 .../components/command-center/CommandCenter.tsx    | 37 ++++++++-
 packages/dashboard/src/__tests__/chat.test.ts      |  1 +
 packages/dashboard/src/chat.ts                     | 55 +++++++++++++
 .../src/routes/register-command-center-routes.ts   | 20 +++++
 .../src/routes/register-task-workflow-routes.ts    | 17 ++++
 packages/engine/src/executor.ts                    | 51 +++++++++++-
 packages/engine/src/gating-classifications.ts      |  5 ++
 packages/engine/src/index.ts                       |  2 +-
 27 files changed, 605 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-8296

Fusion-Task-Lineage: f94647cf-c89f-4f0e-b25f-cbf5b56683bc

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 18:38:47 -07:00
gsxdsm
059a71f5e9 fix(FN-8288): fail closed when review contract is unavailable
Fusion-Task-Id: FN-8288
2026-07-18 18:00:52 -07:00
gsxdsm
358b628b8d fix(FN-8288): preserve approved review and recovery state
Fusion-Task-Id: FN-8288
2026-07-18 17:24:49 -07:00
gsxdsm
cf1a5991aa fix: stop processing before returning tasks to Todo (#2322)
## Summary

Moving an active task back to Todo could update the board before its
agent and subprocesses had stopped, leaving a Todo card that was still
processing. User-initiated in-progress-to-Todo moves now wait for every
executor cancellation surface before the new column is persisted or
returned to the dashboard. Cancellation is fail-closed and bounded: a
wedged shutdown leaves the task in Progress, releases its lock for
recovery, and fences late cleanup from replacement execution
generations. Engine-driven recovery moves and other transitions retain
their existing behavior.

## Validation

- Confirmed with PostgreSQL-backed symptom tests that the durable row
stays in Progress while cancellation is pending and that a timeout
releases the task lock without publishing Todo.
- Verified multi-executor ownership and replacement-generation fencing
across focused core and engine tests: 18 tests passed.
- Core build, engine typecheck, targeted lint, and strict changeset
validation passed.

---

[![Compound
Engineering](https://img.shields.io/badge/Built_with-Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin)
2026-07-18 14:54:54 -07:00
gsxdsm
bcdad279d7 FN-8289: add feature-video review artifacts
Add gated local feature-video capture to completed user-facing deliverables.

- Capture loopback scenario WebM recordings through the existing artifact registry.
- Keep recording failures non-blocking and cover gated, unsafe, and failed capture paths.
- Document the scenario contract and package the Playwright runtime dependency.

Files changed:
 .changeset/fn-8289-feature-video.md                |   7 +
 docs/workflow-steps.md                             |   8 +
 packages/cli/package.json                          |   3 +-
 packages/cli/tsup.config.ts                        |   7 +
 packages/engine/package.json                       |   3 +-
 .../__tests__/executor-review-artifacts.test.ts    |  44 ++++
 packages/engine/src/executor.ts                    |  33 +++
 .../src/review-artifacts/feature-video.test.ts     |  75 +++++++
 .../engine/src/review-artifacts/feature-video.ts   | 226 +++++++++++++++++++++
 packages/engine/src/review-artifacts/index.ts      |  10 +
 pnpm-lock.yaml                                     |   6 +
 11 files changed, 420 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-8289

Fusion-Task-Lineage: 8a34675a-2417-4669-a14a-b74c4aa99331

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 13:53:58 -07:00
gsxdsm
d51ce46db5 FN-8295: add persisted ideation mission handoffs
Persist bounded ideation sessions through agent tools, the Command Center, and atomic Mission convergence.

- Store ideation sessions and divergent candidates in PostgreSQL with async APIs and migration support.
- Expose gated ideation tools, chat routes, and agent lifecycle integration.
- Add the Ideation panel, documentation, release metadata, and regression coverage.

Files changed:
 .changeset/fn-8295-ideation-diverge-converge.md    |   7 ++
 docs/ideation/persisted-diverge-converge.md        |  22 ++++
 docs/missions.md                                   |   4 +
 .../__tests__/postgres/ideation-store.pg.test.ts   |  57 +++++++++
 packages/core/src/async-ideation-store-queries.ts  | 117 +++++++++++++++++
 packages/core/src/async-ideation-store.ts          | 138 +++++++++++++++++++++
 packages/core/src/async-mission-store.ts           |  27 ++--
 packages/core/src/ideation-types.ts                |  69 +++++++++++
 packages/core/src/index.ts                         |   3 +
 .../core/src/postgres/migrations/0022_ideation.sql |  67 ++++++++++
 packages/core/src/postgres/schema-applier.ts       |  18 ++-
 packages/core/src/postgres/schema/project.ts       |  49 +++++++-
 packages/core/src/store.ts                         |   8 +-
 packages/core/src/task-store/remaining-ops-8.ts    |  14 +++
 .../components/command-center/CommandCenter.tsx    |   7 +-
 .../components/command-center/IdeationPanel.css    |  18 +++
 .../components/command-center/IdeationPanel.tsx    |  58 +++++++++
 .../__tests__/CommandCenter.test.tsx               |   6 +-
 .../dashboard/src/__tests__/chat-manager.test.ts   |   1 +
 packages/dashboard/src/__tests__/chat.test.ts      |   1 +
 .../__tests__/ideation-tool-route-parity.test.ts   |  29 +++++
 packages/dashboard/src/chat.ts                     |   4 +
 packages/dashboard/src/ideation-routes.ts          |  50 ++++++++
 .../src/routes/register-integrated-routers.ts      |   2 +
 .../src/__tests__/agent-ideation-tools.test.ts     |  40 ++++++
 .../src/__tests__/gating-classifications.test.ts   |  16 +++
 .../src/__tests__/permanent-agent-gating.test.ts   |   2 +
 packages/engine/src/agent-heartbeat.ts             |   4 +-
 packages/engine/src/agent-tools.ts                 |  67 ++++++++++
 packages/engine/src/executor.ts                    |   2 +
 packages/engine/src/gating-classifications.ts      |   8 ++
 packages/engine/src/index.ts                       |   1 +
 packages/engine/src/triage.ts                      |   2 +
 33 files changed, 897 insertions(+), 21 deletions(-)

Fusion-Task-Id: FN-8295

Fusion-Task-Lineage: 1b8b0752-22bd-4b2f-aebd-4305c63abcf9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 13:18:08 -07:00
gsxdsm
b533b918fe fix(FN-8064): narrate all task step transitions
Fusion-Task-Id: FN-8064
2026-07-18 12:21:08 -07:00
gsxdsm
8d1620ea23 FN-8294: expose action-gated Mission hierarchy tools
Expose project-scoped Mission hierarchy operations to engine agents and eligible dashboard chat sessions.

- Add Mission, milestone, slice, and feature tool definitions backed by MissionStore
- Classify hierarchy mutations for action and permanent-agent approval gates
- Wire gated tool access through triage, executor, heartbeat, CLI, and chat lanes
- Cover tool availability, mutation gating, and chat integration with tests and documentation

Files changed:
 .changeset/fn-8294-mission-engine-tools.md         |   7 ++
 docs/missions.md                                   |   8 ++
 packages/cli/src/extension.ts                      |   2 +-
 .../dashboard/src/__tests__/chat-manager.test.ts   |  48 +++++++++
 packages/dashboard/src/__tests__/chat.test.ts      |   1 +
 packages/dashboard/src/chat.ts                     | 113 ++++++++++++++++++++-
 .../src/__tests__/agent-mission-tools.test.ts      |  43 ++++++++
 packages/engine/src/__tests__/triage.test.ts       |  34 ++++++-
 packages/engine/src/agent-heartbeat.ts             |   4 +-
 packages/engine/src/agent-tools.ts                 |  64 ++++++++++++
 packages/engine/src/executor.ts                    |   2 +
 packages/engine/src/gating-classifications.ts      |  11 ++
 packages/engine/src/index.ts                       |  17 ++++
 packages/engine/src/triage.ts                      | 111 ++++++++++++++++++++
 14 files changed, 457 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-8294

Fusion-Task-Lineage: ab0f248b-8a38-40e3-b297-79f9dbe18075

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 10:31:59 -07:00
gsxdsm
7c23771433 FN-8265: add task follow-up proposal creation
Enable configured ephemeral workers to propose and create follow-up tasks from mailbox messages.

- Add persisted task-proposal claim state, migrations, and async messaging APIs.
- Register task-proposal creation routes, SSE events, agent tool support, and CLI integration.
- Add mailbox creation controls, settings, documentation, localization, and regression coverage.

Files changed:
 .changeset/fn-8265-task-follow-up-policy.md        |   7 ++
 docs/dashboard-guide.md                            |   2 +-
 docs/settings-reference.md                         |  12 ++-
 packages/cli/src/extension.ts                      |  34 ++++---
 .../src/__tests__/postgres/sqlite-migrator.test.ts |  14 ++-
 .../postgres/task-proposal-claim.pg.test.ts        |  51 +++++++++++
 packages/core/src/async-message-store.ts           |  39 ++++++++
 packages/core/src/index.gate.ts                    |   4 +-
 packages/core/src/index.ts                         |   4 +-
 packages/core/src/message-store.ts                 |  46 ++++++++++
 .../core/src/postgres/migrations/0000_initial.sql  |   2 +
 .../migrations/0020_task_proposal_claim.sql        |   4 +
 packages/core/src/postgres/schema-applier.ts       |  13 ++-
 packages/core/src/postgres/schema/project.ts       |   3 +
 packages/core/src/settings-schema.ts               |  19 +++-
 packages/core/src/task-store/async-persistence.ts  |   2 +-
 packages/core/src/task-store/persistence.ts        |   4 +-
 packages/core/src/task-store/serialization.ts      |   1 +
 packages/core/src/task-store/task-creation.ts      |  51 +++++++++++
 packages/core/src/task-store/task-row-mappers.ts   |   2 +-
 packages/core/src/types.ts                         |  56 +++++++++++-
 packages/dashboard/app/api/legacy.ts               |   5 +
 packages/dashboard/app/components/MailboxModal.tsx |   4 +
 .../app/components/MailboxTaskProposal.css         |   3 +
 .../app/components/MailboxTaskProposal.tsx         |  33 +++++++
 packages/dashboard/app/components/MailboxView.tsx  |   4 +
 .../__tests__/MailboxTaskProposal.test.tsx         |  43 +++++++++
 .../app/components/settings/section-keys.ts        |   2 +-
 .../settings/sections/GeneralSection.search.ts     |  13 ++-
 .../settings/sections/GeneralSection.tsx           |  22 +++--
 .../settings-default-descriptions.test.tsx         |   4 +-
 .../routes/__tests__/task-proposal-routes.test.ts  |  99 ++++++++++++++++++++
 .../src/routes/register-messaging-scripts.ts       | 101 +++++++++++++++++++++
 packages/dashboard/src/sse.ts                      |   7 ++
 packages/engine/src/agent-tools.ts                 |  30 ++++--
 packages/engine/src/executor.ts                    |   9 +-
 packages/engine/src/step-session-executor.ts       |   8 +-
 packages/i18n/locales/en/app.json                  |   5 +
 38 files changed, 696 insertions(+), 66 deletions(-)

Fusion-Task-Id: FN-8265

Fusion-Task-Lineage: 4e864a2f-3485-4a54-8be7-1699b5479a94

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 03:48:38 -07:00
gsxdsm
5acea6c0cf fix(pg): route residual SQLite-stub store paths through the async data layer (#2273)
## Summary

An audit of the SQLite→PostgreSQL store migration found data-store paths
still reaching the removed SQLite stub in backend (PG) mode. In backend
mode `store.db`/`getDatabase()` throw the removed-SQLite error, so each
of these either threw on every run or — worse — had the throw swallowed
into a silent wrong result. This PR routes all of them through the
`AsyncDataLayer` (and removes one dead primitive).

## The 6 live bugs fixed

| Fix | Was |
|-----|-----|
| `executor.ts` authoritative assigned-agent fallback now inherits the
TaskStore `asyncLayer` | silently returned `null` → model drift to the
pi built-in (the exact thing its comment guards) |
| `pruneAgentLogFilesAsync` replaces the sync self-healing prune call |
threw `SQLite Database is not available` every maintenance sweep →
agent-log pruning never ran |
| `cleanupOrphanedMaterializedSteps` deletes PG `workflow_steps` rows on
a failed create | swallowed the throw → leaked rows |
| `deleteTaskBackendImpl` now runs the async mission feature/task-link
unlink | PG hard delete left orphaned mission links |
| `getWorkflowSettingsProjectId` returns `rootDir` in backend mode
without touching the stub | swallowed throw for unscoped backend stores
|
| `fn plugin` unregistered-project fallback bootstraps a `CentralCore`
`AsyncDataLayer` | layerless `PluginStore` threw in PG |

## The 4 latent traps, fixed properly

- **`cleanupArchivedTasks`** — real async port (enumerate archived
soft-deleted rows, guarantee cold snapshot, hard-delete project row +
purge selection rows + rm dir).
- **`deleteWorkflowStep`** — real async port (delete `workflow_steps`
via the layer with `.returning()` to preserve the not-found contract).
- **`applyTaskPatch`** — **removed** (zero-caller SQLite column-patch
primitive with no backend analogue; impl + facade + import deleted).
- **`AgentStore.importLegacyFileRuns`** — clean backend no-op (no legacy
SQLite run-files exist in a PG deployment; its only `init()` caller
early-returns in backend mode).

## Symptom Verification

New PG regression suite
`packages/core/src/__tests__/postgres/store-sqlite-residue-fixes.pg.test.ts`
reproduces the original failures against real embedded Postgres and
asserts they're gone:
- orphaned `workflow_steps` are actually deleted (no swallowed throw)
- `pruneAgentLogFilesAsync` resolves and prunes inactive-task log files
- hard delete unlinks the mission feature from the task
- `deleteWorkflowStep` removes the row / reports not-found
- `cleanupArchivedTasks` hard-deletes the project row while retaining
the cold snapshot

## Verification

- `@fusion/core`, `@fusion/engine`, `@runfusion/fusion` typecheck clean
- ~50 existing + 5 new PG tests pass; lint clean; changeset validates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* **Bug Fixes**
* Prevented PostgreSQL backend maintenance from hitting removed legacy
SQLite code paths, avoiding datastore failures and residue cleanup
issues.
* Fixed workflow-step deletion and “not found” behavior in backend mode.
* Ensured backend hard-deletes correctly unlink related mission
feature/task links and clean orphaned materialized steps.
* Prevented legacy file-run imports from incorrectly reporting success
in backend mode.
* **New Features**
* Added async agent-log pruning for inactive tasks and updated
maintenance to use it.
* **Tests**
* Added PostgreSQL regression coverage for residue fixes and
archive/workflow cleanup.
* **Refactor**
* Removed an unused task patch operation and updated task-store cleanup
methods to be async where needed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:22:21 -07:00
gsxdsm
eb7d223a03 FN-8207: add task reassignment for delegated work
Correct delegation routing for duplicate tasks and enable explicit task owner reassignment.

- Preserve requested assignee and todo routing on duplicate canonical tasks
- Add governed fn_task_assign to engine, heartbeat, triage, workflow, and chat sessions
- Cover assignment validation, truthful delegation responses, and tool availability

Files changed:
 .changeset/fn-8207-delegate-assign.md              |   7 ++
 docs/agents.md                                     |   6 ++
 packages/core/src/types.ts                         |   1 +
 packages/core/src/usage-events.ts                  |   2 +-
 .../dashboard/src/__tests__/chat-manager.test.ts   |   2 +
 packages/dashboard/src/__tests__/chat.test.ts      |   2 +
 packages/dashboard/src/chat.ts                     |   2 +
 .../engine/src/__tests__/agent-action-gate.test.ts |   2 +
 .../src/__tests__/agent-tools-delegation.test.ts   |  99 ++++++++++++++++++-
 .../src/__tests__/agent-tools-task-assign.test.ts  |  75 +++++++++++++++
 .../src/__tests__/gating-classifications.test.ts   |   1 +
 .../src/__tests__/heartbeat-executor.test.ts       |   8 +-
 .../src/__tests__/permanent-agent-gating.test.ts   |   2 +
 .../src/__tests__/step-session-executor.test.ts    |   4 +-
 packages/engine/src/__tests__/triage.test.ts       |   5 +-
 packages/engine/src/agent-heartbeat.ts             |   4 +-
 packages/engine/src/agent-tools.ts                 | 105 ++++++++++++++++++++-
 packages/engine/src/executor.ts                    |   3 +
 packages/engine/src/gating-classifications.ts      |   1 +
 packages/engine/src/index.ts                       |   2 +
 packages/engine/src/step-session-executor.ts       |   2 +
 packages/engine/src/triage.ts                      |   2 +
 22 files changed, 324 insertions(+), 13 deletions(-)

Fusion-Task-Id: FN-8207

Fusion-Task-Lineage: db6f3876-bdc8-4279-b726-29344d9acdb9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 10:53:19 -07:00
gsxdsm
7a50232916 FN-8208: validate agent message recipients before delivery
Prevent false-success agent messages by validating recipients before delivery.

- Wire AgentStore into every send-message tool registration.
- Reject missing or unvalidated agent recipients before persistence or wake-up.
- Add recipient validation coverage and a patch changeset.

Files changed:
 .../fn-8208-send-message-recipient-validation.md   |   7 ++
 .../chat-send-message-agentstore-wiring.test.ts    |  11 ++
 packages/dashboard/src/chat.ts                     |   2 +-
 ...tools-send-message-recipient-validation.test.ts | 116 +++++++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             |   4 +-
 packages/engine/src/agent-tools.ts                 |  24 ++++-
 packages/engine/src/executor.ts                    |   2 +-
 packages/engine/src/step-session-executor.ts       |   2 +-
 8 files changed, 162 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-8208
Fusion-Task-Lineage: 84752bb8-c9f7-42bd-87c1-9681ac442789
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 10:07:24 -07:00
gsxdsm
7760d783bd fix: green full-suite after getAgentLogCount and inventory drift (#2266)
## Summary
- Follow-up after #2229: full suite on main still failed on dashboard
curated inventory (21 ungated files) and mass engine failures
(`this.store.getAgentLogCount is not a function`).
- Harden executor tool-failure cursor capture for minimal/test
`TaskStore` adapters (same optional-API pattern as `project-engine`),
keep mock fixtures in lockstep, and quarantine inventory-only dashboard
files with ledger + vitest exclude.

## Changes
- **Executor**: optional `getAgentLogCount` / `getAgentLogs` /
`updateTask` at graph entry and trailing-failure detection.
- **Mocks**: `createMockStore`, soft-delete guard, post-done
continuation, cron `getGlobalSettingsDir`, executor-prompt
`bulkCompletionRefusalAt` (FN-8141).
- **i18n** (prior commit): es/fr/ko/zh-CN/zh-TW triage-duplicate keys.
- **Inventory**: 21 dashboard files → `test-quarantine.json` +
`vitest.config.ts` lockstep (VAL-REMOVAL SQLite / load flakes /
build-only dist assert).

## Test plan
- [x] `node scripts/check-test-inventory.mjs --dashboard-curated`
- [x] `pnpm test:gate`
- [x] engine: soft-delete, prompt, cron, post-done, tool-failure-retry,
and related samples
- [x] `@fusion/core` schema-applier + `@fusion/i18n` parity
- [ ] Full Suite (non-blocking) on this PR / main after merge

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

## Summary by CodeRabbit

- **New Features**
- Added localized text for triage duplicate-resolution settings and
near-duplicate task actions in Spanish, French, Korean, Simplified
Chinese, and Traditional Chinese.
- Users can now see translated options and confirmations to keep or
delete detected duplicate tasks.

- **Bug Fixes**
- Improved resilience during task execution and recovery when optional
activity-log services are unavailable, preventing avoidable failures
during error handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-16 23:44:35 -07:00
gsxdsm
daa34fbc38 fix: refineTask/duplicateTask fail in backend (PostgreSQL) mode (#2253)
## Summary

Eliminates the remaining backend/PostgreSQL-mode sync-SQLite
(`store.db`) call sites — both the crashing ones and the
try/catch-masked ones that silently degraded features. Found via a full
audit of `store.db`/`archiveDb` residue after the PG cutover's per-site
routing missed them.

**Crashes fixed:**
1. **refineTask / duplicateTask** threw `TaskStore.db: SQLite Database
is not available in backend mode`. Both create rows through
`createTaskWithId` callbacks calling `store.atomicCreateTaskJson()`
directly, bypassing `_createTaskInternal`'s backend routing. The shared
helper now routes itself (soft-delete conflict check + non-destructive
insert in one AsyncDataLayer transaction).
2. **Merger verification cache**: `getVerificationCacheHit` ran sync
SQLite unguarded *outside* any try/catch in
`runDeterministicVerification`; `recordVerificationCachePass` was
swallowed so the cache never warmed. Both are now async with a PG
branch.

**Silent degradations fixed (features that were dead on PG):**
- Workflow run-branch + foreach step-instance persistence
(`saveWorkflowRunBranch`, `loadWorkflowRunBranches`,
`clearWorkflowRunBranches`, `saveWorkflowRunStepInstance`,
`loadWorkflowRunStepInstances`, `clearWorkflowRunStepInstances`) —
executor crash-resume checkpoints were silently never persisted.
- `getBranchProgressByTask` — returned an empty map, dropping
`branchProgress` from task payloads.
- `runPluginColumnTransitionHooks` — plugin `onEnter`/`onExit`
column-transition hooks never fired (marker bookkeeping + non-locking
task read now async).
- `getTaskColumns` — dashboard treated all agent-linked tasks as
non-terminal.
- `getWorkflowStep` / `listWorkflowSteps` — stored workflow-step rows
now read from `project.workflow_steps` (listing previously returned
plugin steps only); `getLegacyWorkflowStepSnapshot` returns `undefined`
on PG (legacy snapshot exists only in pre-migration SQLite).
- `readRawProjectSettings` / `listWorkflowPromptOverridesForProject` —
now read via the async layer.

These store methods became **async**; engine/dashboard callers await
them (the workflow persistence interfaces already accepted
`Promise`-returning impls).

**PG gotcha encoded in the fixes:** migration `0006_project_ownership`
rebuilds every project-schema PK to lead with `project_id`, so
column-list `ON CONFLICT` inference fails (42P10) — upserts target the
PK by constraint name.

## Surface Enumeration

- Creators through `atomicCreateTaskJson`: `refineTaskImpl`,
`duplicateTaskImpl` (fixed); `_createTaskInternalImpl` unaffected
(already routed).
- Verification-cache callers (all merger, all 3 sites now awaited).
- Run-branch/step-instance callers: executor persistence adapters,
parse-steps foreach probe, integration-queue flip, crash-resume
reconcile, graph-reset cleanup; triage replan cleanup; dashboard
spec-rebuild pin clears; agent-reflection rework summing — all awaited.
- Audit classified everything else as guarded or sync-mode-only (dead in
production — every entry point constructs stores via
`createTaskStoreForBackend`).

## Symptom Verification

- **Original symptoms:** refinement/duplicate creation threw; merge
verification threw; workflow checkpoints/branch progress/plugin
hooks/task-column lookups silently no-oped on PostgreSQL.
- **Exact reproduction:** `refine-duplicate-task.pg.test.ts`,
`verification-cache.pg.test.ts`, and
`sync-db-residue-backend.pg.test.ts` exercise each surface against
embedded-PostgreSQL backend-mode TaskStores.
- **Assertion it is gone:** all suites pass (14 + 5 tests), plus
`transition-pending-and-status-clear.pg.test.ts`,
`create-task-reserved-id.pg.test.ts`, dashboard `routes-github.test.ts`
(123), engine `triage.test.ts` (221) and `agent-reflection.test.ts`
(31). Core/engine/dashboard typecheck fully clean: the 13 errors from
the FN-8142 pi SDK migration are fixed by bumping
@earendil-works/pi-ai/pi-coding-agent to ^0.80.10 (FN-8142 used APIs
absent from the previously locked 0.80.6). Locally green: `pnpm
verify:fast` (scoped typecheck + build + CLI build + boot smoke), `pnpm
test:gate`, and `pnpm lint`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* **Bug Fixes**
* Fixed refinement/duplication task creation in PostgreSQL-backed
backend mode.
* Improved backend-mode persistence for workflow checkpoints,
foreach-step instances, branch progress, and cleanup flows (including
retries/resets/transitions), so stored data reliably round-trips.
* Hardened backend-mode reads for workflow steps, task columns, project
settings, and prompt overrides.
* Made verification-cache reads/writes complete reliably, including
command-specific cache behavior.
* **Tests**
* Added PostgreSQL integration/regression coverage for
refinement/duplication, sync residue, and verification caching.
* **Chores**
* Bumped `@earendil-works/pi-ai` and `@earendil-works/pi-coding-agent`
to `^0.80.10`.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 22:35:01 -07:00
gsxdsm
f116d05c41 fix(engine): honest BLOCKED park survives pause-abort and workflow-graph teardown (#2264)
## What

Follow-up 1 to the FN-8141 guard series (#2254–#2260). Makes the honest
`fn_task_done(outcome="blocked")` park (`status:"failed"`,
`error:"BLOCKED: <reason>"`, blockedBy → dependencies, added in #2256)
**survive the graph-teardown machinery** that bounced FN-8141's failed
park back to `todo`.

## Why

In the original FN-8141 incident, the executor's parked-failed state did
not stick: the pause-abort classifier and the workflow-graph failure
handler either rehomed the task to `todo` (clearing `status`/`error`) or
overwrote the distinctive `BLOCKED:` error with a generic "Workflow
graph terminated with failure" string. #2256 added the blocked exit but
nobody proved the park survives that bounce. Any path that
clears/overwrites the marker re-opens the laundering hole, because
self-healing (#2257/#2260) and dependency-gated scheduling key off
exactly that `BLOCKED:` error plus the recorded `blockedBy`
dependencies.

`handleGraphFailure` now detects a live blocked park (`status ===
"failed" && error.startsWith("BLOCKED:")`) **before every other
classifier** and honors it, following the existing non-graph honor-park
precedent (executor `~12163`):

- no requeue to `todo`, no engine-internal auto-continue, no `BLOCKED:`
error overwrite;
- clears the in-memory pause-abort marker so
`recoverPausedAbortFailures` has nothing to chase;
- **releases the worktree / `maxWorktrees` slot** (FN-6782 leaked-holder
precedent — the graph `finally` does not delete `activeWorktrees`);
- leaves `status`/`error`/`column`/`dependencies`/steps untouched.

Unblocking still works: the operator requeue (`moveTask`
in-progress→todo, `moves.ts ~628`) and `buildManualRetryResetPatch`
clear the `BLOCKED:` error; the guard keys off the **live** error, so a
cleared row is never re-wedged, and dependency-gated scheduling leaves
the parked row untouched while `blockedBy` deps are unmet.

## Surfaces covered

Pause-abort classifier (hard-cancel), engine-internal auto-continue, and
the plain terminal graph-failure sink — all routed through
`handleGraphFailure`, so a single top-of-method guard composes across
them.

## Test evidence

Extended `executor-task-done-blocked.test.ts` (drives
`handleGraphFailure` against a live blocked park):
- honors the park under a hard-cancel pause-abort bounce (no requeue /
clear / auto-continue);
- honors it under a plain terminal graph failure (sink never overwrites
`BLOCKED:`);
- releases the worktree/concurrency slot + clears the pause-abort
marker;
- NON-blocked failed park keeps existing behavior (guard scoped to
`BLOCKED:`);
- a cleared (unblocked) row is NOT re-honor-parked.

```
pnpm --filter @fusion/engine exec vitest run src/__tests__/executor-task-done-blocked.test.ts  → 13 passed
pnpm --filter @fusion/engine exec vitest run executor-paused-abort-todo-benign + executor-graph-requeue-gate  → 53 passed
pnpm --filter @fusion/engine exec tsc --noEmit  → clean
pnpm verify:fast  → PASS (3 steps green)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus <noreply@anthropic.com>
2026-07-16 21:39:16 -07:00
gsxdsm
a136535f15 fix(engine): taint steps skipped after a bulk-completion refusal so they cannot auto-promote (#2260)
## What & why

**FN-8141 laundered a failed task into `done` with zero net changes and
no sign-off.** After the executor's
`bulk-step-completion-without-review` refusal fired (steps had no
APPROVE verdicts), the agent used the sanctioned skip affordance
(`fn_task_update status="skipped"`) on the remaining unreviewed steps.
Because every completion check counts `skipped` as complete, the task
then satisfied the exact condition the refusal was protecting, and
downstream **automatic** promotion (implicit `fn_task_done`,
self-healing `recoverStrandedCompletedTodoTasks`) moved it to in-review
— where the AI merger found an empty diff and finalized it as a no-op
`done`.

This PR restores the invariant: **steps skipped while a
bulk-step-completion refusal marker is active on the task are "tainted"
and cannot carry the task to review through any automatic path.** The
taint clears on an honest exit — an accepted `fn_task_done` (explicit or
non-tainted implicit) or an operator manual retry — so the legitimate
`PREMISE STALE` skip-then-done flow is unaffected.

## Design

- **Persisted marker**: new nullable `Task.bulkCompletionRefusalAt` (ISO
timestamp), stamped when the `bulk-step-completion-without-review`
refusal fires (explicit `fn_task_done` handler + implicit
`handleImplicitTaskDoneRefusal`). Survives requeue so a refusal on
attempt N taints attempt N+1's promotion. Full store plumbing (types,
descriptors, serialization, SQLite/PG schema + health self-heal).
- **Pure evaluator** `evaluateSkipBypassTaint(task)` in `@fusion/core`
(next to `evaluateNoCommitsNoOpFinalize`): `blocked` iff the marker is
set AND ≥1 step is `skipped`. Single rule every AUTO-promotion check
calls.
- **Clearing**: accepted explicit `fn_task_done`, accepted
implicit/retry completion (the success-reset `updateTask`s), and
`buildManualRetryResetPatch` (operator retry). A fresh lifecycle that
genuinely re-does the work leaves zero skipped steps, so it is never
blocked even if a marker lingers.

## Surface enumeration (every consumer of "all steps done/skipped" that
gates AUTO-promotion)

- **executor.ts**: `getCompletedTaskFinalizationDecision` (gated on the
`isTaskWorkComplete` branch only, never on an accepted `taskDone`);
`recoverCompletedTask` (shared chokepoint for unpause resume,
completed-task watchdog, orphan resume);
`evaluateImplicitCompletionRefusal` (both implicit-completion loops);
`isTaskAlreadyCompleteForNonContinuableSession`; graph merge-boundary
`getWorkflowMergeImplementationProofFailure`.
- **self-healing.ts**: `recoverCompletedTasks` (stuck in-progress) and
`recoverStrandedCompletedTodoTasks` (the exact FN-8141 promoter).
- **Verified-safe, left as-is**: per-step graph node projections
(executor ~6274/6298) and progress-render checks — they don't gate
whole-task auto-promotion.

## Test evidence

Scoped runs (all green):

```
CORE:   pnpm --filter @fusion/core exec vitest run \
          src/__tests__/skip-bypass-taint-guard.test.ts \
          src/__tests__/skip-bypass-taint-persistence.test.ts \
          src/__tests__/manual-retry-reset.test.ts
        → 17 passed

ENGINE: pnpm --filter @fusion/engine exec vitest run \
          src/__tests__/executor-skip-bypass-taint.test.ts \
          src/__tests__/self-healing.test.ts
        → 401 passed
```

Coverage: pure-evaluator (skip-before-refusal counts, skip-after-refusal
doesn't, taint-clearing, empty-marker/empty-steps edges); store
round-trip of the marker (set→read→clear); executor white-box (implicit
completion refused when tainted, allowed when clean or fully re-done,
graph merge-boundary reports missing proof, and the **explicit
`fn_task_done` PREMISE-STALE honest exit stays accepted**); self-healing
(FN-8141 sequence does not promote from either recovery path; a clean
legitimately-skipped task still promotes); manual-retry clears the
marker.

## Note on `pnpm verify:fast`

`verify:fast` currently fails at the workspace-artifact bootstrap on
**pre-existing** pi-SDK type errors in
`packages/engine/src/{auth-storage,pi,provider-registration}.ts` — the
FN-8145 upstream migration breakage (pi 0.80.x removed
`AuthStorage`/`ModelRegistry.create`). **None of those files are in this
diff.** `@fusion/core` builds clean (`packages/core build: Done`), and
`@fusion/engine` `tsc` reports **no errors in the files this PR
touches** (`executor.ts`, `self-healing.ts`); the only engine build
errors are the FN-8145 files. This base failure is the same condition
FN-8141 describes and is out of scope for this task.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus <noreply@anthropic.com>
2026-07-16 20:37:05 -07:00
gsxdsm
29543a0aac FN-8157: add PostgreSQL workflow step-instance persistence
Persist workflow foreach step-instance state through async PostgreSQL store APIs.

- Add async save, load, and stale-run pruning operations backed by Drizzle.
- Route executor persistence, recovery, and integration projection through async APIs.
- Cover PostgreSQL persistence and migrate foreach wiring coverage to the PG harness.
- Quarantine unrelated flaky route and triage tests per the test ledger.

Files changed:
 .../workflow-run-step-instances.pg.test.ts         | 100 +++++++++++++++++++
 packages/core/src/store.ts                         |  14 ++-
 packages/core/src/task-store/remaining-ops-6.ts    | 109 ++++++++++++++++++++-
 .../dashboard/src/__tests__/routes-github.test.ts  |  14 +--
 .../src/routes/register-task-workflow-routes.ts    |  18 ++--
 packages/engine/src/__tests__/triage.test.ts       |   6 +-
 .../src/__tests__/workflow-foreach-wiring.test.ts  |  59 +++++------
 packages/engine/src/executor.ts                    |  57 ++++++++---
 packages/engine/src/triage.ts                      |   4 +-
 packages/engine/vitest.config.ts                   |   2 +-
 scripts/lib/test-quarantine.json                   |   7 +-
 11 files changed, 315 insertions(+), 75 deletions(-)

Fusion-Task-Id: FN-8157

Fusion-Task-Lineage: c359f0d3-9191-4d27-aaed-9912419c5c27

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 20:36:45 -07:00
gsxdsm
136958fc60 fix(engine): stranded-completed promoters withhold tasks whose last execution ended in a failure park (#2257)
## What & why

FN-8141 laundered a failed task into `done`. The executor correctly
parked the task `failed` ("task parked failed during no-fn_task_done
retry" / "fn_task_done refusal retry budget exhausted"), the pause-abort
machinery bounced it to `todo`, and ~12 minutes later
`recoverStrandedCompletedTodoTasks` promoted it to `in-review` because
every step was done/skipped — overriding the honest failure park. From
there the AI merger found an empty diff and finalized it as a no-op
`done`, with no reviewer ever seeing it.

Existing exclusions (`task.error`,
`evaluateNoCommitsNoOpFinalize().blocked`, active statuses, refreshing
review state) all missed it because the failure provenance lived **only
in the durable task log** by the time the promoter ran — status/error
had been cleared by the pause-abort bounce.

This PR restores the invariant: **a stranded-completed promoter must not
promote a task whose most recent execution lifecycle ended in a
failure/refusal park.**

## Change

- New pure, unit-testable evaluator
`evaluateCompletedPromotionFailureProvenance(task)` in `@fusion/core`
(next to `no-commits-finalize-guard.ts`). It scans the task-log **tail**
(bounded to 250 entries) and lets the **most-recent execution-outcome
marker** decide: a failure/refusal park → `{ blocked: true, reason:
"failure-provenance" }`; a fresh clean completion (`Task marked done by
agent` / `All steps complete — implicit fn_task_done`) that appears more
recently supersedes an earlier park; zero failure markers → not blocked.
Recency is by construction, so a failure that predates a newer clean
execution is never reached.
- Both self-healing sweeps (`recoverCompletedTasks` stuck-in-progress
**and** `recoverStrandedCompletedTodoTasks` stranded-todo) fetch the
full task for candidates that already cleared the cheap slim filters
(slim listings strip `log`) and skip when blocked, emitting a
**deduped** `task:reconcile-stranded-completed-no-action` run-audit
event (ids/outcomes-only: `taskId`, `reason`, `sweep`, `marker?`).
- Defense-in-depth: the shared executor `recoverCompletedTask`
chokepoint — which the sweeps AND the executor's own
unpause/`resumeOrphaned` fast-paths all funnel through — also refuses a
provenance-blocked promotion, so no route can launder a failed park.

**Escape hatch (documented in FNXC comments):** an operator
retrying/moving the task starts a fresh execution whose clean-completion
marker supersedes the failure park, clearing the block with no code
change.

## Surface enumeration

- `recoverCompletedTasks` (stuck-in-progress sweep, self-healing.ts) —
guarded + audited.
- `recoverStrandedCompletedTodoTasks` (stranded-todo sweep,
self-healing.ts) — guarded + audited. FN-8141 shows both columns can
launder.
- `recoverCompletedTask` executor callback (the route both sweeps +
unpause + `resumeOrphaned` share) — verified it did **not** check
log-based provenance; added the guard there as the final chokepoint.

## Test evidence

Pure-evaluator unit tests (`@fusion/core`) — marker detection,
most-recent-outcome recency, supersede-by-clean-completion,
empty/missing log, tail-scan bound:
```
pnpm --filter @fusion/core exec vitest run src/__tests__/completed-promotion-failure-provenance.test.ts
  Test Files  1 passed (1)   Tests  9 passed (9)
```

Self-healing integration tests (`@fusion/engine`) — FN-8141-shaped todo
(3 done + 2 skipped + refusal-exhaust/park marker) is NOT promoted and
emits the no-action event exactly once (deduped across a second cycle);
same task after a fresh clean execution IS promoted; stuck-in-progress
variant covered:
```
pnpm --filter @fusion/engine exec vitest run src/__tests__/self-healing.test.ts -t "recoverCompletedTasks|recoverStrandedCompletedTodoTasks|FN-8141"
  Test Files  1 passed (1)   Tests  14 passed | 382 skipped (396)
```

`@fusion/core` builds clean. My engine changes add **zero** new type
errors (verified: all 13 engine build errors are the pre-existing pi-SDK
cluster in `auth-storage.ts`/`pi.ts`/`provider-registration.ts`, none in
`self-healing.ts`/`run-audit.ts`/`executor.ts`/the new file).

## Known environmental blocker

`pnpm verify:fast` cannot go green on this branch: the `@fusion/engine`
build is **already broken at baseline** (confirmed by stashing all my
changes) by the pi 0.80.x SDK migration errors
(`ModelRegistry`/`AuthStorage`/`ModelRuntime`) — the exact FN-8145
upstream breakage described in the FN-8141 incident. That is out of
scope for this task and independent of this diff. Likewise, the 22
pre-existing
`restart.integration.test.ts`/`executor-fast-mode-workflows.test.ts`
failures are identical with and without my changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus <noreply@anthropic.com>
2026-07-16 19:36:57 -07:00
gsxdsm
9a37415887 fix(engine): add honest blocked exit to fn_task_done so impossible tasks park failed instead of laundering to done (#2256)
## What & why

FN-8141 ("Update pi SDK to latest and verify Kimi K3 end to end") was
impossible as specced — pi 0.80.x removed `AuthStorage`/`ModelRegistry`
APIs, so every SDK bump broke the build. The executor correctly reverted
its work and filed follow-up FN-8145 — but had **no sanctioned way to
end the task in a blocked state**. `fn_task_done` only expressed
success: the bulk-completion gate refused it, the requeue budget re-ran
the doomed task 5 times, and the only remaining affordance (mark every
step `skipped`, then complete) made `isTaskComplete()` return true.
Self-healing then promoted the "complete" todo to in-review and the AI
merger finalized the empty diff as `done`. **The honest path must be
cheaper than the laundering path.**

This adds a first-class **blocked** outcome to the executor's
`fn_task_done` tool.

## Change

- `fn_task_done` gains `outcome: "completed" | "blocked"` (default
`"completed"`), optional `blockedBy: string[]`, and `reason` (required
when blocked).
- `outcome="blocked"` runs **before** every completion gate (completion
blocker, verdict providers, worktree invariants, bulk-completion
refusal) — blocked is not a completion claim, so none of those gates
apply.
- Parks the task `failed` with `error = "BLOCKED: <reason>"`, following
the FN-7863 `EXECUTION_DISPATCH_LOOP_EXHAUSTED` park convention: **steps
keep their true statuses** (no auto-done, no auto-skip), worktree/branch
preserved. It does **not** call `onDone()`, so the executor's existing
`status === "failed"` post-loop branch honors the park instead of
handing off to review.
- `blockedBy` is recorded as real `task.dependencies` edges (unioned
with existing) so the task requeues behind the blocker.
- Emits run-audit `task:execution-blocked-parked` with ids/outcomes-only
metadata (`taskId`, `blockedBy` ids, `hasReason` boolean — **never** the
reason prose).
- Executor + core prompt guidance and the
`bulk-step-completion-without-review` refusal message now name the
blocked exit as **the** correct action when work cannot proceed,
replacing skip-and-done. `PREMISE STALE:` skip guidance is preserved for
genuinely-stale premises.

## Surface enumeration

- **fn_task_done tool schema + handler**
(`packages/engine/src/executor.ts`): blocked branch added at the top of
`execute`, before all gates.
- **Refusal/requeue machinery**: `formatTaskDoneRefusal` for
`bulk-step-completion-without-review` now points at the blocked exit;
the requeue-budget path is untouched (blocked never enters it).
- **Executor prompt text**: turn-ending rules, the "Cannot proceed"
section, the preflight/stale-premise escape hatch (now explicitly
distinguishes stale-premise skip from blocked).
- **Core prompt mirror** (`packages/core/src/agent-prompts.ts`): same
turn-ending + cannot-proceed guidance.
- **Tool reference doc**
(`packages/cli/skill/fusion/references/engine-tools.md`): `fn_task_done`
params updated. (grep for `fn_task_done` confirmed the only executable
tool schema is in executor.ts; CLI/pi surfaces re-export it, no separate
schema copy.)
- **Self-healing**: verified a blocked-parked row is NOT auto-recovered
by `recoverStrandedCompletedTodoTasks` — its steps are not all
done/skipped and `task.error` is set (both are hard filters in the
sweep).
- **Run Audit inventory** (`AGENTS.md`): documented the new event.

## Test evidence

New `packages/engine/src/__tests__/executor-task-done-blocked.test.ts`
(8 tests) asserts the invariant across surfaces:

```
pnpm --filter @fusion/engine exec vitest run \
  src/__tests__/executor-task-done-blocked.test.ts \
  src/__tests__/executor-task-done-invariant.test.ts \
  src/__tests__/gating-classifications.test.ts \
  src/__tests__/reliability-interactions/execute-requeue-loop-guard.test.ts --reporter=dot
→ Test Files 3 passed | Tests 138 passed (0 failed)
```

Coverage: blocked parks failed with `BLOCKED:` error and does **not**
trip the bulk-completion refusal or requeue to todo; `blockedBy` unioned
into `dependencies`; `task:execution-blocked-parked` emitted with
metadata that excludes the reason prose; steps left untouched; empty
`reason` rejected without parking; `completed` outcome unchanged (still
marks steps done, no blocked audit); and
`recoverStrandedCompletedTodoTasks` never promotes a blocked-parked row.

### Note on `pnpm verify:fast`

`verify:fast` currently fails at the workspace build step due to
**pre-existing** type errors in `packages/engine/src/auth-storage.ts`,
`pi.ts`, and `provider-registration.ts` — the exact FN-8142 pi SDK API
break that FN-8145 will fix. These are present on the base branch and
untouched by this PR. Verified instead that this change introduces
**zero** new type errors (`tsc` diff before/after, engine and core both
clean) and that all scoped tests are green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus <noreply@anthropic.com>
2026-07-16 19:35:37 -07:00
gsxdsm
5a60643c0a FN-8142: migrate auth storage and model runtime to pi SDK
Migrate Fusion's credential and model integrations to pi SDK 0.80.8+.

- Replace legacy AuthStorage initialization with a locked Fusion credential store and ModelRuntime-backed registry.
- Wire asynchronous model initialization and refresh through CLI, desktop, dashboard, executor, and provider paths.
- Update provider, routing, and registry tests for the new SDK contracts.

Files changed:
 packages/cli/src/commands/__tests__/daemon.test.ts |   2 +-
 .../cli/src/commands/__tests__/dashboard.test.ts   |   9 +-
 .../cli/src/commands/__tests__/onboard.test.ts     |   1 +
 packages/cli/src/commands/__tests__/serve.test.ts  |   2 +-
 packages/cli/src/commands/daemon.ts                |  19 +-
 packages/cli/src/commands/dashboard.ts             |  20 +-
 packages/cli/src/commands/onboard.ts               |   6 +-
 packages/cli/src/commands/serve.ts                 |  19 +-
 packages/cli/src/commands/startup-model-sync.ts    |   4 +-
 packages/core/src/__tests__/openai-models.test.ts  |  17 +-
 ...-model-routes-openai-codex-supplemental.test.ts |  17 +-
 ...register-model-routes-zai-real-registry.test.ts |  15 +-
 packages/dashboard/src/routes.ts                   |  12 +-
 .../dashboard/src/routes/register-model-routes.ts  |   2 +-
 packages/desktop/src/local-runtime.ts              |   2 +-
 packages/desktop/src/local-server.ts               |   2 +-
 .../custom-providers-openai-completions.test.ts    |  16 +-
 .../custom-providers-openai-responses.test.ts      |  16 +-
 .../engine/src/__tests__/executor-test-helpers.ts  |   2 +-
 .../src/__tests__/pi-create-fn-agent.test.ts       |   8 +-
 .../engine/src/__tests__/pi-layers-wiring.test.ts  |   2 +-
 packages/engine/src/__tests__/pi.test.ts           |  47 ++---
 .../src/__tests__/provider-registration.test.ts    |  17 +-
 packages/engine/src/auth-storage.ts                | 218 ++++++++++++++++++---
 packages/engine/src/custom-provider-registry.ts    |  14 +-
 packages/engine/src/executor.ts                    |  15 +-
 packages/engine/src/pi.ts                          |  50 +++--
 packages/engine/src/provider-auth.ts               |  58 +++---
 packages/engine/src/provider-registration.ts       |  16 +-
 29 files changed, 421 insertions(+), 207 deletions(-)

Fusion-Task-Id: FN-8142

Fusion-Task-Lineage: 8ae79064-7820-4976-9645-9431b5a3129e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 18:13:37 -07:00
gsxdsm
ca7a5a7106 FN-8144: remove workspace worktrees on archive
Archive workspace task worktrees synchronously and safely across archive entry points.

- Add store-scoped workspace disposal planning, reservations, and quarantine handling.
- Install baseline and executor disposers that remove per-repository worktrees and branches without shell interpolation.
- Cover disposal-plan deduplication and document the archive cleanup behavior.

Files changed:
 .../fn-8144-archive-removes-workspace-worktrees.md |   7 ++
 AGENTS.md                                          |   1 +
 docs/task-management.md                            |   4 +
 .../archive-removes-workspace-worktrees.test.ts    |  59 +++++++++++
 packages/core/src/archive-worktree-disposer.ts     |  52 ++++++++++
 packages/core/src/index.gate.ts                    |   8 ++
 packages/core/src/index.ts                         |   8 ++
 .../core/src/task-store/archive-lifecycle-2.ts     |  29 ++++--
 packages/core/src/task-store/archive-lifecycle.ts  | 114 ++++++++++++++++++++-
 .../src/archive-worktree-disposer-install.ts       |  27 ++++-
 packages/engine/src/executor.ts                    |  25 ++++-
 11 files changed, 319 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-8144

Fusion-Task-Lineage: 1c4b65f3-a1d2-4a5c-a4b6-c263f9e6f61d

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 17:05:29 -07:00
gsxdsm
f57dfc03b6 FN-8105: remove archived task worktrees safely
Archive task worktrees through a store-scoped, race-safe disposal lifecycle.

- Reserve pinned worktree paths during archive cleanup and successor creation.
- Reconcile quarantined removals before reusing a pinned path.
- Gate PostgreSQL archival before destructive worktree disposal and wire CLI cleanup.

Files changed:
 .changeset/fn-8105-archive-removes-worktree.md     |   7 +
 docs/task-management.md                            |   4 +
 .../extension-experiment-finalize.test.ts          |   1 +
 .../src/__tests__/extension-fn-secret-get.test.ts  |   1 +
 .../extension-gitlab-tracking.test.ts              |   1 +
 .../cli/src/__tests__/extension-web-fetch.test.ts  |   1 +
 .../task-command-github-import-tracking.test.ts    |   1 +
 packages/cli/src/commands/__tests__/task.test.ts   |   1 +
 packages/cli/src/commands/task.ts                  |   8 +-
 packages/cli/src/extension.ts                      |   4 +
 .../__tests__/worktree-path-reservation.test.ts    |  58 ++++++++
 packages/core/src/archive-worktree-disposer.ts     |  21 +++
 packages/core/src/index.gate.ts                    |  13 ++
 packages/core/src/index.ts                         |  13 ++
 .../core/src/task-store/archive-lifecycle-2.ts     |   8 ++
 packages/core/src/task-store/archive-lifecycle.ts  |  37 +++++
 packages/core/src/worktree-path-reservation.ts     | 149 +++++++++++++++++++++
 .../src/archive-worktree-disposer-install.ts       |  18 +++
 packages/engine/src/executor.ts                    |  16 +++
 packages/engine/src/index.ts                       |   2 +
 packages/engine/src/runtimes/in-process-runtime.ts |   1 +
 packages/engine/src/worktree-acquisition.ts        |  27 +++-
 22 files changed, 388 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8105
Fusion-Task-Lineage: cabb8f52-093f-4986-bfda-2c7601a72579
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 15:27:03 -07:00
gsxdsm
d870878a23 FN-7998: add executor alternate model escalation
Add opt-in executor escalation after same-model tool-failure retries are exhausted.

- Persist escalation settings and one-shot task state across SQLite and PostgreSQL stores.
- Retry once on a configured alternate model or scheduler node and audit escalation outcomes.
- Expose escalation controls, documentation, translations, migration, and regression coverage.

Files changed:
 .changeset/fn-7998-executor-escalation.md          |   7 ++
 AGENTS.md                                          |   1 +
 docs/settings-reference.md                         |  13 ++-
 .../core/src/__tests__/settings-defaults.test.ts   |  23 ++++-
 packages/core/src/in-review-stall.ts               |  29 ++++++
 packages/core/src/index.gate.ts                    |   3 +-
 packages/core/src/index.ts                         |   3 +-
 packages/core/src/manual-retry-reset.ts            |   1 +
 .../0014_executor_escalation_attempt.sql           |   2 +
 packages/core/src/postgres/schema-applier.ts       |  17 ++++
 packages/core/src/postgres/schema/project.ts       |   1 +
 packages/core/src/settings-schema.ts               |   4 +
 packages/core/src/store.ts                         |   2 +-
 packages/core/src/task-store/persistence.ts        |   2 +
 packages/core/src/task-store/remaining-ops-2.ts    |   2 +-
 packages/core/src/task-store/remaining-ops-3.ts    |   2 +-
 packages/core/src/task-store/remaining-ops-6.ts    |   2 +-
 packages/core/src/task-store/serialization.ts      |   1 +
 packages/core/src/task-store/task-update.ts        |   2 +
 packages/core/src/types.ts                         |  13 +++
 .../dashboard/app/components/SettingsModal.tsx     |  12 +++
 .../app/components/settings/section-keys.ts        |   4 +
 .../settings/sections/SchedulingSection.search.ts  |  36 +++++++
 .../settings/sections/SchedulingSection.tsx        |   6 ++
 .../settings-default-descriptions.test.tsx         |   4 +
 .../__tests__/executor-tool-failure-retry.test.ts  |  91 +++++++++++++++++-
 packages/engine/src/executor.ts                    | 104 +++++++++++++++++++--
 packages/i18n/locales/en/app.json                  |   8 ++
 28 files changed, 376 insertions(+), 19 deletions(-)

Fusion-Task-Id: FN-7998

Fusion-Task-Lineage: bbce767d-c61a-4667-be62-abc0cc54d8be

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 14:31:59 -07:00
gsxdsm
60b6e3e048 FN-7996: add configurable executor tool-failure retries
Add bounded, durable same-model retry handling for qualifying consecutive executor tool errors.
- Persist retry claims, cursors, and audit markers with PostgreSQL migrations.
- Expose project retry count, backoff, and failure threshold settings in the dashboard.
- Cover retry, exhaustion, reset, and stale-run safety behavior with tests.

Files changed:
 .changeset/fn-7996-executor-tool-failure-retry.md  |   7 +
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |   1 +
 docs/settings-reference.md                         |  10 ++
 .../executor-tool-failure-retry-claim.test.ts      |  17 +++
 .../core/src/__tests__/manual-retry-reset.test.ts  |   3 +
 .../core/src/__tests__/settings-defaults.test.ts   |  15 +-
 packages/core/src/in-review-stall.ts               |  20 +++
 packages/core/src/index.gate.ts                    |   6 +
 packages/core/src/index.ts                         |   6 +
 packages/core/src/manual-retry-reset.ts            |   3 +
 .../0013_executor_tool_failure_retry.sql           |   4 +
 packages/core/src/postgres/schema-applier.ts       |  17 +++
 packages/core/src/postgres/schema/project.ts       |   3 +
 packages/core/src/settings-schema.ts               |   3 +
 packages/core/src/store.ts                         |  10 +-
 packages/core/src/task-store/persistence.ts        |   7 +
 packages/core/src/task-store/remaining-ops-2.ts    |   2 +-
 packages/core/src/task-store/remaining-ops-3.ts    |   2 +-
 packages/core/src/task-store/remaining-ops-6.ts    |  65 ++++++++-
 packages/core/src/task-store/serialization.ts      |   3 +
 packages/core/src/task-store/task-update.ts        |   6 +
 packages/core/src/types.ts                         |  16 +++
 .../dashboard/app/components/SettingsModal.tsx     |  15 ++
 .../app/components/settings/section-keys.ts        |   3 +
 .../settings/sections/SchedulingSection.search.ts  |  27 ++++
 .../settings/sections/SchedulingSection.tsx        |   4 +
 .../settings-default-descriptions.test.tsx         |   3 +
 .../__tests__/executor-tool-failure-retry.test.ts  | 160 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |  87 ++++++++++-
 packages/i18n/locales/en/app.json                  |   6 +
 31 files changed, 523 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7996
Fusion-Task-Lineage: d1682ef8-534c-410e-b74c-1f2cf176eac2
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 13:41:14 -07:00
gsxdsm
2142841f0c FN-8111: restore reliability test coverage
Restore PostgreSQL-compatible reliability coverage and prevent completed tasks from wedging on stale continuation recovery.

- Update reliability fixtures and audit assertions for PostgreSQL-backed stores
- Prioritize completed-task handling before stale assistant-continuation retries
- Unquarantine the restored meta-archive and continuation reliability suites

Files changed:
 .../explicit-duplicate-marker-sweep.test.ts        |  4 ++++
 .../meta-archive-guard-composition.test.ts         | 26 +++++++++++++++++-----
 .../post-done-continuation-no-wedge.test.ts        |  3 ++-
 packages/engine/src/executor.ts                    |  7 ++++++
 packages/engine/vitest.config.ts                   |  4 ++--
 scripts/lib/test-quarantine.json                   | 10 ---------
 6 files changed, 36 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-8111

Fusion-Task-Lineage: 8b30b5cb-c160-44e1-8e8c-dd58f4877edc

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 12:09:55 -07:00
gsxdsm
aa07a78f18 fix: recover graph-node missing-worktree failures instead of terminal-parking (FN-7996) (#2231)
## Why

FN-7996 sat in a dispatch→park loop **all day** (06:06→16:35): its
`worktree` metadata pointed at recycled pool worktrees (`coral-badger`,
`grand-ridge` — the latter actually belonged to FN-8069), Plan Review
refused to start in the missing directory, and the task terminal-parked
`failed` every cycle while the planner overseer blindly retried.

Root-cause chain:

1. **`graphFailureValue()` couldn't read optional-group results.**
`runOptionalGroup` publishes context under the group id
(`node:plan-review:value`) and the unqualified template id, but the
failed node is recorded as the materialized
`plan-review::plan-review-step` — the lookup only understood `#` foreach
ids. FN-7977's provider-failure hold *did* classify this failure, but
its hold value was invisible to routing.
2. **No graph-failure router handled the `assertValidWorktreeSession`
refusal**, so it fell to the terminal sink, which parked the task and
*overwrote* `task.error` with a generic message — erasing the signature
the missing-worktree self-healing sweep (in-review-only anyway)
classifies on.
3. **Plan Review didn't need the worktree at all** — its spec is
store-injected (FN-7561) — yet it launched its reviewer in whatever
stale `task.worktree` said.

## What

- `handleGraphFailure` routes unusable-worktree node failures (any node,
any error key, `::`/`#` materialized ids) into the existing bounded
worktree-session recovery: clear stale worktree/branch/session metadata,
requeue to todo, budgeted by `worktreeSessionRetryCount`. An exhausted
budget still falls through to the visible terminal park for human
inspection.
- `graphFailureValue` resolves `group::template` ids (group value first
— it carries post-classification routing intent — then the unqualified
template value). Foreach `#` behavior unchanged.
- Plan Review falls back to the repo root when its recorded worktree is
missing on disk; other read-only gates intentionally keep failing fast
into the new recovery (silently retargeting them to root would review
the wrong tree).
- `recoverMissingWorktreeSessionStartFailure` returns its outcome so the
graph router can distinguish requeue from escalate-exhausted; existing
truthy callers unchanged.

## Symptom Verification

- **Original symptom:** graph-node session-start refusal → `Workflow
graph terminated with failure at node 'plan-review::plan-review-step'`,
task parked failed with stale metadata intact, no recovery.
- **Reproduction:** `graph-node-missing-worktree-recovery.test.ts`
drives `handleGraphFailure` with the exact FN-7996 result shape
(optional-group materialized id + `Refusing to start coding agent in
missing worktree` node error).
- **Assertion it is gone:** the task is requeued to `todo` with
`worktree`/`branch`/`sessionFile` cleared and retry budget incremented —
and is *not* marked `failed`; budget exhaustion still parks visibly.

## Surface Enumeration

- Optional-group template nodes (Plan Review — the repro), write-capable
review gates, and any custom graph node: covered by the
`handleGraphFailure` router (scans exact/materialized/unqualified
`:error` keys).
- Execute-seam session start: already covered by the pre-existing
recovery (unchanged, still passes).
- In-review / merge-active columns: already covered by self-healing
sweeps (unchanged).
- Paused / user-paused / deleted / done tasks: explicitly left to their
owning machinery (guard tests).
- Budget exhaustion: falls through to the visible terminal park (test).

## Testing

- `pnpm --filter @fusion/engine exec vitest run
src/__tests__/reliability-interactions/graph-node-missing-worktree-recovery.test.ts`
— 13 passed
- Adjacent suites (`worktree-incomplete-session-start`,
`executor-graph-requeue-gate`, `workflow-graph-optional-group`,
`executor-paused-abort-todo-benign`) — 78 passed
- `tsc --noEmit` on `@fusion/engine` — clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved recovery when workflow tasks encounter missing or recycled
worktrees.
* Automatically retries affected tasks with stale worktree details
cleared, up to the configured retry limit.
  * Escalates tasks after recovery attempts are exhausted.
* Improved failure routing for optional workflow groups and template
instances.
* Plan Review now falls back to the repository root when its recorded
worktree is unavailable.
* **Tests**
* Added regression coverage for recovery, routing, retry limits, and
repository-root fallback behavior.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 10:28:11 -07:00
gsxdsm
1a337df5e9 FN-8098: add executor model fallback
Add workflow-specific executor fallback configuration and bounded recovery.

- Add executor fallback provider, model, and thinking settings across core schemas and settings UI.
- Route executor, heartbeat, child, and workflow-step sessions through the executor fallback resolver.
- Retry the primary model after fallback failure before reporting terminal exhaustion.
Files changed:

 .changeset/fn-8098-model-fallback.md               |  7 +++
 docs/settings-reference.md                         |  7 ++-
 .../core/src/__tests__/model-resolution.test.ts    | 13 ++++
 .../core/src/__tests__/settings-parity.test.ts     |  5 ++
 packages/core/src/builtin-workflow-settings.ts     | 24 +++++++
 packages/core/src/index.gate.ts                    |  1 +
 packages/core/src/index.ts                         |  1 +
 packages/core/src/model-resolution.ts              | 21 +++++++
 packages/core/src/settings-schema.ts               |  3 +
 packages/core/src/types.ts                         | 11 ++++
 .../app/components/WorkflowSettingsPanel.tsx       |  8 +++
 .../settings/sections/ProjectModelsSection.tsx     | 10 ++-
 packages/engine/src/__tests__/pi.test.ts           | 14 ++++-
 packages/engine/src/agent-session-helpers.ts       |  7 ++-
 packages/engine/src/executor.ts                    | 48 +++++++-------
 packages/engine/src/pi.ts                          | 73 ++++++++--------------
 packages/engine/src/step-session-executor.ts       |  8 ++-
 17 files changed, 180 insertions(+), 81 deletions(-)

Fusion-Task-Id: FN-8098

Fusion-Task-Lineage: 61b3103b-357b-431a-8d58-411e7806b87b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 08:33:57 -07:00
gsxdsm
3f133e0b13 FN-8058: add task agent log reader
Expose paginated, filterable persisted agent logs to task-scoped and chat agent sessions.

- Add the read-only fn_task_logs_read tool across engine, dashboard chat/planning, heartbeat, step, and CLI extension surfaces.
- Filter agent-log entries before pagination, report matching totals, and render complete persisted rows for diagnosis.
- Document the tool, add release metadata, regression coverage, and complete affected engine mocks.

Files changed:
 .changeset/fn-8058-task-logs-read.md               |  7 ++
 docs/agents.md                                     |  4 +-
 packages/cli/skill/fusion/SKILL.md                 |  2 +-
 .../cli/skill/fusion/references/extension-tools.md | 11 +++
 .../skill/fusion/references/fusion-capabilities.md |  1 +
 .../extension-experiment-finalize.test.ts          |  2 +
 .../src/__tests__/extension-fn-secret-get.test.ts  |  2 +
 .../__tests__/extension-gitlab-tracking.test.ts    |  2 +
 .../src/__tests__/extension-integration.test.ts    |  1 +
 .../cli/src/__tests__/extension-web-fetch.test.ts  |  2 +
 packages/cli/src/__tests__/extension.test.ts       |  1 +
 packages/cli/src/extension.ts                      | 34 ++++++++
 .../src/__tests__/agent-logs-backend-mode.test.ts  | 28 +++++-
 packages/core/src/store.ts                         | 11 ++-
 packages/core/src/task-store/remaining-ops-7.ts    | 16 +++-
 packages/core/src/types.ts                         |  1 +
 packages/dashboard/src/__tests__/chat.test.ts      |  1 +
 .../planning-answered-question-reemit.test.ts      |  1 +
 .../planning-generation-cancellation.test.ts       |  1 +
 packages/dashboard/src/chat.ts                     |  5 ++
 packages/dashboard/src/planning.ts                 |  3 +
 .../__tests__/agent-task-logs-read-tools.test.ts   | 72 ++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             |  4 +-
 packages/engine/src/agent-tools.ts                 | 99 +++++++++++++++++++++-
 packages/engine/src/executor.ts                    |  6 ++
 packages/engine/src/gating-classifications.ts      |  2 +
 packages/engine/src/index.ts                       |  6 ++
 packages/engine/src/step-session-executor.ts       |  6 +-
 28 files changed, 316 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-8058
Fusion-Task-Lineage: 74f198b2-f538-4b39-973f-431f22e68f29
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 04:03:43 -07:00
gsxdsm
c2475b012d FN-8064: add proactive task chat status updates
Task-detail chat now narrates engine progress and review outcomes in real time.

- Emit bounded, redacted status rows for step lifecycle and review paths.
- Present status entries with a distinct task-chat treatment.
- Cover status narration and diagnostic sanitization with engine tests.

Files changed:
 .changeset/fn-8064-proactive-chat.md               |   7 +
 docs/architecture.md                               |   1 +
 packages/dashboard/app/components/TaskChatTab.css  |  16 ++
 packages/dashboard/app/components/TaskChatTab.tsx  |   9 +-
 .../engine/src/__tests__/executor-prompt.test.ts   |  28 +++-
 .../engine/src/__tests__/proactive-status.test.ts  |  54 +++++++
 packages/engine/src/executor.ts                    | 176 ++++++++++++++++-----
 packages/engine/src/proactive-status.ts            | 117 ++++++++++++++
 8 files changed, 365 insertions(+), 43 deletions(-)

Fusion-Task-Id: FN-8064

Fusion-Task-Lineage: c6d0a9b5-0946-4bf4-8338-e982e1cbfd53

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:47:59 -07:00
gsxdsm
274318aebf FN-8056: enforce task token budgets
Enforce configured task token budgets whenever session usage is persisted.

- Apply soft alerts and hard pauses atomically from all executor persistence paths.
- Exclude cache-read tokens from budget usage and dispatch budget notifications once.
- Document budget semantics and add regression coverage.

Files changed: .changeset/fn-8056-token-budget-enforcement.md     |   7 ++
 docs/settings-reference.md                         |   2 +
 packages/core/src/types.ts                         |   4 +-
 .../src/__tests__/session-token-usage.test.ts      | 101 ++++++++++++++++++++-
 .../src/__tests__/token-budget-enforcer.test.ts    |  81 ++++++++++-------
 packages/engine/src/executor.ts                    |  22 ++++-
 packages/engine/src/session-token-usage.ts         |   8 +-
 packages/engine/src/token-budget-enforcer.ts       |  98 +++++++++++++++++---
 8 files changed, 262 insertions(+), 61 deletions(-)

Fusion-Task-Id: FN-8056

Fusion-Task-Lineage: 5f5ed522-f950-42ce-b4fd-e0b1d45b5815

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 01:52:10 -07:00
gsxdsm
753b1bb710 fix(engine): honor graph cancellation at the merge node
The merge node could not observe a graph abort. WorkflowPrimitiveContext
carried no signal, so requestMerge raced the merge only against its own
30-minute GRAPH_MERGE_TIMEOUT_MS using a controller it owned. A hard-cancel
(user cancel, engine restart, pause/resume) aborted the graph controller and
the walk kept sitting inside the merge node for the full timeout. When the
timeout finally fired it aborted the still-running AI merge -- surfacing as
"Manual-merge failed: Request was aborted" -- and the walk reported
value=merge-timeout for a cancellation it had missed half an hour earlier.
An abort landing between merger-ai's `worktree: null` write and
mergeConfirmed then stranded the card as no-worktree-no-merge-confirmed.

Thread the graph AbortSignal from WorkflowNodeExecutionContext (where it
already existed) through primitiveNodeContext/primitiveContextForNode into
the primitives, and honor it on both merge surfaces:

- requestMerge fails fast when the walk is already cancelled, before
  ensureWorkflowMergeBoundaryTask mutates the row or the requester enqueues
  a merge, and links the graph signal into its timeout controller via
  AbortSignal.any -- raced separately so the walk returns on the abort
  rather than waiting on a requester that may never settle.
- The legacy merge seam had the identical unguarded race and gets the same
  treatment.

The timeout stays: it bounds a wedged merge queue, which is a different
failure from cancellation. Both signals must stay live -- dropping either
silently restores the stall with no type error.

Cancellation returns a distinct `merge-cancelled` rather than reusing
merge-timeout. Returning `data.status: "failed"` would let classifyMergeFailure
read the unknown reason as merge-failed and route the cancellation into
bounded auto-merge retry, re-requesting the merge the operator just cancelled.

Regression test covers both merge surfaces, both cancel timings (pre-flight
and mid-flight), the no-signal back-compat path, the signal plumbing itself,
and the classification boundary. Verified by removing the fix: 7 of 9 cases
fail, with the mid-flight cases hanging until timeout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 19:43:08 -07:00
gsxdsm
214af98591 FN-7977: hold Plan Review provider failures without replan regression
Prevent provider, model, transport, and abort failures from bouncing tasks back to planning after they enter execution.

- Classify non-plan-defect Plan Review failures and skip needs-replan handoff
- Terminate graph traversal with plan-review-provider-failure-hold and retry in place
- Guard triage recovery so advanced column/worktree/step state is never overwritten
- Document planning-recovery no-regression invariant and add regression tests
- Add patch changeset for the operator-facing fix

Files changed:
 .changeset/fn-7977-planning-failure-no-regression.md |   7 ++
 docs/architecture.md                               |   1 +
 docs/workflow-steps.md                             |   2 +-
 packages/engine/src/__tests__/replan-target.test.ts     |  17 +++-
 packages/engine/src/__tests__/transient-error-detector.test.ts |  32 +++++-
 packages/engine/src/__tests__/triage.test.ts       | 110 +++++++++++++++++++++
 packages/engine/src/__tests__/workflow-graph-optional-group.test.ts          |  46 ++++++++-
 packages/engine/src/__tests__/workflow-graph-optional-step-fix.test.ts       |  36 +++++++
 packages/engine/src/executor.ts                    |  62 +++++++++++-
 packages/engine/src/replan-target.ts               |  22 +++++
 packages/engine/src/transient-error-detector.ts    |  37 +++++++
 packages/engine/src/triage.ts                      |  73 +++++++++++---
 packages/engine/src/workflow-graph-executor.ts     |  45 ++++++++-
 13 files changed, 466 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-7977

Fusion-Task-Lineage: 6d62d3ca-c6f3-4d02-a377-d7fd59f0c0f9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 16:29:10 -07:00
gsxdsm
f1b528f4c5 fix(FN-7965): honor terminal fn_task_done park instead of resurrecting the session
The in-session `fn_task_done` handler parks a task terminally (status=failed,
worktree/branch/sessionFile cleared) once its refusal/invariant retry budget is
exhausted. That write happens inside the live agent session, so the executor's
no-fn_task_done retry loop never observed it and spawned a fresh session anyway.
The retry completed, marked the task done, and dragged a worktree-less row into
the pre-merge graph, where the first write-capable node failed on
`no-worktree-for-write-node` — surfacing as a misleading "Workflow graph
terminated with failure at node 'code-review-remediation'" instead of the real
refusal. Observed on FN-7965 and again live on FN-7981.

Re-read state at the top of the retry loop and honor the park. The status probe
covers all three park sites (invariant-check, explicit refusal, implicit
refusal) rather than the single reported repro.

Deliberately not routed through the FN-4806 reclaim branch: its silent todo
requeue would clear the park and, with the budget already spent, re-park on the
next pickup in a todo->execute->park loop.

The pre-existing reclaim probes could not catch this — they test
`worktree === null`, but the store maps a cleared column to `undefined`
(`task-store/serialization.ts`: `row.worktree || undefined`), so the existing
test only passed because its mock returned a value production never emits.
Tightening that probe regressed 7 fixtures and is left as separate work.

Verified: new tests fail with the guard disabled; engine reliability surfaces
show zero regressions vs baseline (17 pre-existing failures unchanged, 495->499
passing); engine-core gate suite 294/294.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 16:21:03 -07:00
gsxdsm
dc7bb40948 FN-7990: share worktree classifier so Code Review acquires a worktree
Unify write-capability classification so graph preparation acquires a worktree for inline-fix Code Review before runtime runs, eliminating the immediate no-worktree-for-write-node failure.

- Add shared workflowNodeRequiresWorktree helper for preparation and runtime
- Plumb optional-group context and reviewerInlineFixes into graph preparation
- Acquire/reuse/reacquire worktrees for write-capable inline review nodes
- Keep Plan Review and disabled inline fixes read-only
- Add regression tests and a patch changeset

Files changed:
 .changeset/fn-7990-code-review-worktree.md         |  7 ++
 .../__tests__/ce-workflow-step-executor.test.ts    | 97 ++++++++++++++++++++++
 .../workflow-node-execution-needs.test.ts          | 47 +++++++++++
 packages/engine/src/executor.ts                    | 32 +++----
 packages/engine/src/workflow-graph-executor.ts     | 52 ++++++++----
 .../engine/src/workflow-node-execution-needs.ts    | 46 ++++++++++
 6 files changed, 243 insertions(+), 38 deletions(-)

Fusion-Task-Id: FN-7990

Fusion-Task-Lineage: f5d19181-0b98-4827-8adb-069f7dc05c03

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 15:34:43 -07:00