## Summary
Windows installs with slow native dependencies now get five minutes to
finish, and a real timeout is reported as an actionable terminal retry
instead of a wall of preceding npm deprecation warnings. Registry
`ETIMEDOUT` errors keep their network diagnosis, including after the
legacy-bin `--force` retry.
Compound Engineering personas are now included in the published CLI
bundle, with complete source-to-staged coverage for all persona
definitions and a clear startup error if the bundled assets are missing
or empty.
The PostgreSQL statement visible in the report was validated by the
existing real-Postgres schema reapply test. Its actual `caused by`
detail was truncated, so this PR deliberately makes no speculative
database change.
## Validation
- Dashboard updater tests: 22 passed
- CLI updater tests: 16 passed
- CE persona installer tests: 7 passed
- Published bundle persona assertion: passed against every source
persona
- CLI and CE plugin typechecks: passed
- Changed production/config lint and strict changeset validation: passed
- Real PostgreSQL schema reapply integration test: passed
---
[](https://github.com/EveryInc/compound-engineering-plugin)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Windows CLI and dashboard updates now allow up to five minutes for
installation and restore Compound Engineering agent personas during npm
installs.
* Update failures now surface clearer, terminal timeout guidance (while
preserving specific network connection diagnostics) and avoid misleading
“deprecated”/generic timeout text.
* Persona assets are reliably included in plugin builds and bunded
persona installation now errors clearly when definitions are missing or
empty.
* **Tests**
* Expanded update and bundling coverage for the new 5-minute timeout and
error-handling scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
Repeated review and executor sessions could replay a follow-up creation
step and produce another live task whenever the wording changed. In the
incident behind this fix, 21 creation calls for three intended
follow-ups left 18 duplicate tasks.
Agent-created tasks now retain their parent and agent provenance across
step sessions, heartbeats, and the published CLI surface. Same-parent
paraphrases converge on the existing task through a serialized pre-check
and a database-backed intent claim, while distinct sibling actions
remain separate. Candidate lookup is parent-indexed, uniqueness failures
abort creation, and canonical reuse no longer emits misleading creation
audit events or workflow claims.
Related: FN-8277
## Validation
- Core duplicate guard and intake: 24 tests passed
- Engine task creation and heartbeat: 154 tests passed
- CLI extension: 66 tests passed, 95 skipped
- Core, engine, and CLI typechecks passed
- Core, engine, and CLI builds passed before rebase; the rebase was
conflict-free
- Scoped lint, strict changeset validation, and diff checks passed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Prevented retried agent steps from creating duplicate follow-up tasks.
* Improved parent-scoped deduplication for paraphrased follow-ups while
preserving distinct sibling actions.
* Preserved parent-task and agent context for created follow-ups.
* Concurrent follow-up requests are now serialized/deduplicated so
duplicates link to the existing task instead of showing as newly
created.
* Updated agent follow-up/heartbeat activity so reused follow-ups no
longer appear in run results as fresh creations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Repair CLI test mocks and retry-reset expectations for the current store contracts.
- Add the backend store factory to the experiment-finalize mock.
- Provide global settings directory access in backup test stores.
- Assert all manual retry reset fields in task command tests.
Files changed:
.../extension-experiment-finalize.test.ts | 13 ++++++++++
.../commands/__tests__/backup-lock-retry.test.ts | 2 ++
packages/cli/src/commands/__tests__/backup.test.ts | 17 ++++++++++++-
packages/cli/src/commands/__tests__/task.test.ts | 28 +++++++++++++++++-----
4 files changed, 53 insertions(+), 7 deletions(-)
Fusion-Task-Id: FN-8222
Fusion-Task-Lineage: 033ce6a6-c699-409c-a59e-2d1f5e041cfc
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Restore the CLI package configuration test to the active test lane with current build expectations.
- Allowlist WhatsApp plugin-only tsup externals as non-runtime CLI dependencies.
- Assert the full workspace build command in the verification contract.
- Remove the stale package-config test quarantine.
Files changed:
packages/cli/src/__tests__/package-config.test.ts | 12 +++++++++++-
packages/cli/vitest.config.ts | 9 ++++-----
2 files changed, 15 insertions(+), 6 deletions(-)
Fusion-Task-Id: FN-8210
Fusion-Task-Lineage: aa29d866-430f-4097-affa-a89d107474b2
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Restore PostgreSQL-backed collision coverage for the built task-delegation extension.
- Seed an occupied task ID through the shared PostgreSQL TaskStore.
- Override the allocator once to exercise the real unique-violation error path.
- Assert that fn_delegate_task returns the structured task-ID collision error.
Files changed:
.../src/__tests__/extension-integration.test.ts | 53 +++++++++++++---------
1 file changed, 32 insertions(+), 21 deletions(-)
Fusion-Task-Id: FN-8100
Fusion-Task-Lineage: d26b825e-2abd-482e-899e-51c0db753176
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Restore the isolated built-core barrel regression guard to the default CLI test lane.
- Hoist recompilation and PostgreSQL fixture setup outside timed test bodies.
- Inject the fixture store into the dynamic extension and retain text-budget assertions.
- Skip cleanly per test when a transitive dist artifact is unavailable.
- Remove the matching CLI quarantine exclusion and ledger entry.
Files changed:
.../src/__tests__/extension-dist-barrel.test.ts | 234 +++++++++++----------
packages/cli/vitest.config.ts | 8 +-
scripts/lib/test-quarantine.json | 5 -
3 files changed, 121 insertions(+), 126 deletions(-)
Fusion-Task-Id: FN-8093
Fusion-Task-Lineage: 352b3675-0579-43bc-acd9-6a11919ed646
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
## Summary
Adds a bundled **Quality** plugin (`fusion-plugin-quality`) that makes
task QA easier and more visual:
- **Task QA tab** (action-first): preview/test server for the task
worktree, allowlisted test runs, report viewer, screenshots CTA,
suggested test cases, CI handoff
- **Quality hub** (left sidebar): project-wide run history and preset
launches
- Host **task-detail slot context** (`taskId`, worktree, `projectId`) so
plugin tabs can scope correctly
- `superviseSpawn` re-exported on the plugin packaging shim for
published plugins
- Plan: `docs/plans/2026-07-14-001-feat-quality-plugin-plan.md`
## Design constraints
- Does **not** replace the merge gate — advisory orchestration only
- Composes Dev Server process patterns and artifact registry (no second
browser stack)
- Never free-form shell; never port 4040
- Full-suite requires explicit confirm
## Test plan
- [x] `pnpm --filter @fusion-plugin-examples/quality test` (15 tests)
- [x] PluginSlot unit tests still pass
- [ ] Enable Quality plugin in dashboard Settings → Built-in Plugins
- [ ] Open Task Detail → **QA** tab with a worktree; start preview, run
verify:fast, generate suggestions
- [ ] Open left sidebar **Quality** hub and list runs
- [ ] Confirm merge gate / PR checks unchanged
## Residual / follow-up (same plan, later units)
- Deeper hub CI (host route)
- Full browser-verification toggle UX + agent QA sessions (U7/U9/U10)
- Richer screenshots gallery wiring to live artifacts API
- Test plans CRUD polish
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added the Quality plugin with a project Quality hub and task-focused
QA tab.
* Added test runs, reports, preview server controls, suggested test
cases, and run history.
* Added configurable test presets, cancellation, status tracking, and
safe command execution.
* Added experimental-feature controls for enabling Quality
functionality.
* Bundled Quality with the CLI and made it available through the plugin
manager.
* **Documentation**
* Added Quality plugin guidance, terminology, configuration details, and
implementation planning documentation.
* **Bug Fixes**
* Improved process supervision so command failures and shutdown timers
are handled safely.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
Speeds up **time-to-HTTP-ready** for `fn dashboard` and `fn serve` after
the PostgreSQL cutover without reintroducing the historical 3s
cwd-engine race that degraded webhooks.
- **Dashboard store share (serve parity):** inject the factory-booted
`TaskStore` as `externalTaskStore` so cwd `ensureEngine` does not open a
second pool; share only when store root matches project working
directory (multi-project safe).
- **Serve multi-project:** stop awaiting `startAll()` before listen;
await only the primary engine; background the rest + reconciliation.
- **Defer non-route-critical engine work:** ordered OAuth (refresh →
monitor), automation schedule syncs, and auto-merge **enqueue** after
the engine handle is returnable.
- **Critical-path merge status clear:** still clear stale
`merging`/`merging-pr` before ready so manual merge is not blocked after
crash.
- **Serve `--paused`:** apply `enginePaused` before
`ensureEngine`/`startAll` (dashboard ordering).
- **Stop safety:** generation counter so deferred tails cannot resume
after `stop()` clears `shuttingDown`.
- **Phase timing:** shared `phaseTime` helper, factory substep logs,
serve time-to-listen.
Plan: `docs/plans/2026-07-14-001-feat-faster-startup-plan.md`
## Test plan
- [x] `packages/engine` — `project-engine-manager.test.ts` (path-matched
external store)
- [x] `packages/engine` — `project-engine-deferred-startup.test.ts`
(status clear, OAuth order, stop generation)
- [x] `packages/cli` — `startup-phase.test.ts`
- [x] `packages/cli` — `serve.test.ts` (60 tests, including `--paused`)
- [ ] Local: warm `fn dashboard` / `fn serve` and compare `startup phase
*` / `time-to-listen` logs
- [ ] `pnpm smoke:boot` (real serve `/api/health` on ephemeral port)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Performance**
* Improved dashboard and serve startup times, including faster
time-to-listen and time-to-ready.
* Moved non-essential background initialization off the critical startup
path.
* Parallelized dashboard service initialization where possible.
* **Reliability**
* Improved multi-project startup handling and project selection.
* Prevented cross-project task-store sharing.
* Added safer shutdown behavior for partially completed startup.
* **Diagnostics**
* Added startup phase timing logs to help identify performance
bottlenecks.
* **Tests**
* Expanded coverage for deferred startup, shutdown, project isolation,
and startup timing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## 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 -->
Code review follow-up for the dual-boot hang fixes:
- Outer tool wrap aborts a linked AbortController on timeout so nested work (npx) stops
- fn_skills_install uses SIGTERM then delayed SIGKILL instead of immediate double-kill
- clearHostTaskStores only drops external entries (does not wipe unrelated CLI boot state)
- Align import/browse schema max with the 50-item hard clamp
- Tests for host-store cache injection and timeout-driven signal abort
Kill the dual-boot FN-7956 class hang for in-process agent tools:
- setHostTaskStore/clearHostTaskStores inject the live dashboard/serve/daemon store
- Prefer host-injected store over createTaskStoreForBackend; race-safe with external overwrite
- fn_skills_install kills npx on abort/timeout so orphan install processes cannot outlive the turn
- Raise budgets for task plan, experiment finalize, and mission backfill
- Hard-cap import/browse batch size at 50 (GitHub + GitLab)
Host-extension research tools dual-booted a second TaskStore and could wedge
agent turns via wait_for_completion polling (same hang class as FN-7956).
Leave research available only when the engine injects createResearchTools under
experimentalFeatures.researchView. Operators still use fn research CLI and the
dashboard Research view. Regen fusion skill docs from extension.ts.
Address review findings on the FN-7956 hang fix:
- Per-tool outer timeouts so fn_research_run(wait_for_completion) is not clipped by a flat 60s budget
- Longer budgets for skills install, import/browse, and web_fetch
- Boot-failure cooldown + orphan-boot log when store boot times out
- Log timeout/abort/errors from the extension wrap; clearer host-extension skip reason
- Tests for budgets, research wait, and sessionPurpose forwarding
AI merge review could park forever when the host fusion extension loaded
fn_task_show and booted a second TaskStore without a tool timeout (FN-7956).
- Skip host @runfusion/fusion extensions for sessionPurpose "merger"
- Forward sessionPurpose into createFnAgent for that policy
- Coalesce + 30s-bound extension TaskStore boots; ALS-propagate AbortSignal
- Wrap every extension registerTool execute with 60s timeout/abort fail-closed
- Unit tests for merger host-extension skip and tool timeout helpers
## Summary
CLI commands, daemon/dashboard startup, packaged desktop startup, and
live-data maintenance scripts now share the mandatory PostgreSQL
lifecycle. Operators no longer risk a command silently reading or
writing a disconnected SQLite shadow when PostgreSQL setup fails.
## Design decisions
- Every startup owner retains and awaits its PostgreSQL shutdown
callback, including partial-startup failure paths.
- CLI project context and lock-retry flows resolve through asynchronous
project stores.
- Maintenance scripts use the shared backend helper; explicit database
migration/inspection remains the only CLI surface allowed to read legacy
SQLite sources.
## Validation
- CLI and Desktop typechecks pass on the stacked branch.
- `pnpm test:gate` passes all 478 gate tests.
- This PR changes 54 files.
## Stack
- Depends on #2109, which depends on #2108.
- Bundled plugins and docs/release follow in later PRs.
Related: #2105
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* PostgreSQL is now the authoritative store for structured project and
task metadata.
* Projects can be recognized and initialized using
`.fusion/project.json`, without creating a legacy SQLite database.
* CLI commands now retry transient PostgreSQL contention errors.
* **Bug Fixes**
* Improved cleanup when commands complete, fail, or run in the
background, preventing lingering resources.
* Improved desktop, server, and session shutdown reliability.
* **Documentation**
* Updated storage and standalone binary guidance to reflect PostgreSQL
and legacy SQLite compatibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
# Migrate storage from SQLite to PostgreSQL — full dashboard cutover
Migrates Fusion's storage layer to the embedded PostgreSQL
`AsyncDataLayer` (the default backend) and **completes the
satellite-store + feature cutover** so every dashboard and Command
Center surface works in PG mode.
## Status — every surface works in embedded-PG mode
Verified live against a running embedded-Postgres dashboard (all
**200**, zero 5xx) and gate-tested (**23 files / 99 tests** on embedded
PG, plus engine-core 294 and ci-shape 63 in the blocking merge gate;
core/engine/cli/dashboard typecheck clean).
| Area | Surfaces | State |
|---|---|---|
| Satellite stores | workflows, todos, insights, research, missions,
goals, mailbox | ✅ |
| Views | artifacts, documents, evals | ✅ |
| Command Center | activity, productivity, team, tokens, tools,
**workflows**, **github**, **signals**, **plugin-activations**, **live**
(all 10) | ✅ |
| Run execution | insight generation, research run execution | ✅
(store-path; AI step needs a provider) |
| Live updates | SSE push for mission/research/insight events | ✅ |
| Workflow editing | create / update / delete / select (+ id counter) |
✅ |
| Engine | mission autopilot, incident-signal ingestion, regression
storm-guard, agent wake-on-message | ✅ |
| Core | tasks, agents, secrets, automations, memory, chat, usage, PRs,
git | ✅ |
## Approach
Each satellite store gets an `Async<Store>` wrapper exposing the sync
store's method names over the existing `async-*-store.ts` helpers;
`get<Store>Store()` returns a `Sync | Async` union; consumers `await`
(harmless on sync), and engine/CLI paths that can't convert use
`instanceof Sync` graceful fallback. Analytics aggregators branch on
`"ping" in dbOrLayer` to run schema-qualified raw SQL over `project.*`
(snake_case) in PG. Executors/orchestrators/autopilot are
await-converted to drive the union store; the async store wrappers
extend `EventEmitter` so SSE live-push fires in both backends.
Not-yet-ported capabilities degrade gracefully (never 500) and are
individually called out in commits.
## Sync with main
The branch is kept continuously merged with `main` (currently through
FN-7845, 2026-07-12); the earlier "final rebase deferred" note no longer
applies. Use **Create a merge commit** (or squash) to land it — GitHub's
rebase-merge cannot replay a merge-maintained branch.
## Residual Review Findings
Multi-agent code review of the PostgreSQL satellite-store ports (U1–U5)
applied 3 safe fixes (see `fix(review): apply autofix feedback`). The
following are **real but gated** — recorded here as follow-up work
rather than auto-applied. All are SQLite→PostgreSQL
**concurrency/atomicity regressions**: the sync stores were immune only
by SQLite's single-writer, single-threaded-handler execution; the async
ports open multi-await read-modify-write windows. **Reachability is low
today** because the execution engines that generate concurrent same-run
mutations (insight run executor, research orchestrator/dispatcher) are
`instanceof`-gated to sync mode in PG. No process-crash class survived
(all engine fallbacks correctly guard the sync store).
- **[P1] Research `appendResearchEvent` dual-write is non-atomic**
(`packages/core/src/async-research-store.ts`, corroborated: adversarial
+ reliability). The `research_run_events` insert (own transaction) and
the `run.events` jsonb update are separate writes — a crash between
them, or two concurrent appends, splits the table count from the jsonb
array. **Fix:** perform the seq-insert and the jsonb update in one
`layer.transactionImmediate`.
- **[P1] Research run terminal-reversion via stale full-row persist**
(`async-research-store.ts` `persistResearchRun`/`updateResearchStatus`).
Concurrent `PATCH /runs/:id/status` + `POST /runs/:id/events` can revert
a terminal run to `running` by overwriting the whole row, bypassing the
transition guard. **Fix:** scoped column `UPDATE`s with a `WHERE status
…` guard, or optimistic version column.
- **[P2] `updateResearchRun`/`updateInsightRun` read-then-write TOCTOU**
— concurrent PATCHes last-writer-wins on the lifecycle merge. **Fix:**
`SELECT … FOR UPDATE` / enclosing transaction.
- **[P2] `upsertRun`/`createRunOrThrowConflict` check-then-create race**
(`async-insight-store.ts`) — two callers can each create an "active"
run. **Fix:** partial unique index on `(projectId, trigger) WHERE status
IN ('pending','running')`.
- **[P3] `createResearchRetryRun` return-value divergence** — sync
returns the pre-update `queued` snapshot; async returns the reloaded
`retry_waiting` run (persisted state is identical). Pick one side for
cross-backend parity.
- **[P2/perf] Mission `getMissionWithHierarchy`/`getMissionHealth` N+1
fan-out** — O(milestones×slices) sequential round-trips hold one pool
slot per request; can starve the pool for large hierarchies. **Fix:**
batched/joined reads.
- **Testing gaps:** no PG-mode concurrency tests (interleaved
status/event mutations), no sync↔async parity assertion for the
lifecycle-error codes, and no mission status/health rollup parity test
vs the sync `MissionStore`.
~~Out of scope (deferred): AI run *execution* (insight/research) +
mission autopilot + live SSE mission events remain sync-gated/degraded
in PG mode.~~ **Since ported** — insight/research run execution, mission
autopilot, and SSE live push all run on the async layer now, which also
makes the concurrency findings above genuinely reachable; they remain
open follow-ups.
---
## Update — 2026-07-12: production-readiness hardening & live acceptance
Everything below landed on this branch since the description above was
written:
**Production blockers from review — fixed**
- `recoverStaleTransitionPending` ported to the async layer (backend
moves write + clear the crash-safe marker; startup/maintenance sweeps no
longer throw).
- Lost-update class fixed: `atomicWriteTaskJson`/`WithAudit` write
changed columns only (full-row upserts silently resurrected stale fields
across concurrent store instances — the "task stuck unplanned forever"
bug).
- First-boot **auto-migration**: booting the PG backend over a project
with a legacy `fusion.db` migrates it automatically (loud failure,
SQLite kept as backup), and the dashboard shows a one-time **"your data
was migrated" banner** with the backup paths and a Need-help Discord
link.
- `pg_dump`/`pg_restore` discovered from common install locations for
embedded-mode backups.
- The PG suite is part of the blocking merge gate (`test:pg-gate`).
**Multi-project isolation (PR #2007, merged into this branch)**
- `project_id` partition key on tasks / archived tasks / config,
`taskProjectScope` threaded through every scan/claim/count, per-project
config rows, layer bound to the project at startup.
- Review P1 follow-up: the shared cold-storage `archive.archived_tasks`
table is also partitioned and all archived-board reads/counts/searches
are scoped.
- Schema drift self-heal generalized to schema-qualified columns so
existing databases upgrade in place.
**Other changes**
- Node settings sync **removed** in PG mode (409
`settings-sync-disabled-postgres`) — nodes share state by connecting to
the same database; auth sync kept (per-machine file).
- Perf (review findings): `listTasks` pushes column filter + ORDER BY +
LIMIT/OFFSET into SQL; `getConversation` capped to the most recent 200
messages.
- Fixed a false "operator action required" pause-abort log fired on
every successfully auto-merged task.
**Live acceptance — PASSED (2026-07-12)**
A sandboxed instance (isolated HOME, embedded PG, real Opus executor)
ran a task through the complete cycle: create → triage (AI spec) →
execute → in-review → AI squash-merge landed on the project's `main` →
done. A write+read sweep of every data surface (settings, comments,
documents, attachments + artifact bridge + artifact edit, chat with real
generation, goals, missions, agent mail, secrets, workflows, memory, CC
analytics) was green on embedded PG.
**Known remaining work**
- The per-project `config` PK re-key has no upgrade path for
pre-isolation embedded-PG databases (needs a real `DROP
CONSTRAINT`/re-key migration; fresh databases are fine).
- `pg_dump`/`pg_restore` binaries are not yet bundled in release
artifacts (PATH/common-location discovery only).
- The satellite-store concurrency findings listed above.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Phil Larson <hello@phillarson.xyz>
Co-authored-by: fusion-merge <fusion-merge@local>
## Summary
Fixes shard 3 failures from runs 29258546612 + 29259574946 (FN-7936
drift).
## Fixes
### `package-config.test.ts` — stale TRANSITIVE_EXTERNALS entry
FN-7936 aliased `@fusion/core` to a runtime shim in bundled plugin
outputs; it's no longer a tsup external. Removed the stale allowlist
entry.
### `bundle-output.test.ts` — stale dashboard client hash ENOENT
**Root cause:** Two test files (`bundle-output.test.ts` +
`extension-integration.test.ts`) call
`buildCliWithRealDashboardAssets()` which triggers concurrent vite/tsup
builds. Vitest runs them in parallel (`pool: "forks"`, `fileParallelism:
true`). Without coordination, two builds clean and write `dist/client`
simultaneously, causing `ENOENT` on content-hashed chunk files.
**Fix (3 parts):**
1. **`workspace-tools.ts buildDashboardClient`** — `rm dist/client`
before vite build. Prevents stale content-hash references from previous
builds.
2. **`bundle-output-helpers.ts`** — atomic `mkdirSync` file lock around
`buildCliWithRealDashboardAssets()`. Winner builds; losers poll with
`Atomics.wait`, then re-check `hasBuiltDashboardAssets()`. On timeout,
**throws** (never builds without owning the lock).
3. Lock uses `Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0,
0, 500)` for sync sleep — no child process spawning.
## Verification
- Gate: exit 0 ✅
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved dashboard asset builds by removing stale files before
rebuilding.
* Prevented concurrent builds from producing incomplete or corrupted
dashboard assets.
* Added safeguards to detect stalled asset builds and fail with clearer
errors.
* **Tests**
* Updated package validation checks to reflect current runtime bundling
behavior.
* Improved reliability of CLI build-related test execution.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fix bundled example plugins (dependency-graph, grok-runtime, roadmap, acp-runtime, compound-engineering) crashing on enable with "Cannot find package '@fusion/core'" by aliasing the private import to a self-contained runtime shim during CLI bundling.
- packages/cli/tsup.config.ts: drop @fusion/core from bundlePluginEntry's external list and alias it to the existing pluginSdkCoreRuntimeShim so bundled.js no longer references the private workspace package at runtime
- packages/cli/src/__tests__/bundle-output.test.ts: add a regression test asserting every staged bundled plugin's bundled.js contains no bare @fusion/core import/reference
- docs/PLUGIN_AUTHORING.md: document that bundled.js outputs must be self-contained and must not leak private @fusion/* workspace imports
- .changeset/fn-7936-bundled-plugin-fusion-core-external.md: add a patch changeset for @runfusion/fusion describing the fix
Files changed:
.changeset/fn-7936-bundled-plugin-fusion-core-external.md | 7 +++++
docs/PLUGIN_AUTHORING.md | 3 +++
packages/cli/src/__tests__/bundle-output.test.ts | 30 ++++++++++++++++++++++
packages/cli/tsup.config.ts | 9 +++++--
4 files changed, 47 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7936
Fusion-Task-Lineage: a8a391b2-9441-4a7c-92bc-f1675e1a8a0d
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
## Summary
Fixes ALL failing shards from the latest full-suite run (29225946428)
AND adds a structural gate check to prevent the recurring mock-export
drift pattern that has caused every full-suite failure across rounds
1–9.
## What broke (run 29225946428, commit 504b0f8b0)
| Shard | Root cause | Tests fixed |
|---|---|---|
| **3 (CLI)** | `workflowValidateParams` (FN-7911) missing from
`@fusion/engine` mock | 8 files |
| **3 (CLI)** | `skill-sync.test.ts` — `fn_workflow_validate` missing
from engine-tools.md | 1 file |
| **4 (dashboard)** | 6 chat default settings keys missing from
description allowlist | 1 file |
| **1+2 (engine)** | `additionalSkillPaths` missing from
`buildSessionSkillContext` mocks (FN-1510/1511) | 10 tests |
| **1+2 (engine)** | heartbeat FN-7878 changed paused→error for generic
run failures | 1 test |
| **1+2 (engine)** | executor `updateTask` exact-match →
`objectContaining` (new fields) | 2 tests |
| **1+2 (engine)** | `connectMcpSessionTools` mock missing for pi.test
MCP forwarding | 1 test |
## Structural fix — `scripts/check-mock-completeness.mjs` (the "fix for
good")
**New gate check** added to `pnpm test:gate`. Statically validates every
hardcoded `vi.mock("@fusion/dashboard")` and `vi.mock("@fusion/engine")`
factory covers all named imports the source file uses. Runs in <0.2s, no
module evaluation.
**How it works:**
1. Extracts named exports from each barrel
(`packages/dashboard/src/index.ts`, `packages/engine/src/index.ts`)
2. For each test file with a hardcoded `vi.mock` factory (no
`importOriginal`/`importActual` spread):
- Resolves source files the test covers (static + dynamic imports,
convention mapping)
- Extracts what those source files named-import from the barrel
- Resolves spread helpers (e.g. `...workflowAuthoringEngineMock`) by
reading the helper's exported keys
- Reports any barrel exports that are named-imported by source but
absent from the mock
**Why this fixes the recurring pattern:** Every round 1–9 failure was a
new barrel export imported by source but missing from a test mock. This
check catches it at gate time, before merge — not after the full-suite
fails on main.
Also completed all 15 latent mock gaps the guard found on first run (9
dashboard + 6 engine), including expanding the centralized
`workflowAuthoringEngineMock` helper with all `extension.ts` named
imports.
## Verification
- Gate (with new check): exit 0 ✅
- CLI: 355/355 passed ✅
- Engine (6 fixed files): 250/250 passed ✅
- i18n + settings: verified ✅
- Mock completeness guard: ✅ (0 issues)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Documented a new non-destructive workflow validation tool that
performs a dry-run and returns typed validation errors.
* **Tests**
* Updated and strengthened CLI, dashboard, extension, and engine tests
with more accurate mock exports and more resilient assertions.
* Adjusted expectations for session/heartbeat and retry-related
behaviors.
* **Chores**
* Added an automated mock-completeness gate and integrated it into the
test quality gate to keep mocks aligned with available platform exports.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
**Structural fix** for the recurring full-suite failure pattern where a
new `@fusion/dashboard` barrel export is imported by CLI source code but
missing from the hardcoded `vi.mock("@fusion/dashboard")` factory in CLI
tests.
## What's new
### Gate check script:
`scripts/check-cli-dashboard-mock-completeness.mjs`
Added to the merge gate (`pnpm test:gate`). Statically validates that
every hardcoded `vi.mock("@fusion/dashboard")` factory in CLI tests
includes all `@fusion/dashboard` exports that the corresponding source
files import.
- Pure static analysis (regex + depth-aware brace tracking) — no module
evaluation, <0.1s
- Handles named imports (`import { foo } from "@fusion/dashboard"`) AND
namespace imports (`import * as dashboard from "@fusion/dashboard"` →
scans `dashboard.X` usages)
- Filters against the real barrel exports to avoid false positives from
typos
- Resolves test→source mapping by parsing static/dynamic imports in the
test file (not just naming convention)
**Result:** the next time someone adds `export { newFunc } from
"./mod.js"` to `dashboard/src/index.ts` and `cli/src/commands/daemon.ts`
imports it, the gate catches the missing mock before merge instead of
the full-suite failing on main.
### Completed all 9 incomplete CLI dashboard mocks
Added the missing exports identified by the check:
| File | Missing exports added |
|---|---|
| `daemon.test.ts` | `registerGithubTrackingHook` |
| `serve.test.ts` | `registerGithubTrackingHook` |
| `dashboard.test.ts` | `AttachTicketStore`, `CliInputAttributionLog`,
`CliConfirmAdvanceRegistry`, `CliRelaunchRegistry`,
`registerGithubTrackingHook` |
| `task.test.ts` | `registerGithubTrackingHook`, `GitLabClient`,
`resolveGitlabAuth`, `buildGitLabTaskProvenance`,
`isGitLabAlreadyImported`, `buildGitLabTaskDescription` |
| `extension-*.test.ts` (×4) | `GitLabClient`, `resolveGitlabAuth`,
`buildGitLabTaskProvenance`, `isGitLabAlreadyImported`,
`buildGitLabTaskDescription` |
| `task-command-github-import-tracking.test.ts` | Same GitLab exports |
These were latent issues — the mocks were incomplete but tests passed
because the missing exports weren't called during test execution. Any
test change that exercises those code paths would have broken.
## Why not `importActual` spread?
Tried converting daemon.test.ts to `vi.mock("@fusion/dashboard", async
(importOriginal) => { ... })` — fails because the barrel's `export *
from "./plugins/index.js"` transitively imports
`@agentclientprotocol/sdk` which isn't available at test evaluation
time. The static check approach avoids this entirely.
## Verification
- `pnpm test:gate`: exit 0 (includes new check)
- `pnpm lint`: exit 0
- CLI tests: daemon 21/21, serve 58/58, dashboard 91/91, task 149/149 ✅
- Gate script: `✅ CLI dashboard mock completeness: all hardcoded mocks
cover source imports.`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Tests**
- Added automated validation to ensure CLI test mocks remain aligned
with available dashboard functionality.
- Updated test coverage setup so GitHub, GitLab, daemon, dashboard,
server, and task scenarios use complete dashboard mocks.
- Test verification now reports missing mocked functionality and blocks
the release gate when inconsistencies are detected.
- **Chores**
- Improved reliability and maintainability of automated verification for
CLI and dashboard integrations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- pnpm dev / new pnpm start default to the dashboard command
- fn dashboard (and bare fn/fusion/npx, incl. packaged binaries) now runs
supervised by default via an attached foreground child (TUI-safe);
--no-supervise opts out; FUSION_RESTART_EXIT_CODE=86 = intentional restart
- New /api/system routes: info, restart, rebuild jobs with SSE output,
engine restart, agents restart-all, plugins reload-all, log tail
- System tab: rebuild & restart (source checkouts only, hidden elsewhere),
restart server/engine/agents, backup DB, live server logs, copy
diagnostics, report bug; new Plugins tab reusing PluginManager
- Desktop restart via Electron app.relaunch(); DashboardLogSink now keeps a
bounded history + listener feed for the log viewer
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>