Commit Graph

1833 Commits

Author SHA1 Message Date
gsxdsm
5cd795a3f2 fix(db): use rollback-journal mode for central DB to stop SIGBUS crashes (#1752)
## 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.

---

[![Compound
Engineering](https://img.shields.io/badge/Built_with-Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin)
![Claude
Code](https://img.shields.io/badge/Opus_4.8_%281M%29-D97757?logo=claude&logoColor=white)


<!-- 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 -->
2026-06-25 00:04:43 -07:00
gsxdsm
e53f50eb38 Address PR review feedback (#1752)
- 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>
2026-06-24 23:51:52 -07:00
gsxdsm
50a94714ec fix(db): use rollback-journal mode for central DB to stop SIGBUS crashes
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>
2026-06-24 23:39:35 -07:00
gsxdsm
eb3833a542 FN-6971: retire dual-observe cutover gating
Remove stale dual-observe prerequisites from workflow-authoritative readiness while preserving parity-summary safeguards.

- Require the authoritative flag plus clean populated parity summaries for interpreter cutover readiness.
- Keep persisted workflowInterpreterDualObserve values inert in runtime tests and documentation.
- Update cutover, parity, and graph-executor tests to reflect retired shadow observation behavior.
- Add a formatted patch changeset for the operator-facing cutover readiness fix.

Files changed:
 .changeset/fn-6971-workflow-cutover-readiness.md   |  7 ++
 docs/architecture.md                               |  2 +-
 docs/settings-reference.md                         |  4 +-
 docs/workflow-steps.md                             | 19 +++--
 .../core/src/__tests__/workflow-cutover.test.ts    | 19 +++--
 packages/core/src/workflow-cutover.ts              |  9 +--
 .../workflow-interpreter-cutover.test.ts           | 87 +++++++++++++++++++---
 .../workflow-interpreter-dual-observe.test.ts      | 76 ++++++-------------
 .../src/__tests__/stepwise-workflow-parity.test.ts | 25 ++++---
 .../engine/src/workflow-authoritative-driver.ts    | 10 +--
 10 files changed, 152 insertions(+), 106 deletions(-)

Fusion-Task-Id: FN-6971
Fusion-Task-Lineage: 363a441d-62e5-403c-9389-75fcf788352a
2026-06-24 23:32:52 -07:00
gsxdsm
28ceca2cbd Address PR review feedback (#1747)
- core/store: include workspaceWorktrees in the slim and activity-log-limited
  SELECT lists (rowToTask reads it, but the explicit column lists omitted it, so
  slim/limited reads dropped the field and could misclassify workspace tasks);
  add regression tests for both read surfaces
- dashboard/register-git-github: validate caller-supplied repoPath in resolveGitDir
  via isPathWithin containment check (path-traversal hardening for all git
  endpoints); make loadWorkspaceConfig a static @fusion/core import per AGENTS.md
- dashboard/legacy: preserve repoPath in the string-form pullBranch overload
- dashboard/GitManagerModal: revalidate selectedRepo against the fetched repo list
  so a stale selection can't persist across project switches

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 15:43:12 -07:00
gsxdsm
f06281961e fix(workspace): persist workspaceWorktrees and isolate concurrent session leases
Multiworkspace tasks could not complete due to two independent bugs:

1. task.workspaceWorktrees had no SQLite column / rowToTask mapping, so
   fn_acquire_repo_worktree's updateTask write was dropped on every persist
   (applyTaskPatch writes the DB-round-tripped task back to task.json). Every
   later getTask returned undefined, so fn_task_done's scope verifier read {}
   and blocked with "acquired no sub-repo worktrees", and isWorkspaceTask()
   consumers misfired. Persist it mirroring mergeDetails (schema column + v129
   migration + db-migrate + defineTaskColumn + TaskRow + rowToTask).

2. In workspace mode every task ran rooted at the shared browse-only root, and
   setActiveSession registered that path keyed only by path — so a second
   concurrent workspace task was rejected by the foreign-task guard
   ("active-session path ... is held by ..."). Give each task a task-scoped
   synthetic session key (sessionRegistryPath), applied at all register and
   unregister sites; the in-memory worktree Set still holds the real root.

Regression tests assert the persistence invariant across getTask/listTasks/
store-reopen and concurrent session registration across all three session
surfaces; both verified to fail without the fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 15:13:43 -07:00
gsxdsm
b680948d8c Address PR review feedback (#1746)
- Fix race condition: add request ID guard for stale workspace detection responses
- Guard workspaceMode:true: only persist when repos.length > 0
- Add server-side taskPrefix validation (/^[A-Z]{1,5}$/)
- Move store.init() inside try/finally in both CLI TaskStore lifecycles
- Accept 1-character prefixes in CLI prompt (was requiring >= 2)
- Fix workspaceMode passing: forward false explicitly (was coerced to undefined)
- Fix 3rd KB→FN fallback in distributed-task-id.ts catch block
- Add try/finally to dashboard TaskStore in register-project-routes
- Gate workspace detection on existing-directory mode only (skip clone mode)
2026-06-24 14:24:07 -07:00
gsxdsm
46d0c4a1f6 Address PR review feedback round 3 (#1741)
- Align dashboard prefix validation to 1-5 chars (was 1-10) matching CLI cap
- Fix distributed-task-id.ts fallback from KB to FN (3 occurrences)
- Move taskPrefix/defaultWorkflowId persistence outside interactive-only block
  so non-interactive CLI registration also gets defaults
- Wrap both TaskStore lifecycles in try/finally to guarantee close() on error
2026-06-24 14:08:32 -07:00
gsxdsm
aae76cecc3 Address PR review feedback (#1741)
- Close first TaskStore before creating second in interactive registration (P1)
- Revert defaultWorkflowId default to undefined; set explicitly in onboarding only (P1)
- Add alpha-only filter + 2-char min to interactive prefix input (P2)
- Move suggestTaskPrefix to @fusion/core, share between CLI and dashboard (P2)
- Fix suggestTaskPrefix JSDoc to match implementation (P2)
2026-06-24 10:45:21 -07:00
gsxdsm
9a7c0c6154 fix: fallback task prefix to FN (was KB) when unset
The hardcoded fallback prefix in store.ts was 'KB' (legacy name). Changed
to 'FN' to match the product name and dashboard placeholder.
2026-06-24 10:31:06 -07:00
gsxdsm
800f845e15 feat(workspace): fix auto-detection, derive prefix from name, default coding workflow
- Fix workspace detection: change workspaceMode default from false to
  undefined so isWorkspaceModeExplicitlyDisabled no longer blocks
  auto-detection on fresh projects (config.json was being written with
  workspaceMode:false during store.init(), causing the guard to skip
  detection before it ever ran)
- Derive task prefix from project name (first 2-4 chars) instead of
  hardcoded 'FN' as the suggested default
- Default workflow is now builtin:coding instead of undefined
- CLI registerProjectInteractive: onboarding prompt for task prefix
  confirmation after project name
- Dashboard POST /api/projects: auto-derive prefix and set default
  workflow for new registrations
2026-06-24 10:31:06 -07:00
gsxdsm
c1b5be7d69 fix(workspace): write config.json before workspace.json, validate settings object
Address PR #1739 review round 3:

- Major (coderabbit): Reorder writes so setWorkspaceModeInConfig runs
  before saveWorkspaceConfig. If the config write fails, no stale
  workspace.json is left behind.
- Major (coderabbit): setWorkspaceModeInConfig only treats ENOENT as
  empty config (not parse errors or permission errors). Validates
  settings is a plain object before merging to prevent clobbering.
2026-06-24 09:02:02 -07:00
gsxdsm
11ffca1611 fix(workspace): persist workspaceMode:true in config.json, let save errors propagate
Address PR #1739 review round 2:

- P1 (greptile): Auto-detection fallback now sets workspaceMode: true in
  config.json so the dashboard toggle reflects the actual state.
- Major (coderabbit): Let saveWorkspaceConfig errors propagate instead of
  silently returning 'existing' when the write fails. A failed write would
  leave the project with no git repo and no workspace config.
2026-06-24 08:36:55 -07:00
gsxdsm
42342eff03 fix(workspace): respect explicit workspaceMode:false, improve exclusion test
Address PR #1739 review feedback:

- P1 (greptile): When workspaceMode is explicitly false in config.json,
  skip the auto-detection fallback so toggling workspace mode off via the
  dashboard has a lasting effect (was being re-enabled on next registration).
- CodeRabbit: node_modules exclusion test now includes a real sibling
  sub-repo to prove the exclusion is the gate, not just absence of
  detection.
- Add test for workspaceMode:false config.json guard.
2026-06-24 08:16:36 -07:00
gsxdsm
9aaf911735 feat(workspace): add per-project workspaceMode setting with interactive confirmation
Add workspaceMode as a first-class ProjectSettings boolean that controls
whether the project root is treated as a workspace parent (multi-repo)
or a single git repo.

- ProjectSettings type + DEFAULT_PROJECT_SETTINGS: workspaceMode?: boolean
- CLI registerProjectInteractive: when sub-repos are detected, ask the
  user to confirm workspace mode instead of auto-applying
- TaskStore.updateSettings: when workspaceMode is toggled on, detect
  sub-repos and persist workspace.json; when toggled off, remove it
- Dashboard SettingsModal GeneralSection: workspace mode toggle checkbox

This lets users change workspace mode per-project at any time via the
dashboard Settings or PUT /settings API.
2026-06-24 00:45:24 -07:00
gsxdsm
ff155b9df7 fix(workspace): exclude node_modules from detection, best-effort save
Address PR #1739 review feedback:

- P1: Exclude node_modules, .fusion, .pi from detectWorkspaceRepos so
  packages installed from git sources don't produce false-positive
  workspace members.
- P2: Wrap saveWorkspaceConfig in try/catch so a write failure (permissions,
  disk full) doesn't fail the current registration.
- Nitpick: Thread runner/timeout through detectWorkspaceRepos so custom-runner
  callers are consistent across all code paths.
2026-06-24 00:26:31 -07:00
gsxdsm
cab375a6f8 fix(workspace): detect sub-repos when workspace.json is missing
The initial fix only checked loadWorkspaceConfig, but the dashboard
POST /api/projects and `fn project add` routes never create workspace.json
(only registerProjectInteractive does). So re-adding a workspace project
through the dashboard still triggered git init because the guard saw no
workspace.json.

Add detectWorkspaceRepos as a fallback: after loadWorkspaceConfig and
isInsideGitWorkTree both miss, probe for git sub-repos. If found, persist
workspace.json and return 'existing' without running git init. This covers
all registration surfaces.
2026-06-24 00:16:37 -07:00
gsxdsm
038ac3060b FN-6963: disable tool output log details by default
Agent logs now keep tool timeline rows while requiring an explicit opt-in to persist verbose tool payloads.

- Default persistAgentToolOutput to false in global settings and direct AgentLogger construction.
- Update the settings UI, API expectations, documentation, and changeset to describe opt-in tool payload persistence.
- Adjust engine and dashboard tests for the new default-off behavior while preserving explicit opt-in coverage.

Files changed:
 .changeset/FN-6963-tool-output-default-off.md      |  5 ++++
 docs/settings-reference.md                         |  2 +-
 packages/core/src/settings-schema.ts               |  6 ++++-
 .../components/__tests__/SettingsModal.test.tsx    | 22 +++++++++++++---
 .../settings/sections/GlobalGeneralSection.tsx     |  2 +-
 .../src/__tests__/routes-settings.test.ts          |  4 +--
 packages/engine/src/__tests__/agent-logger.test.ts | 30 ++++++++++++++++++----
 .../src/__tests__/heartbeat-executor.test.ts       |  4 +--
 .../src/__tests__/merger-merge-details.test.ts     |  2 +-
 .../src/__tests__/merger-verification.test.ts      |  2 +-
 .../src/__tests__/step-session-executor.test.ts    |  4 +--
 packages/engine/src/__tests__/triage.test.ts       |  2 +-
 packages/engine/src/agent-logger.ts                |  8 ++++--
 13 files changed, 71 insertions(+), 22 deletions(-)

Fusion-Task-Id: FN-6963

Fusion-Task-Lineage: 7db32871-f539-4a27-a324-02c55ce5bd04
2026-06-23 23:35:33 -07:00
gsxdsm
6745126e14 Merge branch 'main' into fix/workspace-git-init-skip 2026-06-23 23:21:35 -07:00
gsxdsm
a9ea1f6fe3 fix(workspace): skip git init for workspace-mode project roots
ensureGitRepositoryForProjectPath unconditionally ran `git init` on
non-git paths, including workspace roots. This created a stray empty
repo with unborn HEAD at the workspace root, poisoning every downstream
git command (executor session cwd: `fatal: ambiguous argument 'HEAD'`).

Add an early-return guard that checks loadWorkspaceConfig before any git
operation, keeping the workspace root non-git as intended by the
workspace execution contract.
2026-06-23 23:14:05 -07:00
gsxdsm
9fbc93c8b1 Merge remote-tracking branch 'origin/main' into latest-1717
# Conflicts:
#	packages/engine/src/executor.ts
2026-06-23 17:40:35 -07:00
gsxdsm
37b2cb38ac Merge branch 'main' into feature/workflow-branch-group 2026-06-23 17:16:16 -07:00
gsxdsm
0dea25061d Merge remote-tracking branch 'origin/main' into conflict-resolution-1717
# Conflicts:
#	packages/engine/src/__tests__/executor-recovery.test.ts
#	packages/engine/src/agent-tools.ts
#	packages/engine/src/executor.ts
#	packages/engine/src/merger-ai.ts
#	packages/engine/src/project-engine.ts
#	packages/engine/src/worktree-acquisition.ts
2026-06-23 16:12:10 -07:00
gsxdsm
4faadd4f75 Merge remote-tracking branch 'origin/main' into conflict-resolution-1712
# Conflicts:
#	packages/dashboard/app/components/WorkflowNodeEditor.tsx
#	packages/engine/src/__tests__/executor-fast-mode-workflows.test.ts
2026-06-23 15:44:52 -07:00
gsxdsm
a8abecd043 Merge remote-tracking branch 'origin/main' into conflict-resolution-1711
# Conflicts:
#	packages/engine/src/executor.ts
2026-06-23 15:37:29 -07:00
gsxdsm
905a877954 Merge pull request #1710 from MichaelHoughtonDeBox/feat/workspace-multi-repo
Workspace mode: open a folder of git repos as one project (foundation + design Q)
2026-06-23 15:08:15 -07:00
gsxdsm
81f43e0e89 Merge pull request #1730 from Runfusion/feature/memory-fix
[codex] Dispose completed spawned child sessions
2026-06-23 10:29:30 -07:00
gsxdsm
a46800128a Address PR review feedback (#1730)
- Await async spawned child session disposal

- Use own-key iteration for structured tool result previews

- Add FNXC requirement comments for new regression assertions
2026-06-23 09:57:49 -07:00
gsxdsm
b02fb62c04 fix(core): avoid loading artifact content in registry lists 2026-06-23 09:16:57 -07:00
gsxdsm
a670f5ce98 FN-6952: repair workflow-column lifecycle regressions
Restores core lifecycle compatibility while keeping workflow-column scheduling on the graduated runtime.\n\n- Split raw compatibility-flag checks from public workflow-column runtime enablement.\n- Keep scheduler and hold-release sweeps on workflow columns despite stale persisted false flags.\n- Preserve legacy moveTask guard bypass and invalid-transition behavior for compatibility paths.\n- Isolate the startup watch recovery fixture and add a patch changeset.\n\nFiles changed:\n .changeset/fn-6952-core-lifecycle-regressions.md |  5 ++++\n packages/core/src/__tests__/store-create.test.ts |  6 +++++\n packages/core/src/store.ts                       | 32 +++++++++++++++++-------\n packages/core/src/workflow-columns-settings.ts   |  8 ++----\n packages/engine/src/hold-release.ts              |  6 +++--\n packages/engine/src/scheduler.ts                 | 10 +++++++-\n 6 files changed, 49 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-6952

Fusion-Task-Lineage: cfd7ad99-db00-4454-b3d7-a07a72a7bbe7
2026-06-23 08:21:10 -07:00
gsxdsm
efb94c8623 FN-6876: add editable model pricing refresh
Add editable model pricing overrides and a LiteLLM refresh path for usage cost analytics.

- Add persisted model pricing override settings and apply them to token and team analytics cost calculations.
- Add a Command Center pricing fetch endpoint that imports chat pricing from LiteLLM and invalidates settings caches.
- Add a Global Models pricing editor with manual rows, removal, and one-click fetch support.
- Cover override lookup, settings parity, analytics, route behavior, and UI editing with tests and docs.

Files changed:
 .changeset/model-pricing-overrides.md              |   5 +
 docs/architecture.md                               |   3 +-
 docs/dashboard-guide.md                            |   5 +-
 docs/settings-reference.md                         |   3 +
 packages/core/src/__tests__/model-pricing.test.ts  | 101 +++++++++++
 .../core/src/__tests__/settings-parity.test.ts     |   4 +
 packages/core/src/__tests__/store-settings.test.ts |  25 +++
 .../core/src/__tests__/token-analytics.test.ts     |  39 +++++
 packages/core/src/index.ts                         |   4 +
 packages/core/src/model-pricing.ts                 | 118 +++++++++++--
 packages/core/src/settings-schema.ts               |   3 +
 packages/core/src/team-analytics.ts                |  17 +-
 packages/core/src/token-analytics.ts               |  19 +-
 packages/core/src/types.ts                         |  12 ++
 .../dashboard/app/components/SettingsModal.tsx     |   2 +
 .../settings/sections/GlobalModelsSection.tsx      |   8 +-
 .../settings/sections/ModelPricingSection.css      |  82 +++++++++
 .../settings/sections/ModelPricingSection.test.tsx | 126 ++++++++++++++
 .../settings/sections/ModelPricingSection.tsx      | 193 +++++++++++++++++++++
 .../register-command-center-routes.test.ts         | 172 +++++++++++++++++-
 .../src/routes/register-command-center-routes.ts   |  58 +++++++
 21 files changed, 967 insertions(+), 32 deletions(-)

Fusion-Task-Id: FN-6876

Fusion-Task-Lineage: 4d4e3b9d-bec4-4e14-b7bc-88f846465566
2026-06-23 01:14:11 -07:00
gsxdsm
a147a983d5 fix(FN-6950): protect global settings and task chat icons 2026-06-23 00:31:58 -07:00
gsxdsm
849b40d220 FN-6947: tolerate workflow project identity failures
Keep workflow IR resolution usable when project identity lookup is unavailable.

- Treat workflow settings project identity errors as an absent project scope.
- Preserve project-scoped cache and prompt override behavior when identity resolves.
- Add resolver regression coverage and a patch changeset for the fallback behavior.

Files changed:
 .changeset/fn-6947-workflow-ir-project-identity.md |  5 ++
 .../src/__tests__/workflow-ir-resolver.test.ts     | 62 +++++++++++++++++++++-
 packages/core/src/workflow-ir-resolver.ts          | 12 ++++-
 3 files changed, 76 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-6947

Fusion-Task-Lineage: f63b985f-6c43-4163-8391-8ca5efb83079
2026-06-22 23:56:34 -07:00
gsxdsm
32986f6b50 fix(core): tolerate missing done task mirrors on startup 2026-06-22 21:51:28 -07:00
gsxdsm
65c4dc5438 fix(engine): harden workflow runtime cutover 2026-06-22 21:45:05 -07:00
gsxdsm
f9043d733e fix(dashboard): polish workflow and chrome defaults 2026-06-22 19:48:50 -07:00
gsxdsm
4fd8d444fb fix(dashboard): polish app chrome and workflow defaults 2026-06-22 18:21:06 -07:00
gsxdsm
c229a15e20 FN-6934: restrict agent workflow reassignment
Clarify agent workflow-routing prompts so agents do not reassign tasks they did not create unless directed.

- Add executor guardrails against changing the current task workflow without explicit user instruction.
- Update triage workflow-routing guidance to distinguish existing tasks from agent-created tasks.
- Cover workflow ownership policy in prompt and engine tests, docs, and a patch changeset.

Files changed:
 .changeset/fn-6934-workflow-movement-policy.md     |  5 +++++
 docs/agents.md                                     |  6 ++++++
 docs/custom-workflow-reliability-acceptance-map.md |  7 +++++--
 docs/settings-reference.md                         |  9 +++++++--
 docs/workflow-steps.md                             |  9 +++++++--
 packages/core/src/__tests__/agent-prompts.test.ts  | 15 ++++++++++++++
 packages/core/src/agent-prompts.ts                 | 23 ++++++++++++++++------
 .../src/__tests__/executor-review-verdicts.test.ts |  3 +++
 .../__tests__/triage-threshold-settings.test.ts    |  3 +++
 packages/engine/src/__tests__/triage.test.ts       |  2 +-
 packages/engine/src/executor.ts                    |  5 +++++
 11 files changed, 74 insertions(+), 13 deletions(-)

Fusion-Task-Id: FN-6934

Fusion-Task-Lineage: cc583806-b160-4a08-b1a7-e798a575dbd5
2026-06-22 17:58:27 -07:00
gsxdsm
a1cac3a6a3 fix(dashboard): replace quick chat with modal chat 2026-06-22 15:23:43 -07:00
gsxdsm
8dd9697468 FN-6714: backfill commit-association diff stats
Backfill historical commit-association diff stats so Command Center LOC can use real persisted git data.

- Add a core backfill API that inspects local git commits for associations with missing additions/deletions and supports dry-run reporting.
- Expose an authenticated Command Center productivity backfill endpoint and route it through the legacy API shim.
- Keep productivity LOC/hour sentinels safe for legacy payloads and document the backfill contract.
- Cover the backfill path, auth gate, productivity analytics, and route registration with tests.

Files changed:
 .changeset/fn-6714-command-center-loc-backfill.md  |   5 +
 docs/architecture.md                               |   4 +-
 docs/storage.md                                    |   4 +-
 ...mmit-association-diff-backfill.real-git.test.ts | 140 +++++++++++++++++++++
 packages/core/src/index.ts                         |   1 +
 packages/core/src/store.ts                         |  76 ++++++++++-
 packages/core/src/types.ts                         |   9 ++
 packages/dashboard/app/api/legacy.ts               |  16 +++
 .../command-center/areas/ProductivityArea.tsx      |   8 +-
 .../register-command-center-routes.auth.test.ts    |  48 ++++---
 .../register-command-center-routes.test.ts         |  49 +++++++-
 .../src/routes/register-command-center-routes.ts   |  20 +++
 12 files changed, 354 insertions(+), 26 deletions(-)

Fusion-Task-Id: FN-6714

Fusion-Task-Lineage: 657c7789-bbe4-4611-abca-127af05b0300
2026-06-22 03:42:24 -07:00
gsxdsm
af06170a51 FN-6778: add agent artifact registry tools
Adds engine and chat tools for registering, discovering, and viewing artifacts with inbox notifications.

- Add fn_artifact_register, fn_artifact_list, and fn_artifact_view tools for heartbeat, executor, and chat sessions.
- Send best-effort dashboard system inbox notifications when artifacts are registered.
- Classify artifact tools for action gating and coordination exemptions, with coverage for executor, heartbeat, permanent agent, and chat flows.
- Document the artifact registry behavior and update package metadata, quarantine ledger, and line-count baseline.

Files changed:
 .changeset/fn-6778-artifact-agent-tools.md         |   5 +
 CONCEPTS.md                                        |   3 +
 docs/agents.md                                     |   1 +
 packages/core/src/db.ts                            |   1 +
 .../src/__tests__/session-error-recovery.test.ts   |   1 +
 .../session-persistence-roundtrip.test.ts          |   1 +
 .../src/__tests__/session-reconnect.test.ts        |   1 +
 .../src/__tests__/session-resume-history.test.ts   |   1 +
 packages/dashboard/src/chat.ts                     |   6 +-
 packages/dashboard/src/planning.ts                 |   4 +
 packages/dashboard/src/test/mockCoreEngine.ts      |   1 +
 .../engine/src/__tests__/agent-action-gate.test.ts |   3 +
 .../src/__tests__/agent-artifact-tools.test.ts     | 458 +++++++++++++++++++++
 .../src/__tests__/executor-step-session.test.ts    |  48 +++
 .../src/__tests__/gating-classifications.test.ts   |   3 +
 .../src/__tests__/heartbeat-executor.test.ts       |  40 +-
 .../src/__tests__/heartbeat-session-prompt.test.ts |  25 +-
 .../src/__tests__/permanent-agent-gating.test.ts   |   6 +
 packages/engine/src/agent-heartbeat.ts             |   6 +-
 packages/engine/src/agent-tools.ts                 | 288 ++++++++++++-
 packages/engine/src/executor.ts                    |  25 ++
 packages/engine/src/gating-classifications.ts      |   7 +
 packages/engine/src/index.ts                       |   9 +
 scripts/lib/test-quarantine.json                   |   8 +-
 scripts/line-count-baseline.json                   |  54 +--
 25 files changed, 945 insertions(+), 60 deletions(-)

Fusion-Task-Id: FN-6778
Fusion-Task-Lineage: 7eb4afcb-8140-4f86-9540-eb3b83e64148
2026-06-22 03:34:14 -07:00
gsxdsm
8c478adc78 FN-6851: prevent stale task board entries
Keep board listings consistent after task dependency moves.\n\n- Sync the watched task cache after dependency updates write todo-to-triage re-specification moves.\n- Deduplicate listTasks results so active task rows win over archived snapshots.\n- Cover dependency edits, archive snapshots, soft deletes, done rows, and orphan reconciliation with regression tests.\n- Add a patch changeset for the published Fusion package.\n\nFiles changed:\n .../fn-6851-stale-board-entries-after-move.md      |   5 +\n .../store-stale-board-entries-after-move.test.ts   | 144 +++++++++++++++++++++\n packages/core/src/store.ts                         |  18 ++-\n 3 files changed, 157 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-6851

Fusion-Task-Lineage: 4622439e-631c-4410-be96-9a9f38c1815e
2026-06-22 03:34:14 -07:00
gsxdsm
3a71237624 fix(review): address PR #1717 Phase C merge-loop review feedback
- merger-ai: resolve+persist concrete landedSha when a sub-repo is recognized
  already-landed via the Fusion-Task-Id trailer fallback, so finalize no longer
  drops it and mis-finalizes a fully-landed workspace task as a no-op
- project-engine: manual-merge land-lease busy errors reject the resolver without
  burning mergeRetries; clear stale busy-reenqueue counter on real partial land;
  persist retry count before arming the backoff timer (fail closed on write error)
- cli/dashboard + task: use shared isWorkspaceTask predicate instead of inlining
- base-commit-capture: POSIX single-quote shell escaping for integration ref
- git-repository: validate workspace.json repos elements are strings
- merger-ai: drop dead store param from landOneRepo
- tests: assert the 60s backoff cap across cycles; exercise the real runAiMerge
  merge door; fix non-git-root assertion; re-export real workspace error classes
  in the merger-ai mock (fixes 24 pre-existing instanceof-undefined failures);
  remove generic fake-timer smoke test now covered by the live engine assertion

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 03:04:21 -07:00
gsxdsm
627bdcfb0a fix(review): Phase C merge-loop hardening — double-land, lease clobber, retry storm
5-persona review of the Phase-C per-repo merge loop. No P0; the no-push invariant
and retry/park accounting verified clean. Fixed:

Land mechanics (merger-ai.ts / active-session-registry.ts):
- persistRepoLandedSha no longer swallows the DB write: a failed landedSha write
  after the ref advanced now escalates to WorkspacePartialLandError so the engine
  parks/retries instead of silently re-landing (duplicate squash). isRepoLanded
  gains a landedSha-independent fallback — it scans the integration ref for this
  task's Fusion-Task-Id trailer (a squash commit is NOT a branch descendant, so a
  branch-ancestor check is provably wrong), so an actually-landed repo is skipped
  on retry.
- The land lease is now taskId-aware across kinds: any foreign-task holder on a
  sub-repo path is contention (a merging task can't run over an executing task's
  acquire lease), and registerPath throws ActiveSessionPathHeldByForeignTaskError
  instead of silently clobbering a different task's entry.
- The per-repo loop is wrapped in try/finally(setStatus(null)) so the busy/partial
  throws can't leave the task stuck 'merging'. WorkspacePartialLandError is a real
  exported class (not a .name-mutated Error). finalizeWorkspaceTask re-reads fresh
  and no longer swallows the mergeDetails write (TOCTOU). isRepoLanded exported for
  Phase D.

Dispatch + doors (project-engine.ts / dashboard.ts / task.ts / @fusion/core):
- getTask-null in the partial-land catch fails closed (park) instead of defaulting
  retries to 0 and scheduling an indefinite retry storm.
- The merge-confirmed reachability fast-path skips workspace tasks (its
  representative commitSha is a sub-repo squash sha, unreachable in the root cwd —
  it was demoting fully-merged tasks); they're verified by per-repo landedSha.
- The CLI/dashboard merge doors now return merged:true on full land (were hardcoded
  merged:false). WorkspaceRepoLandBusyError re-enqueues with backoff WITHOUT burning
  the mergeRetries quota (bounded busy counter) so contention can't park a healthy
  task. Backoff capped at 60s. shouldRetryWorkspacePartialLand folded into
  shouldRetryAutoMergeConflict. Catch switched to instanceof. New canonical
  isWorkspaceTask predicate in @fusion/core.

Gate green: build, typecheck, lint, test:gate (649+58); workspace-merger + oracle
+ project-engine 174.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:11:52 -07:00
gsxdsm
429258354d fix(workspace): address CodeRabbit review findings on the foundation
Resolves the actionable CodeRabbit threads on the workspace-mode foundation:

- project-resolver: defer saveWorkspaceConfig until after the user confirms init
  and store.init() succeeds (no partial .fusion/ on a declined/non-interactive run).
- git-repository: validate each candidate with a real `git rev-parse` work-tree
  probe before counting it (no false-positive repos from stray .git markers);
  loadWorkspaceConfig now rejects absolute paths, `..` escapes, and non-string
  entries so a corrupt/malicious config can't resolve outside the workspace root.
- executor: gate workspace mode on repos.length > 0 at all three sites so an
  empty { repos: [] } can't bypass the git-repo guard or enable an empty workspace.
- worktree-acquisition: thread the configured-command runner through the workspace
  acquire path (sub-repos run their init setup); validate repoRelPath as an in-root
  relative path before joining; liveness-check a remembered worktree before
  reporting it ready (pruned paths fall through to re-acquire); clear the singular
  task.worktree/branch after persisting per-repo state (per-repo state lives only
  in workspaceWorktrees).
- agent-tools: forward runContext into acquireWorkspaceRepoWorktree for log attribution.

The executor-workspace test's mock-the-subject pattern is left for the
session-scoping follow-up that rewrites it with a real two-repo fixture (FN-5048).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:09:59 -07:00
gsxdsm
7544346320 feat(workspace): Phase C U2 — per-repo landed predicate, finalize-once, auto-retry-then-park
landWorkspaceTask now tracks per-repo landing and finalizes the task exactly once.
After a repo lands, its advanced integration tip is persisted as
workspaceWorktrees[repo].landedSha (fresh-read merge, siblings untouched). Before
landing, isRepoLanded skips a repo iff its landedSha is present AND an ancestor of
(or equal to) its local integration ref — so a retry after a partial land never
re-advances an already-landed ref. finalizeWorkspaceTask runs only when every
acquired repo is landed: it builds an aggregate MergeResult (representative
commitSha + a workspaceLandedShas map in MergeDetails) and calls the existing
task-global finalizeTask once, satisfying the task:merged consumer. No premature
done on the first repo.

Partial lands surface as WorkspacePartialLandError; the engine consumes a
mergeRetry and re-enqueues landWorkspaceTask (skipping landed repos) with the
existing conflict-retry backoff up to MAX, then operator-parks (status:failed) —
mirroring shouldRetryAutoMergeConflict (new exported shouldRetryWorkspacePartialLand
seam). The defense-in-depth WorkspaceTaskMergeError still hard-fails without
burning retries; manual merges fall through to rejectMergeResolvers.

types: workspaceWorktrees entry gains landedSha?; MergeDetails gains
workspaceLandedShas?. 6 new idempotency/predicate/finalize-once/retry-park tests;
oracle (52) + U1 (5) stay green. Gate: build, typecheck, lint, test:gate (649+58).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 23:46:44 -07:00
gsxdsm
bb663a4705 FN-6906: improve non-coding workflow artifact prompts
Non-coding built-in workflows now guide agents toward structured, reviewable artifacts.

- Expand marketing and lead-generation prompts with explicit inputs, output structure, quality bars, and persisted task-document deliverables.
- Require design execution to persist a reviewable preview document and update design review guidance to inspect it.
- Document the new artifact-oriented behavior and cover prompt routing with regression tests while preserving coding workflow defaults.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-6906-non-coding-workflow-prompts.md  |  5 +++++
 docs/workflow-steps.md                             | 11 +++++++----
 .../builtin-lead-generation-workflow-ir.test.ts    |  2 ++
 .../core/src/__tests__/builtin-workflows.test.ts   | 22 ++++++++++++++++++++++
 .../src/builtin-lead-generation-workflow-ir.ts     | 13 ++++++++-----
 packages/core/src/builtin-marketing-workflow-ir.ts |  9 ++++++---
 packages/core/src/builtin-workflows.ts             | 16 ++++++++++++++--
 7 files changed, 64 insertions(+), 14 deletions(-)

Fusion-Task-Id: FN-6906
Fusion-Task-Lineage: 76f39350-e441-4dde-8571-35a6fbf6fcda
2026-06-21 23:15:46 -07:00
gsxdsm
43421722a5 FN-6904: name CE slash commands in built-in workflow prompts
Built-in compound-engineering workflow prompts now point agents at the intended /ce- skill commands directly.

- Prefix each compound-engineering skill stage prompt with its matching /ce- slash command.
- Add workflow coverage that verifies every skill-node prompt names the expected command while the merge boundary stays generic.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-6904-ce-workflow-prompt-skill-callout.md |  5 +++++
 packages/core/src/__tests__/builtin-workflows.test.ts  | 18 ++++++++++++++++++
 packages/core/src/builtin-workflows.ts                 | 16 ++++++++++------
 3 files changed, 33 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-6904
Fusion-Task-Lineage: c1d8c9cd-c0ae-49a0-a287-48721490f41f
2026-06-21 22:51:07 -07:00
gsxdsm
26c8d960a2 FN-6893: add editable built-in workflow prompts
Enable project-scoped prompt overrides for built-in workflows without allowing structural edits.

- Add workflow prompt override storage, normalization, and IR overlay support for prompt and gate nodes.
- Expose dashboard API routes and Workflow Node Editor controls to edit or reset built-in prompts.
- Cover override persistence, route behavior, editor flows, and engine workflow resolution with tests.
- Document editable built-in prompts and reset-to-default behavior.

Files changed:
 docs/dashboard-guide.md                            |   2 +-
 docs/settings-reference.md                         |   2 +
 docs/workflow-steps.md                             |  20 ++-
 .../__tests__/workflow-definition-store.test.ts    |  25 +++
 .../workflow-prompt-overrides-store.test.ts        | 190 ++++++++++++++++++++
 .../__tests__/workflow-prompt-overrides.test.ts    |  58 +++++++
 packages/core/src/db.ts                            |  35 +++-
 packages/core/src/index.ts                         |   7 +
 packages/core/src/store.ts                         |  97 ++++++++++-
 packages/core/src/workflow-ir-resolver.ts          |  21 ++-
 packages/core/src/workflow-prompt-overrides.ts     |  65 +++++++
 packages/dashboard/app/api/legacy.ts               |  34 ++++
 .../app/components/WorkflowNodeEditor.css          |  35 ++++
 .../app/components/WorkflowNodeEditor.tsx          | 191 ++++++++++++++++++++-
 .../__tests__/WorkflowNodeEditor.test.tsx          | 136 ++++++++++++++-
 .../src/__tests__/workflow-routes.test.ts          |  59 +++++++
 .../src/routes/register-workflow-routes.ts         |  86 +++++++++-
 .../workflow-prompt-overrides-resolution.test.ts   |  61 +++++++
 packages/i18n/locales/en/app.json                  |  14 +-
 packages/i18n/locales/es/app.json                  |  14 +-
 packages/i18n/locales/fr/app.json                  |  14 +-
 packages/i18n/locales/ko/app.json                  |  14 +-
 packages/i18n/locales/zh-CN/app.json               |  14 +-
 packages/i18n/locales/zh-TW/app.json               |  14 +-
 24 files changed, 1168 insertions(+), 40 deletions(-)

Fusion-Task-Id: FN-6893

Fusion-Task-Lineage: 961eb119-32e1-44c3-9b51-6edd982fa565
2026-06-21 21:23:41 -07:00
gsxdsm
12d33c512d feat(workspace): Phase A U2 — per-repo acquisition hardening
acquireWorkspaceRepoWorktree now hardens each sub-repo worktree at acquisition:
(1) installs the identity guard with the executor's settings args
(commitMsgHookEnabled/taskPrefix/taskAttributionTrailerName) for single-repo
parity — it was installing no guard before; (2) captures a per-repo
baseCommitSha local-first against the repo's resolved integration branch via
resolveIntegrationBranch(repoAbsPath, {...settings, integrationBranch: undefined})
— stripping the shared override so each sub-repo falls through to its own
origin/HEAD, not a project-wide branch; (3) persists baseCommitSha into the
workspaceWorktrees[repo] entry (Task type extended); (4) registers same-sub-repo
exclusivity on the sub-repo path via activeSessionRegistry under a distinct
"workspace-repo-acquire" kind (released in finally), so two concurrent workspace
tasks contending for the same sub-repo are serialized (throws
WorkspaceRepoAcquireBusyError). Idempotent re-acquire short-circuits.

resolveCapturedBaseCommitSha gains an optional trailing integrationBranch param
defaulting to "main", so existing single-repo callers + base-commit-capture
real-git tests stay green. New audit events worktree:workspace-repo-acquire-busy
/-failed. 6 new real-fixture tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:17:08 -07:00