## Summary
Concurrent PostgreSQL project initialization no longer causes transient
dashboard failures, including repeated `GET /api/remote/status` 500
responses. The failure was a database deadlock between project-row
identity promotion and schema/plugin DDL, which previously acquired
overlapping locks in inconsistent orders.
This establishes one advisory-lock order across SQLite cutover, project
identity promotion, and schema mutations. Focused regression coverage
proves schema DDL waits behind an active migration transaction and that
identity stamping acquires the migration lock before reading
project-owned tables.
## Validation
- 25 focused unit tests passed.
- 3 focused real-PostgreSQL regression tests passed.
- `@fusion/core` typecheck passed.
- Strict changeset validation passed.
- Fast workspace verification passed, including the CLI build and boot
health check.
---
[](https://github.com/EveryInc/compound-engineering-plugin)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Prevented transient dashboard failures caused by PostgreSQL startup
and migration deadlocks.
* Improved serialization when multiple projects initialize or update
database schemas concurrently.
* Ensured migration state updates and schema changes occur in a
consistent order.
* **Tests**
* Added coverage for migration lock ordering, concurrent schema
operations, and recovery after lock contention.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Heartbeat customTools inventory includes `fn_research_promote_finding`
(64 tools).
- Schema-applier bookkeeping for migration `0023` research feature
provenance.
- Seed upgrade fixtures include `mission_features.slice_id` for the
unique index.
## Evidence
- Full greens earlier this session: **29662309385** (#2323),
**29663526777** (#2325), **29664692957** (#2327).
- Tip red after FN-8297: heartbeat 63→64 + schema upgrade seed.
## Test plan
- [x] heartbeat expected-tools + schema upgrade tests green locally
- [ ] Full Suite all shards green on tip after merge
## Summary
Planning breakdowns now preserve their creating task as durable lineage
and reuse only siblings from that same parent. Identical wording under a
different parent creates a distinct child instead of silently linking
the wrong lineage.
The dashboard planning path now uses the same duplicate-safe creation
contract as agent tools, leaves reused canonical tasks untouched, and
exposes API-created parent links in task details.
Related: FN-8277
## Validation
- Core duplicate guard: 12 tests passed
- Engine task creation: 32 tests passed
- Dashboard planning routes: 4 focused tests passed
- Dashboard task detail provenance: 2 focused tests passed
- Core, engine, dashboard, and CLI typechecks passed
- Lint and strict changeset validation passed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Preserved parent-task lineage for subtasks created through planning
breakdowns and API workflows.
- Improved duplicate detection so identical tasks from different parent
tasks can coexist safely.
- Added parent-task links to API-created task provenance details.
- Reused existing duplicates only within the same parent-task context.
- **Bug Fixes**
- Prevented duplicate handling from incorrectly archiving or skipping
tasks belonging to other parents.
- Improved dependency handling when creating planned subtasks.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
Moving an active task back to Todo could update the board before its
agent and subprocesses had stopped, leaving a Todo card that was still
processing. User-initiated in-progress-to-Todo moves now wait for every
executor cancellation surface before the new column is persisted or
returned to the dashboard. Cancellation is fail-closed and bounded: a
wedged shutdown leaves the task in Progress, releases its lock for
recovery, and fences late cleanup from replacement execution
generations. Engine-driven recovery moves and other transitions retain
their existing behavior.
## Validation
- Confirmed with PostgreSQL-backed symptom tests that the durable row
stays in Progress while cancellation is pending and that a timeout
releases the task lock without publishing Todo.
- Verified multi-executor ownership and replacement-generation fencing
across focused core and engine tests: 18 tests passed.
- Core build, engine typecheck, targeted lint, and strict changeset
validation passed.
---
[](https://github.com/EveryInc/compound-engineering-plugin)
Read the live port from PostgreSQL's actual postmaster.pid field so extension TaskStore boot reuses the existing server instead of wedging on a colliding start.
## 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 -->
## Summary
Task cards now remove the overseer eye as soon as their workflow's
effective oversight becomes `off`, instead of reusing an active value
cached before the setting changed.
The invalidation covers card remounts as well as mounted cards, and
authoritative writes from the dashboard, agents, and configuration
rollback reach the board through the existing project-scoped SSE stream.
Older in-flight responses cannot restore the eye after a newer `off`
value wins, while unrelated workflow-setting saves leave active
indicators undisturbed.
## Validation
- 99 focused dashboard regression tests passed across selected and
aggregate cards, desktop and mobile, SSE delivery, and out-of-order
responses
- Core and dashboard typechecks passed
- `pnpm lint` and `pnpm check:changesets` passed
- `pnpm verify:fast` passed production builds and the CLI/server boot
smoke
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Planner-overseer eye badges now disappear immediately when workflow
oversight is turned off.
- Prevented stale or out-of-order updates from displaying incorrect
oversight status.
- Oversight indicators now remain hidden when the effective setting
cannot be confirmed.
- Live workflow setting changes now update task cards without requiring
a page refresh.
- **Documentation**
- Clarified eye badge visibility rules, tooltip meaning, and active
oversight states in the dashboard guide.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Extend shared TaskDetailModal lucide mock for FN-8286
ArtifactsGallery/TaskReviewTab icons.
- Update schema-applier bookkeeping for FN-8295 ideation (93 project
tables, version 0022).
- Seed historical 0000 upgrade fixtures with missions/mission_features
stubs so ideation FKs apply after ownership rewrite.
## Test plan
- [x] TaskDetail modal suites + mock-coverage green locally
- [x] Full schema-applier suite (59 tests) green locally
- [ ] Full Suite all 4 shards green on main after merge
## Summary
- Full Suite run
[29641723814](https://github.com/Runfusion/Fusion/actions/runs/29641723814)
left shards 1–3 green; shard 4 (`@fusion/core`) failed after FN-8265
landed.
- `settings-parity`: `PROJECT_SETTINGS_KEYS` now includes
`NON_DEFAULT_PROJECT_SETTINGS_KEYS` (`ephemeralAgentTaskCreationPolicy`
has no default; resolver owns fallback).
- `schema-applier`: expected applied-migration lists and identity suite
include `TASK_PROPOSAL_CLAIM_VERSION` (`0020`).
## Test plan
- [x] `pnpm --filter @fusion/core exec vitest run
src/__tests__/settings-parity.test.ts
src/__tests__/postgres/schema-applier.test.ts` — 136 passed
- [ ] Full Suite all 4 shards green on main after merge
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Updated migration validation tests to include the latest task proposal
claim migration.
* Expanded settings parity checks to cover non-default project settings.
* Added coverage confirming migration ordering and immutable migration
identities.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- uninstaller: taskkill only the first, digits-only postmaster.pid line
(the for /f loop ran taskkill on the port/epoch lines — potential
unrelated-process kill)
- git-missing dialogs use new ConfirmOptions.alwaysAsk so global
skip-confirmations cannot silently pick an unseen choice
- Windows quit prompt: embedded-local runtimes only, skipped during OS
session end (sync dialog blocked Windows shutdown)
- 'leave it running' detaches the embedded lifecycle (disarms its
process shutdown hook) so Electron exit cannot kill the postmaster
the operator chose to keep (new detachKeepingEmbedded)
- wizard: ref-based double-submit guard around the async git preflight
- clone route: ENOENT invalidate-and-retry matching runGitCommand
- openExternalUrl: drop the async window.open fallback (always
popup-blocked); log bridge failures instead
- DirectoryPicker: close the panel when listing the created folder
fails so Select cannot re-commit the parent
- git status probe bounded to two spawns (PATH + first candidate)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Registering a project on a git-less host used to fail after submission
with a raw spawn error. The setup wizard now probes gitCli up front and
offers: open the Git downloads (picked up without restart thanks to the
stale-PATH resolver), create the project anyway without a git repo
(new skipGitInit passthrough, rejected for clone mode), or cancel.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A git installed DURING first-run setup stayed invisible (spawn git
ENOENT on project creation; onboarding indicator stuck on missing)
because the server's PATH snapshot predates the install. New resolver
probes well-known install locations on PATH ENOENT with cache
invalidation, wired into project git init/workspace detection, the
onboarding git status probe, and the dashboard clone route.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Users whose embedded cluster was initdb'd with an OS-locale encoding by
a pre-fix version now self-heal with zero manual steps: on the
encoding-conversion schema failure the startup factory proves the
cluster is non-UTF-8 AND empty (the baseline transaction never applied,
so no schema or migrated data can exist) and that this process owns the
postmaster, then deletes the data dir and reboots once with the UTF-8
initdb defaults. Joined instances and unproven states keep the manual
re-init hint; one retry ever, so no loops.
Verified on the elevated windows-latest runner: CI seeds a real WIN1252
cluster via initdb and proves a stock 'fn serve' auto-recovers it to a
healthy /api/health (run 29633351848, all jobs green). Also caps the
desktop-windows embedded-PG smoke at 30 min and adds a skip input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Squash of feature/win-elevated-no-user, verified end-to-end on the
elevated windows-latest runner (restricted-token double boot + full
'fn serve' /api/health smoke, both green).
- Elevated Windows boots embedded PostgreSQL via pg_ctl's built-in
restricted-token re-exec instead of creating a 'fusion-pg' local user
(operator requirement: Fusion must never create accounts). Removes
the credential launcher, icacls grants, and cmd/PowerShell wrapper —
and with them the 'directory name is invalid' and wrapper-log EBUSY
field failures. Leftover fusion-pg accounts are deleted on start.
- Embedded clusters are always initdb'd --encoding=UTF8 --locale=C
(GitHub issue #2286: OS-locale WIN1252/WIN1254 clusters could not
store the UTF-8 schema and crash-looped the dashboard). Existing
non-UTF-8 clusters get an actionable re-init hint at boot.
- Schema-backend boot failures now surface the full error cause chain
(DrizzleQueryError hid the real PostgresError behind the SQL text).
- Elevated stop() waits until the port closes and postmaster.pid is
gone before resolving.
- CI: branch verification workflow (restricted-token proof + elevated
boot smoke + account-absence assertions); boot-smoke stderr tail
widened for diagnosability.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Start-Process -Credential (CreateProcessWithLogonW) validates the working
directory as the TARGET user. The launcher inherited the desktop app's cwd
(admin profile / install dir), which the dedicated fusion-pg user cannot
read, so elevated desktop boots died with "The directory name is invalid"
before postgres ever started. launch.ps1 now pins -WorkingDirectory to the
.pgrunner run dir inside the data dir the user was just granted full
control on. CI never caught it because runner cwds are world-traversable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The one-time SQLite→PostgreSQL migration runs inside createTaskStoreForBackend
before any HTTP server listens, so browsers saw "connection refused" and open
tabs failed silently for minutes. Now:
- CLI: a temporary holding server binds the dashboard port for the boot window,
serving an auto-reloading "Database migration in progress" page and an
/api/health payload with status "migrating" + structured progress; the port
is handed off (awaited) to the real app.listen().
- Dashboard SPA: already-open tabs render the new MigrationInProgressBanner
from the 15s health poll when status is "migrating".
- Desktop: LocalRuntimeManager publishes migration progress on
DesktopRuntimeStatus via the new core onMigrationProgress option;
DesktopLaunchGate shows the live label and extends its 30s startup timeout
while progress advances (2min stall cap), in both boot and first-run flows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Legacy SQLite databases can hold U+0000 in TEXT cells and inside stored
JSON, which PostgreSQL rejects in text and jsonb columns and which
aborted the first-boot auto-migration. Strip NUL from plain text cells,
JSON string values and object keys, malformed-JSON scalars, and opaque
legacy-preservation cells; content-checksum verification compares the
sanitized source against the sanitized target so migrations still verify.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
shared_memory_type=mmap (defaulted 2026-07-16 for SysV shm exhaustion)
is invalid on Windows — PostgreSQL only accepts "windows" there and
dies with FATAL invalid value for parameter before opening the port.
Every Windows embedded start broke, failing the Windows release smoke
in both the v0.70.0 and v0.70.1 tag runs. Default flags now come from
defaultEmbeddedPostgresFlagsFor(platform): empty on win32 (no override
needed; SysV exhaustion cannot occur there), mmap elsewhere. Regression
test asserts the per-platform flag invariant.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bun-compiled exe has been unbootable since the PG cutover: bun
standalone binaries do no node_modules resolution, so the deliberately
out-of-graph require("embedded-postgres") failed from /$bunfs, and
readFile'd migration .sql files were never embedded, so even external
DATABASE_URL mode died at schema init.
- schema-applier: resolveMigrationsDir() — FUSION_MIGRATIONS_DIR env >
module-relative dist/migrations (npm/desktop, unchanged) >
execPath-relative migrations/ (standalone exe), probe-based.
- embedded-lifecycle: require("embedded-postgres") first (npm/desktop
untouched), falling back to a self-contained staged bundle at
<execDir>/runtime/<platform>/embedded-postgres/dist/index.cjs
(FUSION_EMBEDDED_PG_RUNTIME_DIR override) with the native
initdb/pg_ctl/postgres payload beside it.
- build.ts: stage dist/migrations plus the per-target embedded-postgres
bundle + native payload (warn when a cross-target payload is absent on
the host, mirroring desktop's verifyEmbeddedPostgresPayloads).
- release.yml: package fn-cli-<os>-<arch>.tar.gz (binary + migrations +
runtime + client) with sha256 per leg; prune staged payload files from
the release-collection globs; bare fn-cli-* binaries still uploaded.
E2E-verified on the compiled binary: embedded mode initdb→/api/health
200 database healthy; DATABASE_URL mode applied migrations 0000–0019
(109 tables). Core typecheck clean; schema-applier 58/58 and
embedded-lifecycle 44/44 tests pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Summary
An audit of the SQLite→PostgreSQL store migration found data-store paths
still reaching the removed SQLite stub in backend (PG) mode. In backend
mode `store.db`/`getDatabase()` throw the removed-SQLite error, so each
of these either threw on every run or — worse — had the throw swallowed
into a silent wrong result. This PR routes all of them through the
`AsyncDataLayer` (and removes one dead primitive).
## The 6 live bugs fixed
| Fix | Was |
|-----|-----|
| `executor.ts` authoritative assigned-agent fallback now inherits the
TaskStore `asyncLayer` | silently returned `null` → model drift to the
pi built-in (the exact thing its comment guards) |
| `pruneAgentLogFilesAsync` replaces the sync self-healing prune call |
threw `SQLite Database is not available` every maintenance sweep →
agent-log pruning never ran |
| `cleanupOrphanedMaterializedSteps` deletes PG `workflow_steps` rows on
a failed create | swallowed the throw → leaked rows |
| `deleteTaskBackendImpl` now runs the async mission feature/task-link
unlink | PG hard delete left orphaned mission links |
| `getWorkflowSettingsProjectId` returns `rootDir` in backend mode
without touching the stub | swallowed throw for unscoped backend stores
|
| `fn plugin` unregistered-project fallback bootstraps a `CentralCore`
`AsyncDataLayer` | layerless `PluginStore` threw in PG |
## The 4 latent traps, fixed properly
- **`cleanupArchivedTasks`** — real async port (enumerate archived
soft-deleted rows, guarantee cold snapshot, hard-delete project row +
purge selection rows + rm dir).
- **`deleteWorkflowStep`** — real async port (delete `workflow_steps`
via the layer with `.returning()` to preserve the not-found contract).
- **`applyTaskPatch`** — **removed** (zero-caller SQLite column-patch
primitive with no backend analogue; impl + facade + import deleted).
- **`AgentStore.importLegacyFileRuns`** — clean backend no-op (no legacy
SQLite run-files exist in a PG deployment; its only `init()` caller
early-returns in backend mode).
## Symptom Verification
New PG regression suite
`packages/core/src/__tests__/postgres/store-sqlite-residue-fixes.pg.test.ts`
reproduces the original failures against real embedded Postgres and
asserts they're gone:
- orphaned `workflow_steps` are actually deleted (no swallowed throw)
- `pruneAgentLogFilesAsync` resolves and prunes inactive-task log files
- hard delete unlinks the mission feature from the task
- `deleteWorkflowStep` removes the row / reports not-found
- `cleanupArchivedTasks` hard-deletes the project row while retaining
the cold snapshot
## Verification
- `@fusion/core`, `@fusion/engine`, `@runfusion/fusion` typecheck clean
- ~50 existing + 5 new PG tests pass; lint clean; changeset validates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Prevented PostgreSQL backend maintenance from hitting removed legacy
SQLite code paths, avoiding datastore failures and residue cleanup
issues.
* Fixed workflow-step deletion and “not found” behavior in backend mode.
* Ensured backend hard-deletes correctly unlink related mission
feature/task links and clean orphaned materialized steps.
* Prevented legacy file-run imports from incorrectly reporting success
in backend mode.
* **New Features**
* Added async agent-log pruning for inactive tasks and updated
maintenance to use it.
* **Tests**
* Added PostgreSQL regression coverage for residue fixes and
archive/workflow cleanup.
* **Refactor**
* Removed an unused task patch operation and updated task-store cleanup
methods to be async where needed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>