Add explicit OpenAI Codex pricing so token analytics can estimate Codex run costs.
- Add openai-codex pricing entries for GPT-5 Codex variants and codex-mini-latest.
- Bump the pricing verification date and document why Codex keys must use the openai-codex provider.
- Cover Codex pricing and lookup behavior in model-pricing tests.
- Add a changeset for the published Fusion package.
Files changed:
.changeset/fn-6869-codex-pricing.md | 7 ++++
packages/core/src/__tests__/model-pricing.test.ts | 37 ++++++++++++++++++-
packages/core/src/model-pricing.ts | 44 ++++++++++++++++++++++-
3 files changed, 86 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-6869
Fusion-Task-Lineage: 4bf119db-0401-4b18-b389-4a762e665cfc
Raise the footer engine control sliders to support higher concurrency without hiding persisted values.
- Increase max tasks, max triage, and max worktree slider baselines to 50.
- Preserve value-aware slider maxima for persisted settings above the new baseline.
- Add coverage for in-range 50 limits, above-range persisted values, and saving a value of 50.
Files changed:
.../dashboard/app/components/EngineControlMenu.tsx | 9 ++--
.../__tests__/EngineControlMenu.test.tsx | 50 +++++++++++++++++++---
2 files changed, 49 insertions(+), 10 deletions(-)
Fusion-Task-Id: FN-6863
Fusion-Task-Lineage: f42373fc-322b-4d20-9b8b-2d0c63254e79
Make dashboard toast status text readable across themed dark and light modes.
- Add toast text tokens and Shadcn-specific success/info color overrides that preserve contrast.
- Cover success, error, and info toast contrast across all Shadcn variants and mobile toast styling.
- Add a patch changeset for the published Fusion package.
Files changed:
.changeset/fn-6858-toast-contrast.md | 5 +
.../app/__tests__/toast-theme-contrast.test.ts | 320 +++++++++++++++++++++
packages/dashboard/app/styles.css | 44 ++-
3 files changed, 368 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-6858
Fusion-Task-Lineage: 1c06e346-9269-4965-a3ae-4ac02b43188e
Restores touch-friendly horizontal scrolling for the Git Manager mobile section toolbar.
- Opt the Git Manager mobile sidebar back into horizontal touch panning and momentum scrolling.
- Prevent Git Manager mobile nav items from shrinking so every section remains reachable.
- Add mobile CSS coverage for the Git Manager toolbar scroll contract.
Files changed:
packages/dashboard/app/components/ScriptsModal.css | 12 ++++++++++++
.../components/__tests__/core-modals-mobile.test.tsx | 19 +++++++++++++++++++
2 files changed, 31 insertions(+)
Fusion-Task-Id: FN-6857
Fusion-Task-Lineage: 8967bdd2-e830-4f2d-8cde-c96ccc80d67a
Command Center scheduler controls now expose a default slider ceiling of 50 without hiding higher persisted values.
- Set max concurrent tasks, max triage concurrency, and max worktrees sliders to default to a maximum of 50.
- Preserve dynamic slider maxima for persisted settings above 50 so existing out-of-range values remain visible.
- Add regression coverage for persisting 50, in-range slider maxima, and above-range readouts.
Files changed:
.../command-center/CommandCenterControls.tsx | 9 ++-
.../__tests__/CommandCenterControls.test.tsx | 71 +++++++++++++++++++---
2 files changed, 67 insertions(+), 13 deletions(-)
Fusion-Task-Id: FN-6855
Fusion-Task-Lineage: 780d5322-5f3c-4503-9ec7-17716e966961
Update the pi SDK dependency family across Fusion packages and record a patch changeset.
- Bump @earendil-works/pi-ai and @earendil-works/pi-coding-agent to ^0.79.9 where used by CLI, dashboard, and engine packages.
- Refresh pnpm-lock.yaml to resolve the updated pi SDK dependency graph.
- Add a patch changeset for the published @runfusion/fusion package.
Files changed:
.changeset/fn-6853-pi-sdk-bump.md | 5 +
packages/cli/package.json | 4 +-
packages/dashboard/package.json | 2 +-
packages/engine/package.json | 4 +-
pnpm-lock.yaml | 285 +++++++++++++++++++++++++++-----------
5 files changed, 214 insertions(+), 86 deletions(-)
Fusion-Task-Id: FN-6853
Fusion-Task-Lineage: bc2dba95-b8c2-48d1-855d-847e6eec9606
Left sidebar navigation now defaults on for non-mobile project screens while preserving an explicit opt-out.
- Treat an unset leftSidebarNav flag as enabled in the App desktop/tablet gate.
- Show the Settings experimental toggle checked by default and save false when users opt out.
- Extend regression coverage across unset/true/false flag states, desktop/tablet/mobile surfaces, and header suppression.
- Update dashboard guide documentation for the default-on behavior and opt-out flag.
Files changed:
docs/dashboard-guide.md | 4 +-
packages/dashboard/app/App.tsx | 5 +-
.../mobile-feature-access-regression.test.tsx | 69 ++++++++++++++++++----
.../dashboard/app/components/SettingsModal.tsx | 16 ++++-
.../components/__tests__/SettingsModal.test.tsx | 39 ++++++++++++
5 files changed, 119 insertions(+), 14 deletions(-)
Fusion-Task-Id: FN-6843
Fusion-Task-Lineage: 44d73b9e-92aa-4381-883b-c42714bd7f99
Render the Command Center Team org chart horizontally when its container has room.
- Measure the Team org-chart viewport and reuse the shared Agents org-chart layout resolver.
- Add horizontal and vertical data-layout styling for Team org-chart roots and children.
- Cover wide, narrow, unmeasured, loading, error, empty, and single-root Team org-chart states.
- Document the Team org-chart horizontal layout behavior.
Files changed:
docs/dashboard-guide.md | 2 +-
.../components/command-center/areas/TeamArea.tsx | 38 ++++++++++-
.../command-center/areas/__tests__/areas.test.tsx | 77 ++++++++++++++++++++++
.../app/components/command-center/areas/areas.css | 36 +++++++++-
4 files changed, 149 insertions(+), 4 deletions(-)
Fusion-Task-Id: FN-6870
Fusion-Task-Lineage: b023788a-a353-4b10-ad68-a661e72e5be6
Move the desktop and tablet search toggle to follow the workflow portal slot.\n\n- Reorder the non-mobile header search button after the workflow portal mount point.\n- Preserve the mobile search trigger position and behavior.\n- Add header tests covering empty, populated, tablet, and mobile slot behavior.\n\nFiles changed:\n packages/dashboard/app/components/Header.tsx | 29 ++++++++-------\n .../app/components/__tests__/Header.test.tsx | 42 ++++++++++++++++++++--\n 2 files changed, 56 insertions(+), 15 deletions(-)
Fusion-Task-Id: FN-6846
Fusion-Task-Lineage: 294100b1-76ae-4c46-b4b3-e4c83e4a55f8
Align the left sidebar selected and resize states with each active dashboard theme.
- Switch active left-sidebar item color and background to the shared --accent token.
- Update the resize-handle focus and hover accent to follow theme accent colors.
- Add a CSS regression test and documentation for the theme-accent invariant.
- Define shared typography tokens and replace an optional-step danger fallback with an existing error token.
Files changed:
docs/dashboard-guide.md | 2 +-
.../left-sidebar-active-accent.css.test.ts | 38 ++++++++++++++++++++++
.../dashboard/app/components/LeftSidebarNav.css | 10 +++---
.../app/components/WorkflowOptionalStepsPanel.css | 2 +-
packages/dashboard/app/styles.css | 3 ++
5 files changed, 48 insertions(+), 7 deletions(-)
Fusion-Task-Id: FN-6830
Fusion-Task-Lineage: add8e9cd-4b91-45a1-a848-a54dd1083723
Keep the desktop usage popover pinned near the board header regardless of viewport height or anchor position.
- Replace the viewport-ratio top cap with a small fixed near-top limit derived from the header inset.
- Update desktop popover positioning expectations for anchored, tall-viewport, and modal fallback cases.
- Cover low-anchor tall viewport behavior so the popover stays near the top of the board.
Files changed:
.../dashboard/app/components/UsageIndicator.tsx | 15 ++++-----
.../components/__tests__/UsageIndicator.test.tsx | 38 +++++++++++++++++++---
2 files changed, 40 insertions(+), 13 deletions(-)
Fusion-Task-Id: FN-6833
Fusion-Task-Lineage: 907c08fc-4da9-4b15-80aa-6c638900df15
Allow the dashboard left sidebar to resize down to a compact but still labeled width.
- Lower the resizable left sidebar minimum width from 192px to 160px.
- Keep narrow sidebar labels truncated so badges and toggles stay aligned.
- Cover drag, keyboard, and persisted-width clamping at the new minimum.
Files changed:
.../dashboard/app/components/LeftSidebarNav.css | 4 +++
.../dashboard/app/components/LeftSidebarNav.tsx | 5 ++-
.../components/__tests__/LeftSidebarNav.test.tsx | 37 ++++++++++++++++++++++
3 files changed, 45 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-6836
Fusion-Task-Lineage: e136647f-3cd8-4b82-8186-b69d630946fc
Keep the dashboard project footer height token scoped with the footer-safe padding contract.
- Preserve the project shell footer-height token for sibling layout consumers.
- Co-locate the desktop footer-height token with the project content padding consumer.
- Repeat the mobile footer-height override where concatenated CSS order can otherwise restore the desktop value.
Files changed:
.../dashboard/app/components/ProjectSelector.css | 43 +++++++++++++++-------
1 file changed, 30 insertions(+), 13 deletions(-)
Fusion-Task-Id: FN-6838
Fusion-Task-Lineage: 0c20437f-7c58-478c-a721-ba963343c995
Keep the footer engine controls popover opaque by using valid dashboard CSS tokens.
- Replace the undefined elevated surface token with the solid card surface.
- Align disabled action opacity, range accent, and mobile height CSS with defined tokens/values.
- Add a CSS token regression test for the engine control menu popover.
Files changed:
.../dashboard/app/components/EngineControlMenu.css | 8 +-
.../dashboard/app/components/EngineControlMenu.tsx | 3 +
.../__tests__/EngineControlMenu.css.test.ts | 99 ++++++++++++++++++++++
3 files changed, 106 insertions(+), 4 deletions(-)
Fusion-Task-Id: FN-6862
Fusion-Task-Lineage: 5e41177a-6fc5-48d0-861d-fefbcfca7060
stuckKillCount is a lifetime counter — incremented by self-healing on each stuck-kill
and reset ONLY by a manual retry — so a long task that genuinely advances between
intermittent stalls could be terminalized by accumulation toward maxStuckKills (default 6),
even though it is making progress.
Reset the streak in TaskStore.updateStep when a step reaches a terminal forward status
(done/skipped), the single chokepoint every step-completion surface routes through (legacy
fn_task_update, graph markStepDone, fn_task_done). It deliberately does NOT rescue a task
wedged re-running the same failing step — no step completes between those kills, so it still
terminalizes as designed; it only bounds the budget to consecutive stalls. Complements the
verification fan-out cap (PR #1708) that keeps verification fast in the first place.
New regression suite asserts reset on done/skipped/graph-source-done and NO reset on
in-progress advance or ignored out-of-order transitions. Merge gate + full @fusion/core
suite (6242 tests) + engine self-healing/stuck-detector (442 tests) green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tighten the executor agent guidance and the fn_run_verification tool guidance so
verification stays scoped to changed files instead of running the full workspace
test suite, which (for a foundational-package edit) reverse-expands across the
whole workspace and stalls the task.
- agent-prompts.ts: remove the "during final integration" blanket permission to
run workspace-wide suites; name the forbidden full-run commands explicitly.
- run-verification-tool.ts: strengthen BOUNDED_VERIFICATION_GUIDANCE to forbid
`pnpm test:full` / `pnpm verify:workspace` / whole-package runs as verification.
Engine + core typecheck pass; run-verification-command and executor-review-verdicts
prompt-assertion suites stay green (93 tests).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-test `createTaskStoreTestHarness` recreated a TaskStore from scratch
every test — mkdtemp ×2 + new store + recursive rm with retry backoff — which
dominated wall-clock across these high-test-count files. Switch the files that
tolerate a shared store to `createSharedTaskStoreTestHarness`, which builds the
store once and resets state between tests via full table truncation + FTS
rebuild + filesystem reset, preserving isolation.
Measured on store-create.test.ts (53 tests): 4.44s → 1.78s wall
(test execution 3.59s → 0.93s, ~3.9x). Full @fusion/core suite stays green
(346 files, 6236 tests) and typecheck passes.
19 files that test disk persistence / migration / workflow-definition state are
incompatible with a shared in-memory store and were intentionally left on the
per-test harness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Read hasResumableProgress from latestTask (the store snapshot fetched
at ~9226), not the frozen dispatch-time task param, so a freshly
dispatched task that commits step progress mid-session is preserved on
a hard-cancel teardown — not just the re-dispatch case (greptile P1)
- Add companion regression test for the fresh-task-with-in-session-progress
case, which fails against the stale-task snapshot (greptile P1)
- Reformat the requirement comment block to the canonical FNXC heading
(FNXC:WorkflowLifecycle yyyy-MM-dd-hh:mm:) convention (CodeRabbit)
Fusion-Task-Id: FN-6722
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the engine aborted in-flight work mid-execution and bounced the task
back to `todo`, the single-session teardown cleared the task `branch` and
re-queued without `preserveResumeState` — resetting every step to `pending`
(store.moveTaskInternal resetAllStepsToPending) and dropping the pointer to
the commits already on the task branch. The next dispatch then re-planned
from Step 0 and the committed work was stranded, observed as FN-6722 losing
all its progress and getting stuck in todo.
The teardown now keeps the branch and moves with `preserveResumeState`
whenever the task has resumable step progress, matching the sibling
step-session (executor ~8065) and pause-park (executor ~1826) paths, so
execute() resumes onto the existing branch from the first incomplete step.
The worktree is still removed to free its concurrency slot (FN-6782) — only
the durable pointers (branch + step state) are kept.
Adds a regression test driving the exact single-session catch teardown.
Fusion-Task-Id: FN-6722
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Many loading states rendered bare "Loading…" text with no spinner
element, and a couple rendered an unstyled `loading-spinner` div with no
matching CSS (invisible). The global spin animation was never broken —
it rotates in Chromium and WebKit — so prior transform-box edits chased
a non-bug, validated only by a string-matching CSS test.
Add a shared <LoadingSpinner> (self-contained animated SVG, no
lucide-react import so it survives partial test mocks) and adopt it
across ~47 loading placeholders so every loading state shows a
consistent animated spinner. Includes a component test that asserts the
svg carries the animate-spin utility.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the left sidebar collapse control into the footer so it sits above Settings with row-style behavior.
- Replace the floating border collapse button with a footer row button that keeps accessible expanded/collapsed labels.
- Retokenize collapse toggle CSS around shared sidebar item styling and remove the obsolete floating modifier.
- Extend sidebar tests and dashboard guide coverage for the footer placement and collapsed rail behavior.
Files changed:
docs/dashboard-guide.md | 4 +-
.../dashboard/app/components/LeftSidebarNav.css | 24 ++--------
.../dashboard/app/components/LeftSidebarNav.tsx | 32 ++++++-------
.../components/__tests__/LeftSidebarNav.test.tsx | 54 ++++++++++++++++++++--
4 files changed, 72 insertions(+), 42 deletions(-)
Fusion-Task-Id: FN-6847
Fusion-Task-Lineage: 5d7781a1-afc9-4e5c-bf7b-0648bb874285
Refine the desktop list split pane so narrower sidebars still show readable task titles.
- Lower the list-view sidebar minimum width from 280px to 200px across resize and keyboard handling.
- Clamp desktop list task titles to two wrapped lines with overflow protection.
- Update ListView coverage for the smaller persisted/keyboard minimum and title-clamp CSS.
Files changed:
packages/dashboard/app/components/ListView.css | 10 +++++++++-
packages/dashboard/app/components/ListView.tsx | 2 +-
.../app/components/__tests__/ListView.test.tsx | 22 +++++++++++++++++-----
3 files changed, 27 insertions(+), 7 deletions(-)
Fusion-Task-Id: FN-6831
Fusion-Task-Lineage: ac3e455d-8cb0-4f42-ac5c-d735e56d2b89
Ensure the Command Center theme selector renders above neighboring views while preserving mobile in-flow behavior.
- Add an open state class to the theme dropdown root for local stacking control.
- Raise the open dropdown and popover above Command Center sibling cards without exceeding app chrome layers.
- Cover desktop elevation and mobile static popover behavior in ThemeDropdown tests.
Files changed:
.../dashboard/app/components/ThemeDropdown.css | 15 +++++++-
.../dashboard/app/components/ThemeDropdown.tsx | 2 +-
.../components/__tests__/ThemeDropdown.test.tsx | 40 ++++++++++++++++++++++
3 files changed, 55 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-6826
Fusion-Task-Lineage: ff43c06e-f3a7-4b4c-8e29-46deb66e9145
Move externalEngines.delete(projectId) to immediately after acquiring the
singleton lock instead of after engine.start() succeeds. If a project was
marked external, the holder exits, acquire succeeds, but start() then throws,
the success-path delete never ran and hasRunningEngine() reported a phantom
engine forever. Added a regression test for the failed-takeover path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Stop reconciliation/startAll/onProjectAccessed from warning every tick for
externally-owned engines: swallow EngineAlreadyRunningError in the outer
catches (it's expected and already logged once in createAndStart)
- Add FNXC:DashboardHealth requirement-trace comments on the externalEngines
field and the dashboard hasRunningEngine health check
- Add regression test: reconciliation stays quiet across ticks for an
externally-owned engine (inner refusal logged once, outer failure suppressed)
- Add regression test: hasDashboardEngine legacy fallback to getAllEngines when
hasRunningEngine is unavailable on the manager
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- FNXC requirement-trace comments on the stepwise workflow-step seam,
the flowToIr v2-signal/byte-identity contract, and TaskForm's
optional-steps create-mode behavior
The dashboard's engine-availability health check only counted engines
this process started. A second launch (e.g. `pnpm dev dashboard`
alongside an already-running `fusion`) is correctly refused the
per-machine engine singleton lock, so its engine map stays empty and
the dashboard showed a false "engine not running" banner even though an
engine was live on the machine.
ProjectEngineManager now records projects whose singleton lock is held
by another process (via EngineAlreadyRunningError) and exposes
hasRunningEngine(), which the health endpoint consults so the banner
reflects machine-level truth. Reconciliation still retries so this
process takes over if the other exits, and the "refusing to start" log
fires once per project instead of on every 30s reconciliation tick.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>