Commit Graph

415 Commits

Author SHA1 Message Date
gsxdsm
85f8b1f909 feat: shared Postgres multi-node — retire mesh data-plane replication (#2130)
## Summary

- Treat **shared PostgreSQL** (`DATABASE_URL`) as the multi-node durable
data plane; mesh HTTP is membership + optional auth, not task/settings
replication.
- **Peer exchange**: under Postgres backend mode, write queue is
**topology/auth-only**; non-topology pending rows fail rather than
replaying multi-leader task/settings payloads.
- **Mesh routes**: task-ID reserve/commit/abort always hit local shared
allocator rows (ignore remote `coordinatorNodeId`); mesh sync ignores
settings and only exchanges `authMaterial`.
- **Docs**: rewrite multi-project runbook, shared cluster protocol, and
architecture mesh sections for shared-Postgres + claims/leases.

## Context

Follows the SQLite→Postgres cutover. Multiple Fusion nodes can share one
external Postgres while keeping **per-node execution** (worktrees,
processes, claims via `central.task_claims`). Explicit non-goals remain:
scheduler failover and live process migration.

Plan:
`docs/plans/2026-07-15-001-refactor-mesh-shared-postgres-multinode-plan.md`

## Test plan

- [x] `pnpm --filter @fusion/engine exec vitest run
src/__tests__/peer-exchange-service.test.ts`
- [x] `pnpm --filter @fusion/dashboard exec vitest run
src/__tests__/mesh-routes.test.ts`
- [x] `pnpm --filter @fusion/core exec vitest run
src/__tests__/shared-mesh-state.test.ts`
- [ ] CI gate (lint/typecheck/build/gate)
- [ ] Manual (optional): two processes, same `DATABASE_URL`, create task
on A visible on B; settings change without mesh settings sync; claim
exclusivity

## Operator note

Multi-node shared board requires **external** `DATABASE_URL` on every
node. Default embedded Postgres is still single-host.

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

* **New Features**
* Improved multi-node deployments using shared PostgreSQL as the durable
source of execution state.
* Task ID reservation/commit/abort now run locally (no remote
coordinator forwarding).
* Mesh syncing now prioritizes topology visibility and authentication
material; settings replication is disabled in shared-Postgres mode.
* **Bug Fixes**
* Prevented task/settings replication over mesh HTTP in shared-Postgres
deployments.
* Refined lease ownership, recovery, and reconciliation to converge via
shared-database primitives.
* **Documentation**
* Updated architecture and shared-mesh protocol guidance, including
multi-node setup and lease/task-ID allocation behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-15 13:32:33 -07:00
gsxdsm
6e3a338cac FN-7968: defer slow cleanup off task deletion critical path
Make soft-delete return after the DB mutation while branch and agent cleanup run in the background.

- Schedule cleanupBranchForTask after the soft-delete transaction instead of awaiting it under withTaskLock
- Persist cleaned-branch log entries on the deleted row asynchronously; warn on deferred failures
- Respond from DELETE /tasks/:id after deleteTask and schedule execution-agent binding release off the HTTP path
- Add core and dashboard regression tests for non-blocking delete cleanup
- Document the fast-path contract in architecture.md and add a patch changeset

Files changed:
 .changeset/fn-7968-task-delete-latency.md          |   7 +
 docs/architecture.md                               |   1 +
 .../task-delete-nonblocking-cleanup.test.ts        | 160 +++++++++++++++++++++
 packages/core/src/task-store/archive-lifecycle.ts  |  57 +++++++-
 .../routes-task-delete-nonblocking.test.ts         | 139 ++++++++++++++++++
 .../src/routes/register-task-workflow-routes.ts    |  19 ++-
 6 files changed, 370 insertions(+), 13 deletions(-)

Fusion-Task-Id: FN-7968

Fusion-Task-Lineage: f218a91e-aee3-46c9-a80f-182751b3ccc4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 12:44:30 -07:00
gsxdsm
a242f1b449 fix(FN-7952): migrate bundled plugins to PostgreSQL (#2111)
## Summary

Bundled plugins now persist shared runtime state in project-scoped
PostgreSQL tables instead of maintaining independent SQLite authority.
Reports, CLI Printing Press, Compound Engineering, Roadmap, Even
Realities, and WhatsApp all follow the same ownership and startup
contract as Fusion core.

## Design decisions

- Plugin schema hooks run through the host’s PostgreSQL owner and
enforce project isolation.
- The SDK exposes the host contract needed by bundled plugins without
importing engine internals.
- Legacy Roadmap ownership fixtures use the supported empty-owner
sentinel, preserving current composite primary/foreign keys while
exercising backfill behavior.
- The lockfile travels with the Even Realities PostgreSQL dependency so
packaged installs remain reproducible.

## Validation

- All six affected plugin builds pass.
- Affected plugin suites pass: 773 tests across Printing Press, Compound
Engineering, Even Realities, Reports, Roadmap, and WhatsApp.
- `pnpm test:gate` passes all 478 gate tests.
- This PR changes 40 files.

## Stack

- Depends on #2110 → #2109 → #2108.
- The documentation/release PR completes the stack.

Related: #2105


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

## Summary by CodeRabbit

* **Breaking Changes**
* PostgreSQL is now required for runtime storage; SQLite files are used
only as one-time migration inputs.
  * The legacy `FUSION_NO_EMBEDDED_PG` fallback has been removed.

* **New Features**
* Added project-isolated PostgreSQL storage for plugins, reports, tasks,
notifications, and other plugin data.
  * Added agent tools for reports and CLI service drafts.
  * Added PostgreSQL schema initialization support for plugin authors.

* **Bug Fixes**
  * Improved migration and recovery of legacy plugin state.
* Prevented cross-project data access and strengthened transactional
schema updates.

* **Documentation**
* Updated storage, migration, deployment, plugin authoring, CLI, and
dashboard guidance for PostgreSQL.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-15 00:27:59 -07:00
gsxdsm
4f037679ad feat: planner overseer session advisor (OMP advisor parity) (#2082)
## Summary

Adds a **session advisor** to the planner overseer so Fusion can review
live executor transcripts the way [oh-my-pi’s
advisor](https://github.com/can1357/oh-my-pi/tree/main/packages/coding-agent/src/advisor)
does — without replacing the existing lifecycle supervisor (stage watch,
retry, merge confirmation, human-control withhold).

### What ships

- **Emission guard** (`OverseerEmissionGuard`) — content-free phrase
filter, session dedupe with severity-rank escalation, one accept per
advisor update
- **Session delta runtime** — queues agent-log deltas, drains through an
advisor agent, drops backlog after 3 failures
- **Session advisor service** — model gate, level matrix (`observe` /
`steer` / `autonomous`), human-control re-check at inject,
`[session-advisor]` steering comments
- **OVERSEER.md / WATCHDOG.md** discovery for project review priorities
- **AgentLogger `onEntriesFlushed`** + poll-backed agent-log cursor for
durable deltas
- Workflow settings: `plannerOverseerAdvisorProvider` +
`plannerOverseerAdvisorModelId` (both required; empty = soft-disabled
for cost safety)
- Docs + changeset

### What does not ship (deferred)

- Multi-advisor YAML roster, mutating advisor tools, reviewer/merger
shadowing, true tool-abort interrupt

### Plan

`docs/plans/2026-07-13-001-feat-overseer-advisor-parity-plan.md`

## Enablement

1. Set workflow **Session advisor model provider** + **Session advisor
model id**
2. Oversight level `observe` (log only), `steer`, or `autonomous`
(inject)
3. Optional: add `OVERSEER.md` or `WATCHDOG.md` in the project

## Test plan

- [x] `pnpm --filter @fusion/core exec vitest run
src/__tests__/overseer-emission-guard.test.ts`
- [x] `pnpm --filter @fusion/engine exec vitest run` overseer-* unit
tests (21 tests)
- [x] Related planner-overseer / intervention regression tests
- [x] `@fusion/engine` + `@fusion/core` typecheck
- [ ] Manual: configure advisor model, run an executor task, confirm
`[session-advisor]` inject + timeline metadata when concern is raised

## Residual Review Findings

None from autofix pass (log-cursor ordering fix already committed).


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

* **New Features**
* Added an off-by-default “session advisor” that can review live
execution activity and provide severity-based guidance.
* Added project and per-task controls to enable it, including a default
enable switch and Quick Add / Task Detail toggles.
* Enhanced advisor prompting by discovering and incorporating
`OVERSEER.md`/`WATCHDOG.md` review files.
* **Documentation**
* Added architecture and settings documentation for the new
session-advisor parity behavior.
* **Bug Fixes**
* Improved fail-soft handling so advisor behavior won’t disrupt
execution.
  * Fixed concurrent PostgreSQL migration startup failures.
* **Tests**
* Added coverage for advice parsing, emission guarding, runtime
behavior, and watchdog discovery.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 20:27:35 -07:00
gsxdsm
6e0fde860c FN-7949: fix deleted planning-mode session resurrecting after in-flight generation completes
Adds a bounded-TTL delete tombstone to AiSessionStore so a straggling post-delete generation write can never resurrect a session the user explicitly deleted.

- AiSessionStore now records a 10-minute delete tombstone (id -> deletion timestamp) in delete(), deleteByIdAndType(), and bulk cleanup paths (cleanupOld/cleanupStaleSessions/emitDeletedSessions).
- upsert() checks the tombstone first and drops (no-ops) any write for a tombstoned id without touching SQLite or emitting ai_session:updated, fixing the root cause once in the shared store rather than per-producer (planning.ts, subtask-breakdown.ts, mission-interview.ts, milestone-slice-interview.ts).
- Tombstone entries are pruned lazily on check and piggyback on the existing cleanupStaleSessions() cadence so the in-memory map cannot grow unbounded.
- Adds a changeset (patch) documenting the user-facing fix.
- Updates docs/architecture.md and docs/storage.md with the new "AI session delete tombstones" behavior.
- Adds regression tests covering the tombstone guard in ai-session-store.test.ts and routes-planning.test.ts.

Files changed:
 .changeset/fn-7949-ai-session-delete-tombstone.md  |   7 +
 docs/architecture.md                               |   2 +-
 docs/storage.md                                    |  12 +-
 packages/dashboard/src/__tests__/ai-session-store.test.ts | 145 +++++++++++++++
 packages/dashboard/src/__tests__/routes-planning.test.ts  | 200 ++++++++++++++++++++-
 packages/dashboard/src/ai-session-store.ts         |  83 +++++++++
 6 files changed, 446 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7949

Fusion-Task-Lineage: 8e509dae-0cc5-46cd-9c4b-9048cfda56d3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-13 13:10:53 -07:00
gsxdsm
e35620c9aa FN-7939: supervise heartbeat timer-audit interval and bound non-advancing zombie re-arms
Fixes agents silently going stale for hours even though the heartbeat repair audit process was running.

- HeartbeatTriggerScheduler now runs an independent watchdog (armTimerAuditWatchdog/checkTimerAuditLiveness) that tracks the audit loop's last-run timestamp and re-arms + immediately re-runs the 60s audit interval if it goes stale beyond a bounded multiple of the cadence, so a silently dropped audit driver self-heals instead of leaving active agents unrepaired for hours.
- Tracks consecutive non-advancing zombie-timer re-arms per agent (nonAdvancingRearmState) and escalates once the count crosses a threshold, recording consecutiveNonAdvancingRearms/nonAdvancingEscalated in agent.metadata.heartbeatTimerRepair and logging reason=heartbeat-rearm-nonadvancing-escalated instead of silently churning the same zombie-timer-rearmed repair forever.
- Clears non-advancing rearm state on unregister, non-eligible agents, paused settings, and stale-run-reap skip paths so tracking never leaks stale per-agent counters.
- Watchdog and its interval handle are armed in start() and cleared in stop() alongside the existing audit interval.
- Adds a changeset (patch) describing the fix, and updates docs/agents.md and docs/architecture.md to document the FN-7939 audit watchdog and non-advancing escalation behavior.
- Adds heartbeat-scheduler.test.ts coverage for watchdog re-arm/liveness and non-advancing escalation.

Files changed:
 .changeset/fn-7939-heartbeat-audit-supervision.md  |   7 +
 docs/agents.md                                     |   8 +-
 docs/architecture.md                               |   1 +
 .../src/__tests__/heartbeat-scheduler.test.ts      | 209 +++++++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             | 128 ++++++++++++-
 5 files changed, 341 insertions(+), 12 deletions(-)

Fusion-Task-Id: FN-7939
Fusion-Task-Lineage: 9fa90240-4333-4588-b595-aef3811b1524
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-13 07:51:07 -07:00
gsxdsm
316d4fa034 FN-7941: anchor execute-requeue loop guard to monotonic terminal-step progress
Hardens the FN-7863 execute-node self-requeue loop guard so residual execute_loop_stall cases (#2043/#2045/#2046/#2047) can no longer reset the loop counter forever via non-terminal signature drift.

- Change buildExecuteRequeueLoopSignature to track terminal step count (done/skipped) plus total step count instead of raw currentStep + every step status, so pending/in-progress oscillation no longer produces a "new" signature each cycle.
- Add buildExecuteRequeueLoopHighWaterSignature, which derives current terminal-step progress via the shared signature parser (parseExecuteRequeueLoopProgressSignature) and only resets the streak on monotonic forward progress, keeping a high-water mark across cycles so decreases/oscillation below the high-water still count toward exhaustion.
- Update executor.ts's execute self-requeue dispatch path to use the new high-water helper when deciding whether to reset (1) or increment executeRequeueLoopCount, replacing the previous raw signature-equality check.
- Extend execute-requeue-loop-guard.test.ts with regression coverage: a drifting-signature case that oscillates step order/status with no terminal progress (still terminalizes at MAX_EXECUTE_REQUEUE_LOOP_CYCLES), a done/in-progress oscillation case bounded after the high-water stops increasing, and an updated "real progress never terminalizes" case driven by genuine monotonic done-step advancement.
- Update docs/architecture.md's FN-7863/FN-7926 self-healing notes to describe the new terminal-step high-water signature and cross-reference FN-7941.

Files changed:
 docs/architecture.md                               |  4 +-
 .../execute-requeue-loop-guard.test.ts             | 83 +++++++++++++++++++++-
 packages/engine/src/executor.ts                    | 54 ++++++++++++--
 3 files changed, 130 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-7941

Fusion-Task-Lineage: cbf1e536-d29b-40da-bdd8-8c34d8d6b1ca

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-13 07:46:54 -07:00
gsxdsm
6dcecb0c34 FN-7926: park completed-but-blocked tasks instead of looping execute-requeue
Stops the execute → pause-abort → re-queue-to-todo infinite loop for tasks whose implementation work is done but a dependency/blockedBy blocker is still live, by diverting them into a dedicated parked state instead of feeding the FN-7863 no-progress backstop or looping forever.

- Add TaskExecutor.parkCompletedBlockedTask(): when work is complete but getTaskCompletionBlocker() still reports a blocker, park the task in todo with pausedReason:"completed-work-blocked", status:"queued", preserved worktree/branch/steps, and a cleared execute-requeue signature.
- Replace shouldFinalizeCompletedTask's boolean with getCompletedTaskFinalizationDecision() returning "finalize" | "blocked" | "incomplete" so both the paused-after-completion and finalization call sites can react to the new "blocked" outcome without re-entering execution.
- Divert completed-but-blocked tasks before the FN-7863 execute-requeue-loop counter increments, so waiting-on-dependency states are no longer misclassified as EXECUTION_DISPATCH_LOOP_EXHAUSTED.
- Add SelfHealingManager.reconcileCompletedBlockedTasks(): a bounded sweep (wired into both startup/maintenance and periodic self-healing passes) that clears the park and advances the task to review once getTaskCompletionBlockerForStore() resolves, guarded by auto-merge eligibility, user-pause, and live-execution checks; failed advances re-park rather than strand the row.
- Add run-audit mutation types task:completed-blocked-parked and task:completed-blocked-advanced (ids/counts/outcomes-only metadata) plus AGENTS.md/docs/architecture.md entries documenting the new lifecycle.
- Extend execute-requeue-loop-guard.test.ts with coverage for the park/advance flow, including the zero-step task edge case.

Files changed:
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |   2 +
 .../execute-requeue-loop-guard.test.ts             | 256 ++++++++++++++++++++-
 packages/engine/src/executor.ts                    |  85 ++++++-
 packages/engine/src/run-audit.ts                   |   4 +
 packages/engine/src/self-healing.ts                |  95 ++++++++
 6 files changed, 432 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-7926
Fusion-Task-Lineage: e47945f4-a816-447e-9ea1-7c13105d0ba9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-12 23:26:02 -07:00
gsxdsm
2e7fce21ae FN-7884: reset durable-agent error state on engine restart
Engine startup now treats itself as an implicit operator retry for durable heartbeat agents stuck in error, clearing eligible error states and re-arming heartbeats instead of waiting for the steady-state sweep's cooldown/exhaustion gates.

- Add SelfHealingManager.resetDurableAgentErrorStateOnStartup(), run first in runStartupRecovery(), which resets shared heartbeatErrorRecovery/legacy durableErrorRecovery metadata, clears lastError/pauseReason, flips eligible error and error-retry-exhausted-parked durable agents to active, and re-arms their heartbeat
- Preserve suppression for operator-actionable, stale worktree/module-resolution, user-paused, error-unrecoverable, ephemeral, disabled-runtime, and actively-executing agents
- Add agent:reset-error-state-on-startup run-audit mutation type with ids/counts/outcomes-only metadata (agentId, priorState, priorPauseReason, source)
- Add changeset FN-7884 (patch) documenting the operator-facing behavior
- Update AGENTS.md and docs/agents.md, docs/architecture.md to describe the new startup reset path alongside existing FN-7835/FN-7844/FN-7859/FN-7878 recovery docs
- Extend self-healing.test.ts with coverage for the new startup reset behavior and its exclusions

Files changed:
 .changeset/fn-7884-restart-error-reset.md          |   7 ++
 AGENTS.md                                          |   1 +
 docs/agents.md                                     |   4 +-
 docs/architecture.md                               |   2 +-
 packages/engine/src/__tests__/self-healing.test.ts | 127 ++++++++++++++++++++-
 packages/engine/src/run-audit.ts                   |   1 +
 packages/engine/src/self-healing.ts                |  88 +++++++++++++-
 7 files changed, 223 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-7884
Fusion-Task-Lineage: fe64f6af-3ff3-4876-8308-8a75591c45f1
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-12 17:39:29 -07:00
gsxdsm
504dc69f02 FN-7878: default heartbeat error recovery to recoverable for generic durable-agent failures
Durable agents were parking as error-unrecoverable on any non-transient-pattern failure, even generic/unknown blips that manual Retry immediately fixed; this changes the default to recoverable and reserves immediate unrecoverable parking for operator-actionable errors.

- isHeartbeatErrorRecoverable now returns true unless the error is operator-actionable (auth/model/billing/scope) or a stale worktree/module-resolution error, instead of requiring a transient-pattern match via classifyError
- Add OAuth scope-requirement and insufficient-scope patterns to the operator-actionable error detector so those still park immediately
- Update heartbeat-error-recovery, heartbeat-executor, self-healing, and transient-error-detector tests to cover the new default-recoverable behavior
- Update AGENTS.md and docs/architecture.md durable-agent error recovery notes to describe the new recoverable-by-default policy
- Add changeset documenting the fix

Files changed:
 .changeset/fn-7878-recoverable-default.md          |  7 ++
 AGENTS.md                                          |  2 +-
 docs/architecture.md                               |  4 +-
 .../src/__tests__/heartbeat-error-recovery.test.ts | 90 +++++++++++++++++++---
 .../src/__tests__/heartbeat-executor.test.ts       | 17 ++--
 packages/engine/src/__tests__/self-healing.test.ts | 45 ++++++-----
 .../src/__tests__/transient-error-detector.test.ts |  7 +-
 packages/engine/src/agent-heartbeat.ts             |  8 +-
 packages/engine/src/transient-error-detector.ts    |  2 +
 9 files changed, 137 insertions(+), 45 deletions(-)

Fusion-Task-Id: FN-7878

Fusion-Task-Lineage: 6f929af9-ceef-404f-95c9-98f26478f020

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-12 16:25:48 -07:00
gsxdsm
9cfb40e137 FN-7863: add bounded execute-node self-requeue loop guard
Bounds the execute->pause-abort->todo dispatch loop so a task can no longer requeue forever with no visible signal or terminal state.

- Track a progress-anchored `executeRequeueLoopCount`/`executeRequeueLoopSignature` pair on the task row (current step + step statuses) so slow no-progress requeue cycles are counted independently of the scheduler's wall-clock `dispatchStormCount` guard.
- Warn visibly in the task log at `EXECUTE_REQUEUE_LOOP_VISIBLE_THRESHOLD` (3) and terminalize non-paused, non-terminal tasks at `MAX_EXECUTE_REQUEUE_LOOP_CYCLES` (6) with `status:"failed"` and an `EXECUTION_DISPATCH_LOOP_EXHAUSTED:` error, preserving worktree/branch/step progress.
- Emit a new `task:execution-dispatch-loop-terminalized` run-audit mutation type with ids/counts/outcomes-only metadata.
- Reset the loop counters on real progress, manual retry, forward moves (in-review/done/archived), and unpause, in both the executor and scheduler.
- Add DB migration 142 (`executeRequeueLoopCount`, `executeRequeueLoopSignature` columns) plus store read/write/reset plumbing.
- Add reliability-interactions coverage for the new loop guard and extend store-persistence tests for the new columns.
- Document the new behavior in AGENTS.md and docs/architecture.md.

Files changed:
 AGENTS.md                                              |   1 +
 docs/architecture.md                                   |   2 +
 packages/core/src/__tests__/store-persistence.test.ts  |  45 +++++
 packages/core/src/db.ts                                |  17 +-
 packages/core/src/manual-retry-reset.ts                |   1 +
 packages/core/src/store.ts                             |  22 ++-
 packages/core/src/types.ts                             |  11 ++
 .../execute-requeue-loop-guard.test.ts                 | 188 +++++++++++++++
 packages/engine/src/executor.ts                        |  67 +++++++-
 packages/engine/src/run-audit.ts                       |   2 +
 packages/engine/src/scheduler.ts                       |   8 +-
 11 files changed, 355 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7863
Fusion-Task-Lineage: db40507f-5851-435e-8854-c1ed695b4154
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-12 11:56:54 -07:00
gsxdsm
67cc025562 FN-7859: park non-recoverable durable heartbeat errors instead of stalling in bare error
Debug org agents error state recovery regression: durable heartbeat-managed
agents with a non-recoverable error (permanent/credential/model-access/
config, not stale-worktree/module-resolution) were previously left
indefinitely in bare `state:"error"` with no operator-visible reason,
and CLI agent inspection tools did not surface error/pause diagnostics.

- Timer path (`HeartbeatMonitor`) and run-entry recovery now classify
  non-recoverable durable heartbeat errors and park the agent `paused`
  with `pauseReason:"error-unrecoverable"` instead of restart-looping or
  sitting in `error` forever.
- `SelfHealingManager` mirrors the same non-recoverable classification in
  its recovery sweep, parking with the same reason/metadata and skipping
  the exhausted/next-retry gates for that terminal bucket.
- New `agent:error-parked-unrecoverable` run-audit event type emitted by
  both the heartbeat and self-healing paths (ids/counts/outcomes-only
  metadata).
- `fn_agent_show` now prints `Last Error`, `Pause Reason`, and a compact
  `Error Recovery` counter line; `fn_list_agents` prints the same
  diagnostics only for agents currently in `error`/`paused`.
- Updated `AGENTS.md`, `docs/agents.md`, and `docs/architecture.md` to
  document the new terminal-park behavior and CLI diagnostics surface.
- Added a changeset (`@runfusion/fusion` patch) describing the
  operator-facing fix.

Files changed:
 .changeset/fn-7859-org-agent-error-diagnostics.md  |  7 ++
 AGENTS.md                                          |  2 +-
 docs/agents.md                                     |  3 +-
 docs/architecture.md                               |  4 +-
 packages/cli/src/__tests__/extension.test.ts       | 68 ++++++++++++++++
 packages/cli/src/extension.ts                      | 64 +++++++++++++++
 .../src/__tests__/heartbeat-error-recovery.test.ts | 47 ++++++++++-
 packages/engine/src/__tests__/self-healing.test.ts | 94 ++++++++++++++++++----
 packages/engine/src/agent-heartbeat.ts             | 71 +++++++++++++++-
 packages/engine/src/run-audit.ts                   |  1 +
 packages/engine/src/self-healing.ts                | 46 +++++++++--
 11 files changed, 375 insertions(+), 32 deletions(-)

Fusion-Task-Id: FN-7859

Fusion-Task-Lineage: 09b2035d-e8a0-438f-b1ab-1b0048b35c76

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-12 11:34:48 -07:00
gsxdsm
e559b2b538 FN-7853: preserve chat thread during active streaming turns
Fix useChat so already-rendered user/assistant messages no longer flicker away while an agent turn is actively streaming.

- useChat.ts: during an active streaming turn for the current session, treat stale/empty/cross-session loadMessages responses as append-only against the visible thread instead of replacing it, merging any genuinely new same-session messages in and skipping the session-cache write when the active thread is being preserved.
- ChatView.streaming-thread.test.tsx: add coverage asserting the rendered thread stays visible across mid-turn session-update/tool-call/stale-reload churn.
- useChat.test.ts: add hook-level regression tests for the append-only/merge/cache-skip behavior during active streaming.
- docs/architecture.md, docs/dashboard-guide.md: document the append-only mid-turn thread-stability behavior.
- Add changeset (patch) for @runfusion/fusion describing the user-facing fix.

Files changed:
 .../fn-7853-chat-mid-turn-message-stability.md     |   7 +
 docs/architecture.md                               |   1 +
 docs/dashboard-guide.md                            |   1 +
 .../__tests__/ChatView.streaming-thread.test.tsx   | 130 +++++++++++++
 .../dashboard/app/hooks/__tests__/useChat.test.ts  | 208 +++++++++++++++++++++
 packages/dashboard/app/hooks/useChat.ts            |  35 +++-
 6 files changed, 380 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7853

Fusion-Task-Lineage: d9909469-082c-4eeb-81fb-b36d1a9e4705

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-12 11:26:53 -07:00
gsxdsm
c9d0211bec FN-7844: coordinate heartbeat and self-healing durable-agent error recovery
Unifies the two independent durable-agent error-recovery paths (heartbeat timer and self-healing sweep) so they share one retry budget, eligibility check, and audit surface instead of racing separate counters.

- Share the heartbeatErrorRecovery attempt budget between HeartbeatMonitor's timer-entry recovery and SelfHealingManager.recoverOrphanedAgents(), with self-healing's legacy durableErrorRecovery metadata folded into the same counter via readHeartbeatErrorRetryCount().
- Add isHeartbeatErrorRecoverable() as the single transient/non-operator-actionable eligibility check, used by both the heartbeat timer and self-healing paths (self-healing additionally allows stale-worktree module-resolution errors).
- resetHeartbeatErrorRecoveryMetadata() now strips the legacy durableErrorRecovery field so recovered agents don't retain stale sweep bookkeeping.
- Self-healing emits the shared agent:auto-recover-error-state / agent:error-retry-exhausted run-audit events with source:"self-healing", and parks the agent paused with pauseReason:"error-retry-exhausted" on budget exhaustion, matching the heartbeat-timer behavior.
- Update AGENTS.md, docs/architecture.md, and docs/agents.md to describe the consolidated recovery budget and audit surface.
- Add a patch changeset documenting the fix for @runfusion/fusion.

Files changed:
 .changeset/fn-7844-error-recovery-coordination.md  |  7 ++
 AGENTS.md                                          |  2 +-
 docs/agents.md                                     | 14 ++--
 docs/architecture.md                               |  2 +-
 packages/engine/src/__tests__/heartbeat-error-recovery.test.ts | 13 +++-
 packages/engine/src/__tests__/self-healing.test.ts | 58 ++++++++++++++-
 packages/engine/src/agent-heartbeat.ts             | 35 ++++++---
 packages/engine/src/self-healing.ts                | 85 ++++++++++++++++++----
 8 files changed, 180 insertions(+), 36 deletions(-)

Fusion-Task-Id: FN-7844
Fusion-Task-Lineage: b70dcba5-56b6-412c-8be2-ef827bee9964
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-11 22:31:30 -07:00
gsxdsm
391ff0d269 FN-7835: auto-clear durable agent error state and retry on next heartbeat
Heartbeat-managed durable agents that land in state:"error" now self-recover on the next heartbeat instead of staying stuck until an operator intervenes.

- HeartbeatTriggerScheduler keeps timers armed for durable heartbeat-managed agents in error state when the last error is transient and not operator-actionable (credential/quota/model-access/permanent-config failures stay parked).
- executeHeartbeat clears recoverable errors at run entry (error → active, clears lastError), bounded by MAX_HEARTBEAT_ERROR_RECOVERY_ATTEMPTS (settings-overridable); a successful run resets the counter.
- On budget exhaustion, the agent is parked paused with pauseReason:"error-retry-exhausted".
- Emits new run-audit events agent:auto-recover-error-state and agent:error-retry-exhausted (added to DatabaseMutationType).
- Adds heartbeat-error-recovery.test.ts and extends heartbeat-scheduler.test.ts to cover the recovery/exhaustion paths.
- Adds changeset and documents the new behavior in AGENTS.md and docs/architecture.md.

Files changed:
 .changeset/fn-7835-agent-error-auto-recovery.md    |   7 +
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |   2 +
 .../src/__tests__/heartbeat-error-recovery.test.ts | 323 +++++++++++++++++++++
 .../src/__tests__/heartbeat-scheduler.test.ts      |  89 +++++-
 packages/engine/src/agent-heartbeat.ts             | 209 ++++++++++++-
 packages/engine/src/run-audit.ts                   |   2 +
 7 files changed, 618 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-7835

Fusion-Task-Lineage: 1bbb28a3-8eb9-40e3-8177-6658ec5dae40

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-11 22:16:48 -07:00
gsxdsm
21fb8f6786 FN-7802: recover phantom-worktree tasks stuck merge-active with scopeOverride
Fixes phantom-worktree context bleed where the engine refused to start a
coding agent in a missing worktree for in-review/merge-active tasks even
when scopeOverride=1, stranding them past the normal recovery paths and
retry budget.

- Add isMergeActiveMissingWorktreeSessionStartFailure/isInReviewMissingWorktreeSessionStartFailure classifiers and MERGE_ACTIVE_MISSING_WORKTREE_STATUSES (merging/merging-pr/merging-fix) in restart-recovery-coordinator.ts, exported from @fusion/engine.
- Self-healing: reorder missing-worktree-review-failures sweep earlier, extend the in-review sweep to also match merge-active missing-worktree failures with a triple-proof-guarded, bounded (recoveryRetryCount) stale-metadata clear and fresh session-start retry budget reset.
- Self-healing: extend scopeOverride worktree-metadata reconciliation to safely clear phantom worktree/branch/session metadata for in-review tasks stuck in a merge-active sub-status, narrowly scoped to avoid clobbering genuinely live in-progress/mid-step tasks (FN-5256 guard preserved).
- CLI (task.ts), pi extension (extension.ts), and dashboard route (register-task-workflow-routes.ts) retry paths now bypass the merge-active status gate via a signature-only check, clearing worktree/branch/sessionFile and requeuing to todo while preserving progress.
- Add regression coverage across self-healing.test.ts, restart-recovery-coordinator.test.ts, extension.test.ts, task-retry.test.ts, and routes-tasks-ops.test.ts; update mockCoreEngine.ts test scaffolding.
- Update docs/architecture.md, docs/self-healing-backward-move-audit.md, docs/task-management.md, and AGENTS.md to describe the new merge-active missing-worktree recovery behavior.
- Add changeset (patch) for @runfusion/fusion.

Files changed:
 .changeset/fn-7802-phantom-worktree-merge-active-recovery.md      |   7 +
 AGENTS.md                                                          |   1 +
 docs/architecture.md                                               |   4 +-
 docs/self-healing-backward-move-audit.md                           |   5 +-
 docs/task-management.md                                            |   2 +-
 packages/cli/src/__tests__/extension.test.ts                       |  64 +++++
 packages/cli/src/__tests__/task-retry.test.ts                      |  49 ++++
 packages/cli/src/commands/task.ts                                  |  28 +-
 packages/cli/src/extension.ts                                      |  26 +-
 packages/dashboard/src/__tests__/routes-tasks-ops.test.ts          |  52 ++++
 packages/dashboard/src/routes/register-task-workflow-routes.ts     |  25 +-
 packages/dashboard/src/test/mockCoreEngine.ts                      |  11 +
 packages/engine/src/__tests__/restart-recovery-coordinator.test.ts |  20 ++
 packages/engine/src/__tests__/self-healing.test.ts                 | 297 +++++++++++++++++++++
 packages/engine/src/index.ts                                       |  13 +
 packages/engine/src/restart-recovery-coordinator.ts                |  19 +-
 packages/engine/src/self-healing.ts                                | 157 +++++++++--
 17 files changed, 744 insertions(+), 36 deletions(-)

Fusion-Task-Id: FN-7802

Fusion-Task-Lineage: 5897105b-6b5c-49d5-a8e8-519902182861

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-10 22:25:21 -07:00
gsxdsm
786a274ae6 FN-7749: fix benign pause/resume abort marking manual merge holds as failed
Fixes tasks in auto-merge-off manual merge hold getting incorrectly marked failed by a benign pause/resume abort, which blocked Merge & Close.

- Add isBenignManualMergeHoldPauseAbort classifier in executor.ts: recognizes a hard-cancel pause-abort at a merge-region node while auto-merge is off (or processing is disallowed) as benign, and preserves the in-review row instead of failing/re-enqueueing it.
- Clear stale pause-abort status/error and suppress the failure notification when this benign manual-hold case is detected, per FN-5147's no-backward-move/no-reenqueue contract.
- Extend self-healing.ts recovery to handle this manual-hold case alongside existing paused-abort recovery paths.
- Add/extend tests in merge-node-paused-abort-retryable.test.ts and self-healing-paused-abort-recovery.test.ts covering the new benign classification.
- Document the fix in docs/architecture.md.
- Add changeset (patch) describing the user-facing fix.

Files changed:
 .changeset/fn-7749-manual-merge-hold-false-failure.md                                   |  7 +++
 docs/architecture.md                                                                    |  4 +-
 packages/engine/src/__tests__/reliability-interactions/merge-node-paused-abort-retryable.test.ts | 50 +++++++++++++++++----
 packages/engine/src/__tests__/self-healing-paused-abort-recovery.test.ts                | 49 ++++++++++++++++++++-
 packages/engine/src/executor.ts                                                         | 51 +++++++++++++++++++++-
 packages/engine/src/self-healing.ts                                                     | 23 ++++++++--
 6 files changed, 168 insertions(+), 16 deletions(-)

Fusion-Task-Id: FN-7749
Fusion-Task-Lineage: 6d90adc3-6cd9-463d-b9d0-7a5c3069c1a5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:08 -07:00
gsxdsm
2ff8e2e13e FN-7743: detect and recover stalled in-progress executor tasks in overseer
Fix the planner overseer's executor-stage stall detection so hung in-progress tasks get unstuck instead of being reported as progressing forever.

- Add configurable stuck-detection: the executor-stage overseer observation now emits signal: "stuck" once an in-progress task has been inactive past a new plannerOverseerExecutorStuckAfterMs threshold, feeding the existing decidePlannerRecovery -> bounded inject_guidance recovery path.
- Register the new plannerOverseerExecutorStuckAfterMs setting in builtin-workflow-settings.ts and export it via core index.ts/index.gate.ts.
- Preserve human-control withholds (user-paused / approval-blocked / autoMerge-off) taking precedence over stuck detection.
- Add/extend tests covering planner-overseer, planner-recovery-controller, planner-recovery, and builtin-workflow-settings-triage.
- Document the new setting in docs/architecture.md and docs/settings-reference.md.
- Add changeset fn-7743-overseer-executor-stall.md (patch).

Files changed:
 .changeset/fn-7743-overseer-executor-stall.md      |   7 +
 docs/architecture.md                               |  31 +++++
 docs/settings-reference.md                         |   3 +-
 .../builtin-workflow-settings-triage.test.ts       |  22 ++++
 .../core/src/__tests__/planner-recovery.test.ts    |  12 ++
 packages/core/src/builtin-workflow-settings.ts     |  26 ++++
 packages/core/src/index.gate.ts                    |   1 +
 packages/core/src/index.ts                         |   1 +
 .../engine/src/__tests__/planner-overseer.test.ts  | 146 +++++++++++++++++++++
 .../__tests__/planner-recovery-controller.test.ts  |  52 +++++++-
 packages/engine/src/planner-overseer.ts            |  88 ++++++++++++-
 packages/engine/src/project-engine.ts              |  11 +-
 12 files changed, 391 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7743

Fusion-Task-Lineage: 791852a2-5b77-48de-955a-1b3916616dfa

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
bab42b40dd FN-7736: prevent recovery/oversight from resuming approval-blocked tasks
Introduces a canonical awaiting-approval pause reason and predicate so recovery and oversight paths treat approval-blocked tasks as terminal-until-approved instead of eligible for early rebound.

- Add isTaskBlockedOnApproval predicate and canonical "awaiting-approval" pause reason in @fusion/core (store.ts, task-merge.ts, index.ts/index.gate.ts)
- Exclude approval-blocked tasks from paused-scope-decay rebound in self-healing.ts
- Keep the planner overseer withholding oversight for approval-blocked tasks (overseer-human-control-policy.ts)
- Executor and agent-heartbeat now recognize the approval-blocked state and avoid resuming it
- Add regression tests across store-persistence, task-merge, overseer-human-control-policy, paused-scope-decay, and self-healing-paused-abort-recovery
- Update docs/architecture.md with the new approval-hold invariant
- Add changeset fn-7736-approval-hold.md (patch)

Files changed:
 .changeset/fn-7736-approval-hold.md                |  7 +++
 docs/architecture.md                               | 64 ++++++++++++++++++++--
 .../core/src/__tests__/store-persistence.test.ts   | 18 ++++++
 packages/core/src/__tests__/task-merge.test.ts     | 34 ++++++++++++
 packages/core/src/index.gate.ts                    |  2 +
 packages/core/src/index.ts                         |  2 +
 packages/core/src/store.ts                         | 18 +++++-
 packages/core/src/task-merge.ts                    | 34 ++++++++++++
 .../executor-approval-gate-suspend.test.ts         |  5 +-
 .../src/__tests__/heartbeat-executor.test.ts       |  5 +-
 .../overseer-human-control-policy.test.ts          | 44 +++++++++++++++
 .../paused-scope-decay.test.ts                     | 44 +++++++++++++++
 .../self-healing-paused-abort-recovery.test.ts     | 21 +++++++
 packages/engine/src/agent-heartbeat.ts             |  8 ++-
 packages/engine/src/executor.ts                    | 13 ++++-
 .../engine/src/overseer-human-control-policy.ts    | 45 +++++++++++----
 packages/engine/src/self-healing.ts                | 12 +++-
 17 files changed, 351 insertions(+), 25 deletions(-)

Fusion-Task-Id: FN-7736

Fusion-Task-Lineage: 67e05b7f-f621-4f9b-bc01-721ff05d715b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
badb86a965 FN-7726: unify fs.watch/poll logic between TaskStore and AgentStore
Extracted the duplicated file-watch-with-polling-fallback logic from TaskStore and AgentStore into a shared controller.

- Added packages/core/src/fs-watch-poll-controller.ts implementing a reusable fs.watch + polling-fallback controller
- Refactored packages/core/src/store.ts (TaskStore) to use the shared controller instead of its own watch/poll implementation
- Refactored packages/core/src/agent-store.ts (AgentStore) to use the shared controller instead of its own watch/poll implementation
- Added packages/core/src/__tests__/fs-watch-poll-controller.test.ts covering the new controller's behavior
- Updated docs/architecture.md to document the shared controller

Files changed:
 docs/architecture.md                               |   1 +
 .../src/__tests__/fs-watch-poll-controller.test.ts | 187 +++++++++++++++++++++
 packages/core/src/agent-store.ts                   |  66 +++-----
 packages/core/src/fs-watch-poll-controller.ts      | 123 ++++++++++++++
 packages/core/src/store.ts                         |  66 +++-----
 5 files changed, 364 insertions(+), 79 deletions(-)

Fusion-Task-Id: FN-7726
Fusion-Task-Lineage: 69be6dc3-5414-44f2-a3f1-3eb72c2d7391
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
e657d3b965 FN-7723: add cross-process agent state change notification bus
Adds opt-in cross-process change detection to AgentStore so the engine reacts to CLI-driven agent stop/start mutations promptly instead of waiting for the periodic audit sweep.

- AgentStore gains fs.watch-based (with poll fallback) cross-process notification, modeled on TaskStore's existing mechanism
- Re-emits existing agent:updated/agent:stateChanged events in the engine process when another process (the fn CLI) mutates an agent row
- HeartbeatTriggerScheduler listeners now fire immediately instead of waiting up to 60s for the auditTimerRegistrations sweep; the sweep remains as durable backstop
- in-process-runtime.ts wires up the new notification bus
- Adds unit tests for agent-store cross-process notifications and heartbeat-scheduler reaction behavior
- Updates docs/agents.md and docs/architecture.md
- Adds changeset (patch) for @runfusion/fusion

Files changed:
 .changeset/fn-7723-cross-process-agent-notify.md   |   7 +
 docs/agents.md                                     |   1 +
 docs/architecture.md                               |   1 +
 packages/core/src/__tests__/agent-store.test.ts    | 177 +++++++++++++++++
 packages/core/src/agent-store.ts                   | 210 ++++++++++++++++++++-
 .../src/__tests__/heartbeat-scheduler.test.ts      | 162 ++++++++++++++++
 packages/engine/src/runtimes/in-process-runtime.ts |  30 +++
 7 files changed, 587 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7723
Fusion-Task-Lineage: d3a7fa05-b40d-4388-8e98-140f9d8861c9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
cda9532c3b FN-7718: fix zombie heartbeat timers surviving agent stop/start
Ensures stopping and restarting an agent durably clears its heartbeat timer instead of relying on the later FN-7645 watchdog repair.

- HeartbeatTriggerScheduler.auditTimerRegistrations now unregisters lingering timers for non-eligible (stopped/paused/disabled) agents
- syncTimerForAgent force-re-arms a stale present timer on a start transition so no orphaned timer entry lingers
- Added 308 lines of new heartbeat-scheduler regression tests covering the stop/start zombie-timer scenarios
- Added changeset (patch) documenting the fix
- Updated docs/agents.md and docs/architecture.md to describe the new invariant

Files changed:
 .changeset/fn-7718-zombie-timer-invalidate.md      |   7 +
 docs/agents.md                                     |   2 +
 docs/architecture.md                               |   1 +
 .../src/__tests__/heartbeat-scheduler.test.ts      | 308 +++++++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             |  49 +++-
 5 files changed, 364 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7718

Fusion-Task-Lineage: fc834ccd-495e-4294-805d-325b4cb536a2

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
c8fcbec94f FN-7717: release active-session locks when a task is archived
Archiving a task from triage/planning/todo (not just in-progress) previously left leaked active-session-registry entries, so a successor task could hit ActiveSessionPathHeldByForeignTaskError and get blocked from Plan Review.

- Add an explicit `to === "archived"` branch in the task-move handler that awaits abort of in-flight task work and sweeps any leftover activeSessionRegistry paths for the task, checked before the narrower `from === "in-progress"` branch so direct in-progress→archived transitions are covered too.
- Deliberately exclude `to === "done"` / `to === "in-review"` from this sweep since those columns legitimately hold ai-merge / workspace-repo-land merge leases that must survive the transition.
- Add regression test coverage for archive releasing active sessions across originating columns.
- Add changeset and architecture doc note.

Files changed:
 .../fn-7717-archive-active-session-release.md      |   7 +
 docs/architecture.md                               |   1 +
 ...xecutor-archive-releases-active-session.test.ts | 167 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |  35 +++++
 4 files changed, 210 insertions(+)

Fusion-Task-Id: FN-7717

Fusion-Task-Lineage: 7cff6821-7bb3-4b75-b502-a26467ca7f51

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
gsxdsm
67cc02750c FN-7692: fix misleading merger confirmation copy under active auto-merge
Correct the planner-oversight confirmation messaging so it no longer claims a hard block when the active auto-merge policy will actually advance the merge/pull-request stage unattended.

- decidePlannerRecovery accepts an additive, messaging-only `autoMergeWillProceed` flag and picks accurate reason wording (advisory vs. genuine human-approval block vs. neutral/unknown) for merger/pull-request await_confirmation decisions
- PlannerRecoveryController.tick threads `allowsAutoMergeProcessing(task, settings)` into decidePlannerRecovery as `autoMergeWillProceed`
- project-engine's requestConfirmation steering comment prefix changed from "confirmation required" to neutral "merge checkpoint" so it doesn't contradict the now-accurate reason text
- added regression tests in planner-recovery.test.ts and planner-overseer-intervention-wiring.test.ts
- added changeset and doc note

Files changed:
 .changeset/fn-7692-merger-confirmation-copy.md     |  7 +++
 docs/architecture.md                               | 10 +++-
 packages/core/src/__tests__/planner-recovery.test.ts    | 66 ++++++++++++++++++++++
 packages/core/src/planner-recovery.ts              | 36 +++++++++++-
 packages/engine/src/__tests__/planner-overseer-intervention-wiring.test.ts | 37 ++++++++++++
 packages/engine/src/planner-recovery-controller.ts | 14 ++++-
 packages/engine/src/project-engine.ts               | 11 +++-
 7 files changed, 176 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7692

Fusion-Task-Lineage: 187684b8-1d24-425d-85d4-627587469908

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-08 15:09:26 -07:00
gsxdsm
bec8987ce9 FN-7648: gate hold-release on trait-based unplanned-card check, not literal todo column
Blocks planning/intake column cards from entering processing columns regardless of literal column id, so renamed custom intake/planning columns are covered by the same guard as the legacy todo column.

- Add isUnplannedForExecution() in hold-release.ts: true when task.status==="planning", or when the card sits in the legacy todo column or a column carrying the intake trait AND its PROMPT.md still equals the bootstrap stub.
- Route issueRelease() (used by the sweep, promoteHeldTask, and releaseHeldTaskByEvent) through this guard before releasing into any countsTowardWip processing column.
- Update scheduler.ts's reserveSlot guard to use the same trait-based predicate instead of a hardcoded "todo" column id check.
- Add regression tests in hold-release.test.ts and scheduler-workflow-cutover.test.ts covering renamed intake/planning columns.
- Document the invariant in docs/architecture.md and docs/workflow-steps.md.
- Add changeset (patch) describing the fix.

Files changed:
 .changeset/fn-7648-unplanned-intake-cards-never-execute.md |   7 +
 docs/architecture.md                               |   2 +
 docs/workflow-steps.md                             |   2 +
 packages/engine/src/__tests__/hold-release.test.ts | 238 +++++++++++++++++++++
 packages/engine/src/__tests__/scheduler-workflow-cutover.test.ts |  60 +++++-
 packages/engine/src/hold-release.ts                |  60 ++++++
 packages/engine/src/scheduler.ts                   |  26 +--
 7 files changed, 378 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-7648

Fusion-Task-Lineage: a4b54d30-f86d-4eb9-9cf2-6ac55b6dbe58

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:06:21 -07:00
gsxdsm
923bba7082 FN-7645: force re-arm zombie heartbeat timers detected as stale during audit
Fixes the heartbeat timer audit so it repairs not just missing timer registrations but also 'zombie' ones — timer entries that remain present in memory after their underlying interval silently stopped firing. Long-interval (~1h) agents were most affected since a single lost tick compounded into hours of staleness before self-healing noticed.

- HeartbeatTriggerScheduler audit now computes staleness (elapsed vs repair-stale threshold) up front for every timer-eligible agent, not only for agents missing a timer entry
- Present-but-stale timer entries are now treated as non-advancing and force cleared/re-registered via registerAgent() (which already clears any existing timer before re-arming)
- Fresh (non-stale) present timers are left alone so healthy short-interval agents are never force-re-armed or double-ticked
- Repair reason/log messages now distinguish zombie-timer-rearmed repairs from missing-registration repairs, and the summary log reports counts for each
- Added heartbeat-scheduler tests covering the zombie-timer repair path
- Added changeset and a docs/architecture.md note

Files changed:
 .changeset/fn-7645-heartbeat-rearm.md              |   7 +
 docs/architecture.md                               |   1 +
 .../src/__tests__/heartbeat-scheduler.test.ts      | 223 +++++++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             |  42 +++-
 4 files changed, 266 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-7645

Fusion-Task-Lineage: 652bc2eb-a660-4306-9f85-d2d5f9ca7e38

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:06:18 -07:00
gsxdsm
9e5c025113 FN-7608: block executors on pending approvals instead of allowing workarounds
Executors could previously treat a pending approval as a normal turn end and go hunt for ungated workarounds instead of stopping. This change makes wait-for-approval a hard suspend point.

- wait-for-approval now suspends the in-flight executor session via awaitAbortInFlightTaskWork
- Dedupe identical pending approvals so repeated waits don't pile up
- Executor prompts now carve out awaiting-approval as a legitimate turn end (agent-prompts.ts)
- Extend provisioning-gate and agent-action-gate coverage for the new suspend/carveout behavior
- Add changeset (patch) documenting the fix for release notes
- Update docs/agents.md and docs/architecture.md to describe the new blocking behavior

Files changed:
 .changeset/fn-7608-awaiting-approval-blocking.md   |   7 ++
 docs/agents.md                                     |   1 +
 docs/architecture.md                               |   1 +
 packages/core/src/agent-prompts.ts                 |   5 +
 .../engine/src/__tests__/agent-action-gate.test.ts |  82 +++++++++++++
 .../executor-approval-gate-suspend.test.ts         | 128 +++++++++++++++++++++
 .../executor-approval-prompt-carveout.test.ts      |  61 ++++++++++
 packages/engine/src/agent-heartbeat.ts             |  13 +++
 packages/engine/src/executor.ts                    |  28 +++++
 packages/engine/src/pi.ts                          |  22 +++-
 .../sandbox/__tests__/provisioning-gate.test.ts    |  29 +++++
 packages/engine/src/sandbox/provisioning-gate.ts   |  11 ++
 12 files changed, 384 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-7608

Fusion-Task-Lineage: 9e42d8ee-bda7-4ef1-b159-46c2100bbc48

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-06 19:03:07 -07:00
gsxdsm
3d58260e1a FN-7551: wire overseer decision points to engine emitOverseer* façade
Wires PlannerOverseerMonitor/PlannerRecoveryController decision points (human-control withholds, confirmation requests/resolutions, and related overseer stages) to the FN-7520 emitOverseer* façade using the real TaskStore, so the planner-oversight intervention timeline now populates from real engine activity instead of staying empty.

- Add onConfirmationResolved handler to PlannerRecoveryController, invoked (best-effort, audit-only) from resolveConfirmation for both approved and denied outcomes.
- Wire project-engine.ts to call emitOverseerObservation/emitOverseerEscalation/emitOverseerConfirmation at the real engine decision points, deduped per (task, stage[, signal]).
- Add planner-overseer-intervention-wiring.test.ts covering the new wiring end-to-end.
- Update docs/architecture.md to reflect the wiring.
- Add changeset fn-7551-overseer-timeline-wiring.md (patch).

Files changed:
 .changeset/fn-7551-overseer-timeline-wiring.md     |   7 +
 docs/architecture.md                               |   2 +-
 .../planner-overseer-intervention-wiring.test.ts   | 319 +++++++++++++++++++++
 packages/engine/src/planner-recovery-controller.ts |  36 +++
 packages/engine/src/project-engine.ts              | 248 +++++++++++++++-
 5 files changed, 607 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7551

Fusion-Task-Lineage: 8bcd103e-8797-4ef5-9b68-bd2daec8d26b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 21:28:18 -07:00
gsxdsm
bf688394a2 FN-7520: add run-audit emission facade for planner-overseer decision points
Adds a canonical emission layer over recordPlannerIntervention so overseer decision points (observation, steering, recovery attempt, retry, confirmation, escalation) emit consistent overseer:intervention run-audit events without inlining action/outcome logic at each call-site.

- Add packages/core/src/planner-overseer-events.ts with emitOverseerObservation, emitOverseerSteering, emitOverseerRecoveryAttempt, emitOverseerRetry, emitOverseerConfirmation, and emitOverseerEscalation, each fixing its category's intervention action/default outcome and delegating to recordPlannerIntervention.
- Export the new emitters and OverseerEventInput type from packages/core/src/index.ts.
- Add unit tests covering each emitter's action/outcome mapping and metadata pass-through.
- Add a minor changeset documenting the new run-audit emission facade for planner-overseer events.
- Update docs/architecture.md's Run Audit API section to describe the FN-7520 emission facade and its relationship to FN-7519's overseer:intervention mutation type.

Files changed:
 .changeset/fn-7520-planner-overseer-events.md      |   7 +
 docs/architecture.md                               |   2 +-
 packages/core/src/__tests__/planner-overseer-events.test.ts | 236 +++++++++++++++++++++
 packages/core/src/index.ts                         |   9 +
 packages/core/src/planner-overseer-events.ts       | 128 +++++++++++
 5 files changed, 381 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7520

Fusion-Task-Lineage: 85e0d761-e4f3-437e-abe2-031e6cf89c1c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 21:28:17 -07:00
gsxdsm
d10ea9aef1 FN-7519: add planner-overseer intervention timeline model and UI
Introduces a persisted planner-overseer intervention timeline surfaced in the task-detail Planner Oversight cluster, recording stage, reason, action taken, outcome, attempt count/limit, and source links for each intervention.

- Add core `PlannerInterventionEntry` type plus `recordPlannerIntervention`/`getPlannerInterventionTimeline` helpers that persist entries via the run-audit store under the `overseer:intervention` mutation
- Add `PlannerInterventionTimeline` dashboard component rendering the timeline (stage/reason/action/outcome/attempts/links) with associated styles
- Wire the new API route/legacy handler and TaskDetailModal integration to expose and render the timeline
- Add unit tests for the core helpers and the new UI component
- Add changeset for the new minor feature and update architecture/dashboard-guide docs

Files changed:
$(cat /tmp/diffstat_7519.txt)

Fusion-Task-Id: FN-7519

Fusion-Task-Lineage: 3c4fcda3-9eb2-46d3-b142-b0c7d6334cd0

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 21:28:17 -07:00
gsxdsm
726cbf89cc FN-7531: expose planner overseer state to task cards
Expose transient planner overseer runtime snapshots to board task payloads and cards.

- Add core planner overseer state types and deterministic state derivation.
- Assemble read-only engine runtime snapshots from overseer observations and recovery registries.
- Enrich GET /api/tasks with best-effort planner overseer state and render non-idle TaskCard badges.
- Cover state derivation, API enrichment, runtime snapshot assembly, and card rendering with tests.

Files changed:
 .../fn-7531-planner-overseer-state-exposure.md     |   7 ++
 docs/architecture.md                               |  36 +++++++
 .../src/__tests__/planner-overseer-state.test.ts   |  85 +++++++++++++++
 packages/core/src/index.ts                         |   7 ++
 packages/core/src/planner-overseer-state.ts        |  78 ++++++++++++++
 packages/core/src/types.ts                         |  12 +++
 packages/dashboard/app/components/TaskCard.tsx     |  27 ++++-
 .../app/components/__tests__/TaskCard.test.tsx     |  29 ++++++
 .../__tests__/tasks-planner-overseer-state.test.ts | 114 +++++++++++++++++++++
 .../src/routes/register-task-workflow-routes.ts    |  23 ++++-
 .../planner-overseer-runtime-snapshot.test.ts      | 104 +++++++++++++++++++
 packages/engine/src/index.ts                       |   8 ++
 .../src/planner-overseer-runtime-snapshot.ts       |  67 ++++++++++++
 packages/engine/src/project-engine.ts              |  17 +++
 14 files changed, 612 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7531

Fusion-Task-Lineage: b7659ed2-bf33-4312-a5ab-818ad37049b9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 21:28:15 -07:00
gsxdsm
79ab367547 FN-7514: withhold overseer actions under human control
Add a human-control guard so planner overseer recovery stays inert for paused or human-review tasks.

- Add a pure overseer human-control policy that treats explicit user pauses and autoMerge:false / human-review tasks as full withhold states.
- Thread settings through planner recovery ticks, skip action classification and pending confirmations when withheld, and emit deduped no-action run-audit events.
- Wire ProjectEngine audit recording and document the new guard, run-audit event, exports, and release note.

Files changed:
 .changeset/fn-7514-overseer-human-control-guard.md |   7 +
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |  39 +++++
 .../overseer-human-control-policy.test.ts          |  86 +++++++++++
 ...anner-recovery-controller-human-control.test.ts | 170 +++++++++++++++++++++
 packages/engine/src/index.ts                       |   7 +
 .../engine/src/overseer-human-control-policy.ts    |  88 +++++++++++
 packages/engine/src/planner-recovery-controller.ts | 107 ++++++++++++-
 packages/engine/src/project-engine.ts              |  44 +++++-
 packages/engine/src/run-audit.ts                   |  15 +-
 10 files changed, 558 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-7514

Fusion-Task-Lineage: d4d3bd04-3f8e-4a05-9636-f177e050390b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 14:11:25 -07:00
gsxdsm
2cc84b5177 FN-7513: require planner confirmation for risky side effects
Require explicit approval before planner recovery runs merge, PR, destructive, or external-service actions.

- Add pure planner side-effect classification and confirmation request modeling in core.
- Route merge/PR recovery decisions to await confirmation instead of autonomous dispatch.
- Persist pending confirmation requests and only execute approved controller actions.
- Cover confirmation gating with core and engine regression tests and document the policy.

Files changed:
 .changeset/fn-7513-planner-confirmation-gate.md    |   7 +
 docs/architecture.md                               |  85 ++++++++-
 docs/settings-reference.md                         |   2 +-
 .../src/__tests__/planner-confirmation.test.ts     | 125 +++++++++++++
 .../core/src/__tests__/planner-recovery.test.ts    |  14 +-
 packages/core/src/index.ts                         |   7 +
 packages/core/src/planner-confirmation.ts          | 141 ++++++++++++++
 packages/core/src/planner-recovery.ts              | 103 ++++++++---
 ...lanner-recovery-controller-confirmation.test.ts | 205 +++++++++++++++++++++
 packages/engine/src/index.ts                       |   5 +
 packages/engine/src/planner-recovery-controller.ts | 204 +++++++++++++++++++-
 packages/engine/src/project-engine.ts              |  44 +++++
 12 files changed, 913 insertions(+), 29 deletions(-)

Fusion-Task-Id: FN-7513

Fusion-Task-Lineage: 1e3c6640-8a4f-41f6-89dd-41eb9b675b2b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 13:51:09 -07:00
gsxdsm
81f2053921 FN-7512: add bounded planner recovery
Adds bounded autonomous planner recovery decisions and dispatch so overseer observations can safely nudge stuck planning stages.

- Add pure core recovery policy with per-stage attempt limits and no-op fallbacks for disallowed or exhausted cases.
- Add engine controller wiring to inject guidance, retry steps, request targeted fixes, and emit recovery audit events.
- Register the planner recovery controller in project engine lifecycle and document the autonomous recovery behavior.
- Cover core decisions and controller dispatch with targeted tests, plus a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7512-planner-bounded-recovery.md     |   7 +
 docs/architecture.md                               |  62 ++++++
 .../core/src/__tests__/planner-recovery.test.ts    | 116 +++++++++++
 packages/core/src/index.ts                         |  12 ++
 packages/core/src/planner-recovery.ts              | 222 +++++++++++++++++++++
 .../__tests__/planner-recovery-controller.test.ts  | 163 +++++++++++++++
 packages/engine/src/index.ts                       |  20 ++
 packages/engine/src/planner-recovery-controller.ts | 195 ++++++++++++++++++
 packages/engine/src/project-engine.ts              |  66 ++++++
 9 files changed, 863 insertions(+)

Fusion-Task-Id: FN-7512

Fusion-Task-Lineage: aad3849d-090e-497d-ae5c-34ec7ca96c3d

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 13:19:02 -07:00
gsxdsm
12a6d1bc6a FN-7511: add planner overseer stage monitoring
Add records-only planner overseer monitoring across in-flight task lifecycle stages.

- Add a PlannerOverseerMonitor with normalized observations and deterministic watched-stage resolution.
- Wire ProjectEngine to poll in-progress and in-review tasks, gated by effective planner oversight level.
- Document the monitoring seam and add focused coverage plus a release changeset.

Files changed:
 .changeset/fn-7511-planner-overseer-monitoring.md  |   7 +
 docs/architecture.md                               |  26 ++
 docs/workflow-steps.md                             |   2 +
 .../engine/src/__tests__/planner-overseer.test.ts  | 294 ++++++++++++++++++
 packages/engine/src/index.ts                       |  12 +
 packages/engine/src/planner-overseer.ts            | 338 +++++++++++++++++++++
 packages/engine/src/project-engine.ts              |  93 +++++-
 7 files changed, 771 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7511

Fusion-Task-Lineage: 81b616cf-47e9-4769-b02d-fc7ebd3fcb2f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 12:55:25 -07:00
gsxdsm
82493e0f62 FN-7488: allow source-free task artifacts to complete
Teach fn_task_done to honor explicit source-free task-artifact contracts without weakening ordinary commit requirements.

- Detect PROMPT-declared gitignored .fusion/tasks-only delivery contracts after completed steps.
- Keep zero-commit refusals for mixed tracked source, docs, config, test, or changeset scope.
- Document the completion contract in executor guidance and architecture notes.
- Add regression coverage for allowed source-free artifacts and refused mixed-scope deliveries.
- Add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7488-source-free-completion.md       |   7 ++
 docs/architecture.md                               |   2 +-
 packages/core/src/agent-prompts.ts                 |   6 ++
 .../__tests__/executor-task-done-invariant.test.ts | 120 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |  61 ++++++++---
 5 files changed, 183 insertions(+), 13 deletions(-)

Fusion-Task-Id: FN-7488
Fusion-Task-Lineage: adbf1146-4513-4531-bdd8-ccecbeb42a63
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 10:42:19 -07:00
gsxdsm
af6e671e72 FN-7385: preserve live worktrees with fresh fallback
Preserve active worktree owners by retrying acquisition on a fresh sibling checkout.

- Add executor fallback that detects active cleanup refusals and creates bounded sibling branches in fresh generated worktrees.\n- Cover DB-only, same-task workflow-step, existing-branch, and exhausted-suffix conflict paths with regression tests.\n- Document the live worktree conflict fallback and add a patch changeset for the published CLI package.\n\nFiles changed:\n .../fn-7385-active-worktree-fresh-fallback.md      |   7 +\n docs/architecture.md                               |   1 +\n .../__tests__/executor-worktree-conflict.test.ts   | 103 +++++++++++++-\n .../engine/src/__tests__/executor-worktree.test.ts | 153 ++++++++++++++++++---\n packages/engine/src/executor.ts                    |  90 ++++++++----\n 5 files changed, 312 insertions(+), 42 deletions(-)

Fusion-Task-Id: FN-7385

Fusion-Task-Lineage: 02c31656-1248-49c0-9063-0750cc8e41c6

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 10:55:57 -07:00
gsxdsm
919420e11a FN-7373: enforce active worktree cap
Enforce maxWorktrees at the task-store transition boundary so active execution worktrees cannot exceed the operator cap.

- Reject allocated moves into in-progress when existing active or pending holders already meet maxWorktrees.
- Count in-progress tasks and pending in-progress transitions while excluding the task being moved.
- Cover scheduler and hold-release paths with regression tests and document the hard-cap invariant.
- Add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7373-max-worktrees-cap.md            |  7 ++
 docs/architecture.md                               |  2 +-
 packages/core/src/__tests__/store-movement.test.ts | 80 +++++++++++++++++++++-
 packages/core/src/store.ts                         | 50 ++++++++++++++
 packages/engine/src/__tests__/hold-release.test.ts | 52 ++++++++++++++
 .../__tests__/scheduler-workflow-cutover.test.ts   | 53 ++++++++++++++
 6 files changed, 242 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7373
Fusion-Task-Lineage: be4a9649-f6ae-475f-9395-07433e98de5c
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 10:18:32 -07:00
gsxdsm
6f2b8ab6e5 FN-7244: retry unavailable Plan Review without replanning
Preserve existing task specs when Plan Review retries after reviewer outages.

- Route plan-review-unavailable triage tasks through the Plan Review/finalization path instead of the planner.
- Validate existing PROMPT.md content and fail clearly when it is missing, empty, or invalid.
- Preserve retry status across interrupted triage work and cover retry behavior with engine tests.
- Document the retry lifecycle and add a patch changeset.

Files changed:
 .../fn-7244-plan-review-unavailable-retry.md       |   7 +
 docs/architecture.md                               |   2 +
 docs/workflow-steps.md                             |   2 +
 .../triage-plan-review-unavailable-retry.test.ts   | 251 +++++++++
 packages/engine/src/__tests__/triage.test.ts       | 604 +++++++++++++++++++++
 packages/engine/src/triage.ts                      | 108 +++-
 6 files changed, 945 insertions(+), 29 deletions(-)

Fusion-Task-Id: FN-7244

Fusion-Task-Lineage: 80e790e3-d2b9-4309-beec-3dbf6a03db39

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-29 17:40:00 -07:00
gsxdsm
998a7f2745 fix(FN-7226): make plan review the single pre-execution gate
Fusion-Task-Id: FN-7226
2026-06-29 01:48:27 -07:00
gsxdsm
e963be4088 FN-7220: harden workflow recovery lineage checks
Harden workflow recovery so pause/resume parks and already-merged detection preserve task ownership lineage.

- Reject already-merged recovery candidates with foreign task or lineage trailers before accepting patch-id, tree, or branch-tip matches.
- Recover benign pause/resume abort parks back to todo when the task has no live executor/session state.
- Add real-git and executor regression coverage plus architecture docs and a changeset for recovery behavior.

Files changed:
 .changeset/fn-7220-workflow-recovery-lineage.md    |   7 +
 docs/architecture.md                               |   8 +-
 .../already-merged-detector.real-git.test.ts       |  69 ++++++++
 .../executor-paused-abort-todo-benign.test.ts      | 194 ++++++++++++++++++---
 .../self-healing-already-merged.real-git.test.ts   |  64 ++++++-
 packages/engine/src/already-merged-detector.ts     | 113 +++++++++---
 packages/engine/src/executor.ts                    |  84 +++++++++
 packages/engine/src/self-healing.ts                | 134 ++++++++++++--
 8 files changed, 609 insertions(+), 64 deletions(-)

Fusion-Task-Id: FN-7220

Fusion-Task-Lineage: 186c65bc-fe1a-457a-b90a-abbd73044252

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-28 22:43:02 -07:00
gsxdsm
58a0c1f1d6 FN-7214: make workflow node pause resume re-entrant
Workflow graph pause aborts now re-enter interrupted nodes instead of failing the task.

- Track and abort active workflow graph runners during hard cancel and global pause flows.
- Stamp interrupted workflow nodes with typed engine-pause abort context and surface it through graph run results.
- Re-enter safe todo, in-progress, and auto-mergeable in-review graph nodes with retry bounds and run-audit evidence.
- Add regression coverage and architecture notes for paused node re-entry behavior.

Files changed:
 .changeset/fn-7214-workflow-graph-node-pause-resume.md    |   7 +
 docs/architecture.md                                      |   4 +-
 packages/engine/src/__tests__/executor-paused-abort-todo-benign.test.ts      | 231 ++++++++++++++++++++-
 packages/engine/src/__tests__/workflow-graph-paused-node-resume.test.ts      | 148 +++++++++++++
 packages/engine/src/executor.ts                           | 158 +++++++++++++-
 packages/engine/src/workflow-graph-executor.ts            |  50 ++++-
 packages/engine/src/workflow-graph-task-runner.ts         |  26 ++-
 7 files changed, 614 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-7214
Fusion-Task-Lineage: 1689e3fd-e35f-4e83-8049-aabbab49cecd
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-28 19:42:45 -07:00
gsxdsm
dc54b615d4 FN-7182: pause auto-merge for manual pull requests
Manual pull requests now pause automatic merge processing until human action closes or merges the PR.

- Mark dashboard-created or linked pull requests with manual provenance and preserve it across PR refreshes and merges.
- Exclude tasks with manual open or draft PRs from automatic merge processing while preserving pipeline PR automation.
- Add regression coverage and document the manual PR handoff behavior.

Files changed:
 .changeset/FN-7182-no-auto-merge-with-manual-pr.md |  7 ++
 docs/architecture.md                               |  2 +-
 docs/dashboard-guide.md                            |  1 +
 packages/core/src/__tests__/task-helpers.test.ts   | 49 ++++++++++++-
 packages/core/src/__tests__/task-merge.test.ts     | 60 +++++++++++++++-
 packages/core/src/index.ts                         |  2 +-
 packages/core/src/task-helpers.ts                  | 13 ++++
 packages/core/src/task-merge.ts                    | 10 ++-
 packages/core/src/types.ts                         |  6 ++
 .../dashboard/src/__tests__/routes-auth.test.ts    | 80 ++++++++++++++++++++++
 .../dashboard/src/__tests__/routes-github.test.ts  | 45 +++++++++++-
 .../dashboard/src/routes/register-git-github.ts    | 20 +++++-
 12 files changed, 285 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-7182

Fusion-Task-Lineage: c415a9dc-43c1-4609-a032-367991e949a1

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-28 01:43:08 -07:00
gsxdsm
9f45f108e5 FN-7174: reset lost steps before stuck requeue cleanup
Preserve durable stuck-requeue progress while preventing retries from skipping deleted uncommitted work.

- Reconcile completed and in-progress steps before stuck cleanup removes executor worktrees.
- Reset step progress when a branch has no unique commits or git proof fails before checkout deletion.
- Cover normal, loop-timeout, and force stuck-requeue paths with regression tests and documentation.

Files changed:
 .changeset/fn-7174-stuck-requeue-progress.md       |   7 +
 docs/architecture.md                               |   2 +-
 packages/core/src/types.ts                         |   9 +-
 ...xecutor-stuck-requeue-preserve-progress.test.ts | 282 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |  99 ++++----
 5 files changed, 349 insertions(+), 50 deletions(-)

Fusion-Task-Id: FN-7174

Fusion-Task-Lineage: 3b8b09e7-fceb-4b3d-af80-993a8842a51a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-28 00:08:53 -07:00
gsxdsm
e42679daff FN-7173: preserve stuck triage drafts on requeue
Stuck triage retries now continue from saved planning drafts instead of restarting.

- Detect non-empty PROMPT.md drafts or saved plan task documents after stuck-detector aborts.
- Requeue draft-backed stuck triage runs as replans with explicit resume feedback and bounded retry escalation.
- Cover prompt-vs-plan recovery, cold retries, approval recovery, and exhaustion behavior in engine tests.
- Document the stuck-triage preservation invariant and add a patch changeset.

Files changed:
 ...-7173-preserve-triage-draft-on-stuck-requeue.md |   7 +
 docs/architecture.md                               |   6 +-
 .../triage-stuck-requeue-preserve-draft.test.ts    | 348 +++++++++++++++++++++
 packages/engine/src/__tests__/triage.test.ts       |   2 +-
 packages/engine/src/triage.ts                      | 153 ++++++++-
 5 files changed, 499 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-7173
Fusion-Task-Lineage: 8e59b025-92cc-4902-bf88-b203b65c2c7d
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-27 23:18:28 -07:00
gsxdsm
d7a02c4d5b FN-7151: free scoped project concurrency slots
Free stopped or paused project engines' leaked slots without disturbing other projects.

- Add scoped semaphore accounting around the shared global agent pool.
- Return residual per-project slots after runtime stop drains aborted agents.
- Keep idle leak reconciliation scoped to the owning project so active projects retain their slots.
- Cover scoped release, reconciliation, project pause, and in-process runtime behavior with tests.

Files changed:
 .../fn-7151-free-concurrency-slots-on-stop.md      |   7 ++
 docs/architecture.md                               |   2 +-
 packages/engine/src/__tests__/concurrency.test.ts  | 126 +++++++++++++++++++++
 .../src/__tests__/project-engine-manager.test.ts   |  60 ++++++++++
 packages/engine/src/concurrency.ts                 | 123 +++++++++++++++++++-
 packages/engine/src/project-engine.ts              |   2 +-
 .../runtimes/__tests__/in-process-runtime.test.ts  |  51 +++++++++
 packages/engine/src/runtimes/in-process-runtime.ts |  22 +++-
 8 files changed, 385 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-7151

Fusion-Task-Lineage: e59e5e0c-67e8-4f80-a6b9-1ea4febaeb97

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-27 20:55:59 -07:00
gsxdsm
8b124960b8 FN-7154: prevent duplicate automation schedule runs
Add an atomic schedule claim so concurrent automation pollers execute each due window only once.

- Add AutomationStore.claimDueSchedule to CAS-advance nextRunAt before execution.
- Gate CronRunner execution on the claim across project, global, and all-scope pollers.
- Cover single-store, shared SQLite, legacy command, step, and in-process intercept deduplication paths.
- Document the claim-then-run automation invariant.

Files changed:
 docs/architecture.md                               |   1 +
 .../core/src/__tests__/automation-store.test.ts    |  77 +++++++++++++++
 packages/core/src/automation-store.ts              |  33 +++++++
 packages/engine/src/__tests__/cron-runner.test.ts  | 110 +++++++++++++++++++++
 packages/engine/src/cron-runner.ts                 |  18 +++-
 5 files changed, 237 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7154

Fusion-Task-Lineage: 490ba154-9dd8-4e92-bacb-24b7184cb6f8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-27 20:09:52 -07:00
gsxdsm
6f46fa17dd FN-7138: show task column context in agent assignments
Agent Current Task output now includes linked task column context to distinguish active execution from parked or stale links.

- Add shared Current Task formatting for active, terminal, and unresolved task links.
- Show linked task columns in engine and CLI agent list/show surfaces.
- Cover parked, active, terminal, and missing task-link display cases with tests.
- Document the durable agent task-link invariant and release the CLI fix.

Files changed:
 .changeset/fn-7138-agent-current-task-context.md   |  7 ++++
 docs/agents.md                                     |  1 +
 docs/architecture.md                               |  2 +-
 packages/cli/src/__tests__/extension.test.ts       | 44 ++++++++++++++++++++++
 packages/cli/src/extension.ts                      | 35 +++++++++++++++--
 packages/core/src/agent-store.ts                   | 30 +++++++++++++++
 packages/core/src/index.ts                         |  2 +-
 .../src/__tests__/agent-tools-delegation.test.ts   | 44 +++++++++++++++++++++-
 packages/engine/src/agent-tools.ts                 | 15 ++++++--
 9 files changed, 169 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-7138
Fusion-Task-Lineage: 0ea97b4c-d4f8-4289-a5b6-e5c51b47b768
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-27 16:16:25 -07:00
gsxdsm
5608bf555f FN-7083: derive project in-flight counts from live tasks
Derive CLI project in-flight agent displays from live in-progress task counts instead of persisted health bookkeeping.

- Add shared CLI display health handling for project list and show output.
- Cover stale, missing, unreadable, table, and JSON project health cases in CLI tests.
- Clarify central health and concurrency fields as persisted bookkeeping in docs and types.
- Add a patch changeset for the published CLI behavior fix.

Files changed:
 .changeset/fn-7083-cli-inflight-live-count.md      |   7 +
 docs/architecture.md                               |   1 +
 docs/multi-project.md                              |   4 +-
 .../cli/src/commands/__tests__/project.test.ts     | 172 ++++++++++++++++++++-
 packages/cli/src/commands/project.ts               |  60 ++++---
 packages/cli/src/project-resolver.ts               |   4 +
 packages/core/src/types.ts                         |  12 +-
 7 files changed, 235 insertions(+), 25 deletions(-)

Fusion-Task-Id: FN-7083

Fusion-Task-Lineage: 2b57cb35-383f-443b-8bf3-3fc3c7a1ad43

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-26 18:35:54 -07:00
gsxdsm
0440ae4bb9 FN-7074: make task ID reservation commits atomic
Task creation now commits or rolls back distributed task ID reservations with the task-row transaction.

- Add transaction-participating reservation commit and rollback helpers.
- Wire create, duplicate, and refinement task paths to commit reservations inside task insertion.
- Record rollback audit events and preserve burned reservation rows after failed creates.
- Cover atomicity, rollback, and allocator behavior with reservation-focused tests and docs.

Files changed:
 .changeset/fn-7074-reservation-atomicity.md        |   7 +
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |   7 +-
 docs/storage.md                                    |   4 +-
 .../core/src/__tests__/distributed-task-id.test.ts |  25 ++-
 .../__tests__/store-reservation-atomicity.test.ts  | 224 +++++++++++++++++++++
 packages/core/src/distributed-task-id.ts           | 208 +++++++++++++------
 packages/core/src/store.ts                         |  93 +++++++--
 8 files changed, 479 insertions(+), 90 deletions(-)

Fusion-Task-Id: FN-7074

Fusion-Task-Lineage: 464a98cf-e903-4257-93ac-424c7129412b
2026-06-26 14:55:01 -07:00