## Summary
- Switches the engine-core Vitest project from thread workers to fork
workers to avoid the Node 24/macOS libuv kqueue SIGABRT while preserving
real failure semantics.
- Adds a small policy regression test covering the gate pool, warning
behavior, and engine-core allow-list expectations.
## Test Plan
- node --test scripts/__tests__/engine-vitest-gate-policy.test.mjs
- corepack pnpm --filter @fusion/engine test:core
<!-- stage-review-badge-begin -->
---
<a href="https://stagereview.app/Runfusion/Fusion/pull/1764">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://stagereview.app/assets/gh-open-in-stage-dark.svg">
<img src="https://stagereview.app/assets/gh-open-in-stage-light.svg"
alt="Open in Stage">
</picture>
</a>
<!-- stage-review-badge-end -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved reliability of the engine’s Vitest test execution on newer
macOS/Node setups by scoping a safer worker strategy to the core
merge-gate suite.
* Prevented configuration and gate-script changes that could otherwise
break consistent test behavior.
* **Tests**
* Added automated “gate policy” checks to validate Vitest configuration
constraints and ensure core/test-gate scripts run with the expected
command and allow-listed test patterns.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What & why
Cuts feedback-loop wall-time on the slowest dashboard test files
(FN-5048 velocity). Profiled the velocity baseline's top offenders; all
changes are **behavior-preserving** — no assertions, timeouts, or
worker/concurrency knobs changed.
## Changes
| File | Root cause | Fix | Result (verified locally) |
|---|---|---|---|
| `SettingsModal.test.tsx` (#1, ~60.5s) | 231 tests in one sequential
worker; flat ~250ms/test | Split into 4 sibling files sharing
`SettingsModal.test-harness.tsx`; the settings project parallelizes them
across workers | shard **60.5s → ~25s** (−58%) |
| `insights-routes.test.ts` (#2, ~26.5s) | Double `TaskStore.init()` per
test; only 1 of 24 tests needs the project-b store | Lazy-init `storeB`
on first use | tests **5.78s → 3.66s** (−37%) |
| `evals-routes.test.ts` | Same double-init pattern | Same lazy `storeB`
| tests ~0.98s |
### SettingsModal split mechanics
- Test bodies moved **verbatim** — static `it()` count preserved at
**231**.
- `vi.mock` factories stay in each test file (they only apply per
module) and reference the ~61 mock fns imported from the harness.
- Shared `beforeEach`/`afterEach` registered via the harness's exported
`installSettingsModalEnv()`.
- `vitest.config.ts`: `qualityAppSettingsOnlyTests` now points at the 4
new files; bare `"SettingsModal"` dropped from
`qualityAppComponentTests`/`isolatedQualityAppComponentTests`.
## Verification
- All 4 split files green; independent run: **518 passed / 0 failed** (4
files × 2 project collections × 259 assertions). Original profile = 259
assertions / 231 `it()`s — matches.
- ESLint exit 0 on all new/changed files; `check-test-inventory
--dashboard-curated` passed.
- `insights-routes` 24/24 and `evals-routes` 7/7 pass.
## Notes
- No changeset (test-only + CI config, behavior-preserving — per
AGENTS.md).
- Stale references to the old filename remain only in generated
snapshots (`test-timings.json`, `line-count-baseline.json`,
`test-velocity-history.json`); they refresh on the next `pnpm
test:velocity` run.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- stage-review-badge-begin -->
---
<a href="https://stagereview.app/Runfusion/Fusion/pull/1763">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://stagereview.app/assets/gh-open-in-stage-dark.svg">
<img src="https://stagereview.app/assets/gh-open-in-stage-light.svg"
alt="Open in Stage">
</picture>
</a>
<!-- stage-review-badge-end -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Expanded dashboard settings coverage with focused suites for General,
Authentication, Scheduling/Merge, and Remote/Notifications.
* Added a shared SettingsModal test harness to centralize rendering,
readiness, and persistence assertions, improving reliability and
maintainability.
* Updated Evals/Insights route tests to lazily initialize and clean up
project-scoped task storage.
* Adjusted Vitest configuration to isolate the new SettingsModal shards
and prevent duplicate execution, keeping test runs faster and cleaner.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- Exclude the 4 SettingsModal split files from the app backfill project
(greptile P1): the split dropped the bare "SettingsModal" entry from
qualityAppComponentTests, which had excluded the curated file from
backfill; without spreading qualityAppSettingsOnlyTests into
backfillAppExclude the split files matched the backfill `app/**` glob
and ran in two projects, doubling their wall-time. Now collected by
exactly one project (dashboard-app-quality-settings).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reduce feedback-loop wall-time on the slowest dashboard test files
(FN-5048 velocity), behavior-preserving — no assertions, timeouts, or
worker counts changed.
- SettingsModal.test.tsx (231 tests, ~60.5s in one sequential worker)
split into 4 sibling files sharing SettingsModal.test-harness.tsx so
the settings project parallelizes them across workers (~60.5s -> ~25s
wall). Test bodies moved verbatim; static it() count preserved at 231.
vi.mock factories stay per-file and reference the harness-exported
mock fns; shared beforeEach/afterEach via installSettingsModalEnv().
- insights-routes.test.ts: lazily init the project-b store (only 1 of 24
tests needs it) instead of a second TaskStore.init() per test
(tests 5.78s -> 3.66s).
- evals-routes.test.ts: same lazy storeB pattern.
- vitest.config.ts: point the settings-only project at the 4 new files;
drop the bare "SettingsModal" entry from the component shards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
Fill in proper translations for three i18n keys that were added as empty
strings to all non-English locales. Also adds the `{{mergingSuffix}}`
interpolation to `workflowSwitcher.countsAria` to match the English
catalog.
## Changes
Keys fixed across zh-CN, zh-TW, fr, es, ko:
| Key | Change |
|-----|--------|
| `dashboard.title` | Empty string -> proper translation |
| `workflowSwitcher.merging` | Empty string -> proper translation |
| `workflowSwitcher.mergingTitle` | Empty string -> proper translation |
| `workflowSwitcher.countsAria` | Added missing `{{mergingSuffix}}`
interpolation |
## Verification
- `pnpm --filter @fusion/i18n vitest run src/__tests__/parity.test.ts
src/__tests__/i18n-gate-coverage.test.ts` passes (7/7 tests)
<!-- stage-review-badge-begin -->
---
<a href="https://stagereview.app/Runfusion/Fusion/pull/1760">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://stagereview.app/assets/gh-open-in-stage-dark.svg">
<img src="https://stagereview.app/assets/gh-open-in-stage-light.svg"
alt="Open in Stage">
</picture>
</a>
<!-- stage-review-badge-end -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added localized dashboard titles for Spanish, French, Korean,
Simplified Chinese, and Traditional Chinese.
* Added/updated workflow switcher text for the merging state, including
clearer task-count messaging and new labels in the same languages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Three keys (dashboard.title, workflowSwitcher.merging,
workflowSwitcher.mergingTitle) were added as empty strings to all
non-en locales. Fill in proper translations and add the
{{mergingSuffix}} interpolation to workflowSwitcher.countsAria to
match the English catalog.
Locales updated: zh-CN, zh-TW, fr, es, ko
TaskStore shutdown now tears down its cached plugin store to avoid leaking plugin database handles.
- Dispose the cached PluginStore during TaskStore.close(), clear the cache, and remove listeners before closing.
- Keep close idempotent when no plugin store was created or after a prior teardown.
- Add regression coverage for direct TaskStore.close() and disk-backed harness reopen lifecycle.
Files changed:
.../src/__tests__/store-plugin-store-close.test.ts | 63 ++++++++++++++++++++++
packages/core/src/store.ts | 15 ++++++
2 files changed, 78 insertions(+)
Fusion-Task-Id: FN-7005
Fusion-Task-Lineage: fe2242d8-7004-4d29-904d-58ee77861d99
Stabilize @fusion/core tests by resetting stale plugin-store database handles and aligning fixture assertions.
- Add a PluginStore close method that disposes local and central database connections.
- Reset the lazy plugin store before the shared test harness clears global settings storage.
- Cover plugin-store reopening from the built-in workflow harness.
- Assert the runtime FN task-prefix fallback without requiring serialized defaults.
Files changed:
packages/core/src/__tests__/builtin-workflows.test.ts | 6 ++++++
packages/core/src/__tests__/store-test-helpers.ts | 8 ++++++++
packages/core/src/__tests__/test-project.test.ts | 8 +++++++-
packages/core/src/plugin-store.ts | 12 ++++++++++++
4 files changed, 33 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7003
Fusion-Task-Lineage: ec4d6e45-61ea-4e6a-b296-3af3acf7ba4b
Remove the stale branch reattachment affordance from Task Detail while preserving self-healing as the recovery path.
- Remove unused rebind banner styles and mobile action-shell rules.
- Drop stale recoverBranchBinding mocks from TaskDetailModal tests.
- Add rendering coverage proving Task Detail and embedded content do not show reattachment affordances across missing, populated, workspace, and mobile branch states.
- Add a patch changeset for the published Fusion package.
Files changed:
.changeset/fn-6983-task-detail-rebind-warning.md | 7 ++
.../dashboard/app/components/TaskDetailModal.css | 42 +-----------
.../TaskDetailModal.create-pr-e2e.test.tsx | 1 -
.../TaskDetailModal.create-pr-integration.test.tsx | 1 -
.../__tests__/TaskDetailModal.rendering.test.tsx | 80 ++++++++++++++++++++++
.../__tests__/TaskDetailModal.test-helpers.ts | 1 -
6 files changed, 88 insertions(+), 44 deletions(-)
Fusion-Task-Id: FN-6983
Fusion-Task-Lineage: 1a45c38e-f7d0-4df7-94cf-7d1309758e0d
Ensure mobile Missions exits detail tabs back to the mission list before outer navigation.
- Track mobile detail visibility instead of selected mission IDs when adding navigation entries.
- Avoid duplicate history entries for Structure/Activity tab switches and mission refreshes.
- Cover browser back and visible Back button behavior across mobile tabs while desktop stays unchanged.
- Add a patch changeset for the published Fusion package.
Files changed:
.changeset/fn-6998-mobile-mission-back.md | 7 ++
.../dashboard/app/components/MissionManager.tsx | 35 +++++--
.../__tests__/MissionManager.swipe-back.test.tsx | 114 ++++++++++++++++++---
3 files changed, 131 insertions(+), 25 deletions(-)
Fusion-Task-Id: FN-6998
Fusion-Task-Lineage: d3dbf3b7-0195-498f-a57f-ed83c6a422e7
Fix 6 failing tests caused by intentional source changes that landed
without updating dependent test assertions:
- Core test-project: taskPrefix default changed from "FN" to undefined
(commit 800f845e1, derived from project name at runtime)
- Dashboard ScriptsModal.css: replace banned --text-primary with --text
- CLI package-config: update expected pi dep version ^0.79.1 -> ^0.79.9
- CLI skill-sync: document 4 new engine tools in engine-tools.md
- CLI version: update expected release:version script to include
run-ci-distill.mjs
- CLI bundled-plugin-freshness: rebuild stale dist directories
## Summary
Running more than one fusion process on a host (multiple dashboards/CLIs
across worktrees, all attaching `~/.fusion/fusion-central.db`) could
crash a `node` process at random — instantly, with no JS stack and
nothing in the logs. This happened 3 times in 3 days on one machine.
After this change those processes coexist without crashing.
The crash was an OS-level `SIGBUS` (`EXC_BAD_ACCESS`, `FS pagein error`
/ kernel `cluster_pagein past EOF`) inside SQLite's `walIndexReadHdr`.
In WAL mode every connection coordinates through a memory-mapped `-shm`
wal-index; on macOS/APFS, when one process resizes/rebuilds that file
during a checkpoint while another has it mmap'd, the reader faults on
the now-out-of-bounds page. A hardware memory fault can't be caught by
`node:sqlite` or JS, so the whole process dies.
The fix switches the central DB to `journal_mode = DELETE` (rollback
journal), which uses no `-shm` memory map and coordinates cross-process
access via POSIX byte-range locks instead — removing the faulting
surface entirely while keeping multi-process access. The existing
`busy_timeout` absorbs the writer serialization that DELETE mode trades
for WAL's reader/writer concurrency. Per-project DBs (`db.ts`) are
intentionally left on WAL: they're single-process-per-project and don't
hit this cross-process fault. SQLite migrates the existing WAL database
on first open (checkpoints `-wal` into the main file and removes
`-wal`/`-shm`), so there is no data loss.
## Test plan
- New regression tests in `central-db.test.ts` assert the central DB
reports `journal_mode = delete` (not `wal`) and that **no `-shm`
wal-index file is ever created** even after write traffic — i.e. the
exact faulted surface is gone.
- All 6 central-DB suites pass (221 tests); `@fusion/core` typechecks
clean.
---
[](https://github.com/EveryInc/compound-engineering-plugin)

<!-- stage-review-badge-begin -->
---
<a href="https://stagereview.app/Runfusion/Fusion/pull/1752">
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://stagereview.app/assets/gh-open-in-stage-dark.svg">
<img src="https://stagereview.app/assets/gh-open-in-stage-light.svg"
alt="Open in Stage">
</picture>
</a>
<!-- stage-review-badge-end -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved stability when multiple dashboards or CLIs run on the same
machine.
* Switched the local database to a safer journaling mode to reduce rare
crash issues on macOS/APFS.
* Prevented creation of extra database side files during normal
operation, while keeping data durability and lock-based coordination in
place.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- Verify the WAL->DELETE journal-mode switch instead of discarding exec()'s
result. During a rolling upgrade a lingering WAL holder blocks the exclusive
lock the switch needs, so SQLite either throws SQLITE_BUSY or no-ops and
returns "wal". Capture both outcomes and warn loudly so the residual -shm
SIGBUS surface is observable, rather than silently swallowed.
- Do not rethrow: the condition is transient and self-healing (the next start
after the last WAL holder exits migrates cleanly); hard-failing would make the
central DB unopenable during the very upgrade window it describes.
- Add a migration-path regression test (a WAL holder blocking the switch) that
the prior fresh-DB-only tests did not cover.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Problem
The latest release **v0.47.0 published 0 binaries**, and every desktop
build leg has been failing.
Two independent bugs in the release pipeline:
### 1. `github-release` job crashed → no binaries published
The job downloads artifacts but never checks out the repo. A step added
2026-06-24 (`Extract release notes from CHANGELOG`) does
`fs.readFileSync('CHANGELOG.md')`, which threw `ENOENT: no such file or
directory` and failed the whole job — so v0.47.0 shipped **0 assets**
even though every bun build leg succeeded. (v0.45/v0.46 predated this
step and still published 21 assets each.)
### 2. Desktop Windows EXE / macOS DMG legs failing
`packages/desktop/src/local-runtime.ts` dynamically imports
`@fusion/engine`, but engine was missing from the esbuild externals list
(only `@fusion/core` and `@fusion/dashboard` were there). esbuild
followed the import and tried to bundle engine's transitive `node-pty`
native binaries:
```
X [ERROR] No loader is configured for ".node" files:
.../@homebridge/node-pty-prebuilt-multiarch/build/Release/pty.node
```
## Fix
- **`.github/workflows/release.yml`** — sparse-checkout `CHANGELOG.md`
in the `github-release` job, and harden the notes script to fall back to
a plain `Release vX.Y.Z` body instead of crashing the publish.
- **`packages/desktop/scripts/build.ts`** — externalize `@fusion/engine`
alongside the other workspace packages; it resolves from `node_modules`
at runtime, same as `core`/`dashboard`.
## Verification
- `pnpm build` runs clean locally — `dist/main.js` (623 kB) builds with
no `.node` loader error.
- YAML validated; `pnpm check:changesets` passes.
## Changeset
`"@runfusion/fusion": patch` (category `fix`) — restores
binary/installer publishing.
## Follow-up
These take effect on the next release. To backfill v0.47.0's missing
binaries, after merge delete + re-push the `v0.47.0` tag (the
tag-triggered run uses the workflow file at the tag).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed release publishing so binary and desktop installer artifacts are
published correctly again.
* Improved release note generation to fall back gracefully when
changelog details aren’t available, preventing failed releases.
* Updated desktop app bundling to avoid packaging native dependencies
incorrectly, reducing build and packaging issues.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The central DB (~/.fusion/fusion-central.db) is opened concurrently by every
fusion process on a host. In WAL mode those connections coordinate through a
memory-mapped `-shm` wal-index; on macOS/APFS a reader takes a SIGBUS
(walIndexReadHdr / `cluster_pagein past EOF`) when another process resizes it
mid-checkpoint, killing the node process with no JS stack or log. Observed 3x
in 3 days. Switch the central DB to journal_mode=DELETE, which uses no `-shm`
mmap and coordinates cross-process access via POSIX byte-range locks instead;
busy_timeout absorbs the added writer serialization. Per-project DBs keep WAL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
local-runtime.ts dynamically imports @fusion/engine, but it was missing from the
esbuild externals list (only @fusion/core and @fusion/dashboard were there). esbuild
followed the import and tried to bundle engine's transitive node-pty native .node
binaries, failing with "No loader is configured for .node files" — which broke every
desktop Windows EXE and macOS DMG build leg. Externalize @fusion/engine like the other
workspace packages; it resolves from node_modules at runtime.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The github-release job downloaded artifacts but never checked out the repo,
so the new "Extract release notes from CHANGELOG" step threw ENOENT and failed
the whole job — v0.47.0 published 0 binaries despite every bun build succeeding.
Sparse-checkout CHANGELOG.md and harden the notes script to fall back to a plain
release body instead of crashing the publish.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>