Commit Graph

11493 Commits

Author SHA1 Message Date
gsxdsm
969fce7aa1 FN-8047: migrate AgentStore multi-node tests to PostgreSQL
Migrate multi-node AgentStore coverage to shared PostgreSQL-backed fixtures.

- Make concurrent central claim insertion resolve unique-key races as checkout conflicts.
- Rework claim and owning-node handoff tests to use shared async PostgreSQL layers.
- Restore PostgreSQL-compatible tests from the quarantine ledger.

Files changed:
 packages/core/src/async-central-db.ts              |  9 ++-
 .../cross-node-claim-mutex.integration.test.ts     | 72 ++++++++++---------
 .../distributed-claim-mutex.integration.test.ts    | 27 +++----
 .../owning-node-handoff.integration.test.ts        | 41 +++++------
 .../__tests__/reliability-interactions/_helpers.ts | 83 ++++++++++++++++++++--
 .../multi-node-claim-mutex-interactions.test.ts    | 28 +++-----
 .../owning-node-unavailable-interactions.test.ts   | 36 +++++-----
 packages/engine/vitest.config.ts                   |  8 +--
 scripts/lib/test-quarantine.json                   | 25 -------
 9 files changed, 180 insertions(+), 149 deletions(-)

Fusion-Task-Id: FN-8047

Fusion-Task-Lineage: 3b7ee21e-0190-4364-a0cb-88aac5e2e1a3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 05:33:55 -07:00
gsxdsm
92a8dc8325 FN-8091: migrate CLI plugin persistence test to PostgreSQL
Move the CLI plugin-install persistence coverage to the shared PostgreSQL test harness.

- Replace SQLite central and local database assertions with PostgreSQL schema queries.
- Assert global installation and project-scoped state persistence without a local plugin store.
- Clean up temporary plugin fixtures after the PostgreSQL test.

Files changed:
 packages/cli/src/commands/__tests__/plugin.test.ts | 120 +++++++++++----------
 1 file changed, 64 insertions(+), 56 deletions(-)

Fusion-Task-Id: FN-8091

Fusion-Task-Lineage: 99b8d1da-54b7-4cd3-a086-9e4461a8aa06

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 05:27:47 -07:00
gsxdsm
19ab7a9e93 FN-8068: add input-language task definitions
Add an opt-in setting that localizes planner-authored task-definition prose.

- Detect confident Spanish, French, Korean, and Chinese input before instructing triage localization.
- Expose and persist the project-level task-definition language toggle with translations and search support.
- Preserve English structural markers, code, and unsupported or uncertain input for deterministic parsing.

Files changed:
 .../fn-8068-task-definition-input-language.md      |  7 +++
 docs/settings-reference.md                         |  1 +
 packages/core/src/settings-schema.ts               |  7 +++
 packages/core/src/types.ts                         | 10 ++++
 .../app/__tests__/settings-sections.test.tsx       | 18 ++++++
 .../dashboard/app/components/SettingsModal.tsx     |  4 ++
 .../__tests__/SettingsModal.mobileClose.test.tsx   | 12 ++++
 .../__tests__/SettingsModal.models-auth.test.tsx   | 11 ++++
 .../app/components/settings/section-keys.ts        |  1 +
 .../sections/ProjectModelsSection.search.ts        | 10 ++++
 .../settings/sections/ProjectModelsSection.tsx     | 17 ++++++
 .../settings-default-descriptions.test.tsx         |  1 +
 packages/engine/src/__tests__/triage.test.ts       | 64 ++++++++++++++++++++++
 packages/engine/src/triage.ts                      | 29 +++++++++-
 packages/i18n/locales/en/app.json                  |  2 +
 packages/i18n/locales/es/app.json                  |  2 +
 packages/i18n/locales/fr/app.json                  |  2 +
 packages/i18n/locales/ko/app.json                  |  2 +
 packages/i18n/locales/zh-CN/app.json               |  2 +
 packages/i18n/locales/zh-TW/app.json               |  2 +
 packages/i18n/src/resources.d.ts                   |  2 +
 21 files changed, 205 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8068

Fusion-Task-Lineage: fe0102f5-68cb-443c-8512-2ffa5fe0e2f8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 05:18:30 -07:00
gsxdsm
72378cb4f2 FN-8037: add resizable image preview windows
Make pending task images compact and inspectable across task creation surfaces.

- Extract shared pending-image thumbnail controls for Quick Add, Task Form, and inline creation.
- Open full images in a responsive, movable, resizable FloatingWindow with Escape focus restoration.
- Add styling, coverage, operator documentation, and a minor changeset.

Files changed:
 .changeset/fn-8037-image-preview-modal.md          |   7 ++
 docs/dashboard-guide.md                            |   4 +-
 .../quick-entry-image-preview-modal.test.tsx       |  60 ++++++++++
 .../dashboard/app/components/FloatingWindow.css    |  22 ++++
 .../dashboard/app/components/InlineCreateCard.css  |  14 ++-
 .../dashboard/app/components/InlineCreateCard.tsx  |  26 ++---
 .../app/components/PendingImagePreviews.css        |  35 ++++++
 .../app/components/PendingImagePreviews.tsx        | 121 +++++++++++++++++++++
 .../dashboard/app/components/QuickEntryBox.tsx     |  27 ++---
 packages/dashboard/app/components/TaskForm.tsx     |  26 ++---
 10 files changed, 280 insertions(+), 62 deletions(-)

Fusion-Task-Id: FN-8037
Fusion-Task-Lineage: 3d92f695-67c9-4791-bfcc-ad25f6aa56f4
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 04:58:03 -07:00
gsxdsm
5b4ec4c08f FN-8042: add merger fallback model lane
Add configurable project fallback models for AI merger retries.

- Resolve complete project merger fallback pairs before the shared global fallback.
- Expose merger fallback model and thinking controls in Project Models with reset-aware persistence.
- Apply the fallback lane across merger, review, PR-response, and recovery sessions with tests and documentation.

Files changed:
 .changeset/fn-8042-merger-fallback-model.md        |  7 +++
 docs/settings-reference.md                         |  4 +-
 .../core/src/__tests__/model-resolution.test.ts    | 24 ++++++++++
 .../core/src/__tests__/settings-parity.test.ts     |  3 ++
 packages/core/src/index.gate.ts                    |  1 +
 packages/core/src/index.ts                         |  1 +
 packages/core/src/model-resolution.ts              | 22 +++++++++
 packages/core/src/settings-schema.ts               |  4 ++
 packages/core/src/types.ts                         | 13 ++++++
 .../app/__tests__/settings-save-split.test.ts      | 41 +++++++++++++++++
 .../app/__tests__/settings-sections.test.tsx       | 36 +++++++++++++++
 .../app/components/settings/save-split.ts          |  7 +--
 .../settings/sections/ProjectModelsSection.tsx     | 53 +++++++++++++++++++++-
 .../settings-default-descriptions.test.tsx         |  3 ++
 .../src/__tests__/agent-session-helpers.test.ts    |  1 +
 .../__tests__/mcp-pr-response-forwarding.test.ts   |  1 +
 packages/engine/src/agent-session-helpers.ts       | 10 +++-
 packages/engine/src/merger-ai.ts                   | 17 +++++--
 packages/engine/src/merger.ts                      | 43 +++++++++++++-----
 packages/engine/src/pr-response-run-ops.ts         | 11 +++--
 20 files changed, 276 insertions(+), 26 deletions(-)

Fusion-Task-Id: FN-8042

Fusion-Task-Lineage: 31762a72-461e-438c-a12d-2816580283fd

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 04:29:17 -07:00
gsxdsm
b885aff4fd FN-8043: migrate deprecated dashboard text tokens
Replace undefined dashboard secondary-text aliases with the canonical muted token.

- Update CLI provider labels and workflow lifecycle warning chips
- Add regression coverage for deprecated token use across base and light themes
- Add a patch changeset for the dashboard styling fix

Files changed:
 .changeset/fn-8043-text-secondary-token-migration.md      |   7 ++
 ...precated-text-secondary-token-migration.test.ts | 103 +++++++++++++++++++++
 .../app/components/CursorCliProviderCard.css       |   6 +-
 .../app/components/GrokCliProviderCard.css         |   6 +-
 .../app/components/OmpCliProviderCard.css          |   6 +-
 .../app/components/WorkflowNodeEditor.css          |   6 +-
 6 files changed, 130 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8043

Fusion-Task-Lineage: 95936078-a40b-4815-bb85-f9597d65ac35

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 04:15:18 -07:00
gsxdsm
de05cb7566 FN-8039: update responsive task detail tab expectation
Align the responsive TaskDetailModal tab-order assertion with the rendered tab set.

- Include Terminal and Cost between Comments and Artifacts in the responsive tab list.
- Document why the regression expectation includes the always-available tabs.

Files changed:
 .../__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx     | 3 +++
 1 file changed, 3 insertions(+)

Fusion-Task-Id: FN-8039

Fusion-Task-Lineage: 86f347a7-ca5a-4a83-8616-4ca303cc6115

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 04:10:16 -07:00
gsxdsm
3f133e0b13 FN-8058: add task agent log reader
Expose paginated, filterable persisted agent logs to task-scoped and chat agent sessions.

- Add the read-only fn_task_logs_read tool across engine, dashboard chat/planning, heartbeat, step, and CLI extension surfaces.
- Filter agent-log entries before pagination, report matching totals, and render complete persisted rows for diagnosis.
- Document the tool, add release metadata, regression coverage, and complete affected engine mocks.

Files changed:
 .changeset/fn-8058-task-logs-read.md               |  7 ++
 docs/agents.md                                     |  4 +-
 packages/cli/skill/fusion/SKILL.md                 |  2 +-
 .../cli/skill/fusion/references/extension-tools.md | 11 +++
 .../skill/fusion/references/fusion-capabilities.md |  1 +
 .../extension-experiment-finalize.test.ts          |  2 +
 .../src/__tests__/extension-fn-secret-get.test.ts  |  2 +
 .../__tests__/extension-gitlab-tracking.test.ts    |  2 +
 .../src/__tests__/extension-integration.test.ts    |  1 +
 .../cli/src/__tests__/extension-web-fetch.test.ts  |  2 +
 packages/cli/src/__tests__/extension.test.ts       |  1 +
 packages/cli/src/extension.ts                      | 34 ++++++++
 .../src/__tests__/agent-logs-backend-mode.test.ts  | 28 +++++-
 packages/core/src/store.ts                         | 11 ++-
 packages/core/src/task-store/remaining-ops-7.ts    | 16 +++-
 packages/core/src/types.ts                         |  1 +
 packages/dashboard/src/__tests__/chat.test.ts      |  1 +
 .../planning-answered-question-reemit.test.ts      |  1 +
 .../planning-generation-cancellation.test.ts       |  1 +
 packages/dashboard/src/chat.ts                     |  5 ++
 packages/dashboard/src/planning.ts                 |  3 +
 .../__tests__/agent-task-logs-read-tools.test.ts   | 72 ++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             |  4 +-
 packages/engine/src/agent-tools.ts                 | 99 +++++++++++++++++++++-
 packages/engine/src/executor.ts                    |  6 ++
 packages/engine/src/gating-classifications.ts      |  2 +
 packages/engine/src/index.ts                       |  6 ++
 packages/engine/src/step-session-executor.ts       |  6 +-
 28 files changed, 316 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-8058
Fusion-Task-Lineage: 74f198b2-f538-4b39-973f-431f22e68f29
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 04:03:43 -07:00
gsxdsm
b330f9703b FN-8038: allowlist migration bookkeeping settings
Classify PostgreSQL migration bookkeeping as engine-managed settings metadata.

- Allowlist the SQLite migration notice and PostgreSQL inbox completion marker in settings-description coverage.
- Document why neither field is a user-editable Settings description.

Files changed:
 .../sections/__tests__/settings-default-descriptions.test.tsx         | 4 ++++
 1 file changed, 4 insertions(+)

Fusion-Task-Id: FN-8038

Fusion-Task-Lineage: 24424373-970e-4cf0-a9c4-4d743fdec4ca

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:53:37 -07:00
gsxdsm
f44b44f43f FN-8036: reflow reliability metric cards
Reliability metrics now adapt to their content column on narrow dashboard surfaces.

- Reflow metric cards with an auto-fit, minimum-width grid
- Cover the responsive grid contract in ReliabilityView tests

Files changed:
 packages/dashboard/app/components/ReliabilityView.css        |  6 +++++-
 .../app/components/__tests__/ReliabilityView.test.tsx        | 12 ++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8036

Fusion-Task-Lineage: e48567ac-2b7e-415d-8652-2c21048cd768

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:46:55 -07:00
gsxdsm
055f3ba75d FN-8032: align GitLab import detail actions
Keep GitLab import details consistent with the shared padded FloatingWindow layout.\n\n- Move the GitLab preview into the shared heading and scrolling-content structure\n- Place the GitLab import control in the shared bottom action bar for mobile reachability\n- Cover cross-provider detail layout and shared mobile-sheet invariants\n\nFiles changed:\n .../dashboard/app/components/GitHubImportModal.tsx | 20 ++++++++++----\n .../__tests__/GitHubImportModal.test.tsx           | 32 +++++++++++++++++++---\n 2 files changed, 42 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-8032

Fusion-Task-Lineage: 150b992a-d5fa-4001-b818-7ece031a6cb5

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:40:47 -07:00
gsxdsm
2734e61d3e FN-8080: fix done-card action centerline test
Correct done-card action expectations in the badge-wrap regression coverage.

- Assert done cards expose only menu and size header controls
- Document the Archive/Revert placement in the TaskContextMenu

Files changed:
 .../app/components/__tests__/TaskCard.badge-wrap.test.tsx          | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8080

Fusion-Task-Lineage: 230ff30c-d493-49a8-b501-05a2b8e89b04

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:33:56 -07:00
gsxdsm
297edd93e4 FN-8073: preserve deletion confirmations until explicitly dismissed
Keep task deletion confirmations open until users intentionally confirm, cancel, or dismiss the backdrop.

- Track backdrop press origin to ignore trigger click-through events
- Claim dialog stacking order before paint and cover mouse and touch regressions
- Add a patch changeset for the confirmation behavior fix

Files changed:
 .changeset/fn-8073-confirm-dialog.md               |  7 ++++
 packages/dashboard/app/components/ConfirmDialog.tsx | 32 ++++++++++++++++--
 .../components/__tests__/ConfirmDialog.test.tsx    | 32 +++++++++++++++++-
 .../app/hooks/__tests__/useConfirm.test.ts         | 38 ++++++++++++++++++++++
 4 files changed, 105 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8073

Fusion-Task-Lineage: 15a8636f-a058-4b15-834f-6b3549fee4c2

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:28:07 -07:00
gsxdsm
90ce57f127 FN-8070: preserve task title input language
Ensure auto-generated task titles use the task description's language.

- Detect description language and add a confident language hint to title prompts
- Cover multilingual title generation and stale-model fallback behavior
- Document the language-preserving title-summary setting and add a patch changeset

Files changed:
 .changeset/fn-8070-title-summary-input-language.md |  7 ++
 docs/settings-reference.md                         |  2 +-
 packages/core/src/__tests__/ai-summarize.test.ts   | 87 ++++++++++++++++++----
 packages/core/src/ai-summarize.ts                  | 18 +++++
 4 files changed, 98 insertions(+), 16 deletions(-)

Fusion-Task-Id: FN-8070

Fusion-Task-Lineage: e003e2e0-eb0c-487e-83de-8a9b37ee1c02

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:23:25 -07:00
gsxdsm
566158232b FN-8069: toggle dashboard keyboard shortcuts
Dashboard keyboard shortcuts now toggle their associated dashboard interfaces.

- Dispatch toggle callbacks for every configurable dashboard shortcut.
- Restore retained prior views and preserve repeated Settings/Command Center history entries.
- Add regression coverage, documentation, and a dashboard feature changeset.

Files changed:
 .changeset/fn-8069-shortcut-toggle.md              |   7 +
 docs/dashboard-guide.md                            |   3 +
 packages/dashboard/app/App.tsx                     |  48 ++++--
 .../app/__tests__/App.keyboard-shortcuts.test.tsx  | 172 +++++++++++++++++----
 .../useDashboardKeyboardShortcuts.test.tsx         |  82 +++++-----
 .../app/hooks/useDashboardKeyboardShortcuts.ts     |  40 ++---
 .../app/utils/dashboardShortcutToggles.ts          |  41 +++++
 7 files changed, 290 insertions(+), 103 deletions(-)

Fusion-Task-Id: FN-8069

Fusion-Task-Lineage: c2e6d67a-d215-46dd-9803-78ffb49fbbda

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:17:35 -07:00
gsxdsm
99b79e456b FN-8066: show reverted badges for completed tasks
Persist git-revert provenance and display it on completed task cards.

- Stamp source tasks after clean or already-reverted git outcomes.
- Render localized Reverted badges in completed and archived task views.
- Cover metadata, route, and card behavior with regression tests.

Files changed:
 .changeset/fn-8066-reverted-badge.md               |  7 +++
 docs/dashboard-guide.md                            |  2 +
 packages/dashboard/app/components/TaskCard.css     | 14 ++++-
 packages/dashboard/app/components/TaskCard.tsx     | 20 ++++++-
 .../app/components/__tests__/TaskCard.test.tsx     | 67 ++++++++++++++++++++++
 .../app/utils/__tests__/taskRevert.test.ts         | 17 ++++++
 packages/dashboard/app/utils/taskRevert.ts         | 11 ++++
 .../src/__tests__/task-revert-route.test.ts        | 35 +++++++++++
 .../src/routes/register-task-workflow-routes.ts    | 30 ++++++++++
 packages/i18n/locales/en/app.json                  |  2 +
 packages/i18n/locales/es/app.json                  |  2 +
 packages/i18n/locales/fr/app.json                  |  2 +
 packages/i18n/locales/ko/app.json                  |  2 +
 packages/i18n/locales/zh-CN/app.json               |  2 +
 packages/i18n/locales/zh-TW/app.json               |  2 +
 packages/i18n/src/resources.d.ts                   |  2 +
 16 files changed, 213 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8066

Fusion-Task-Lineage: 2a071c14-7e5d-4161-ab0c-158f47ad9c22

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 03:00:59 -07:00
gsxdsm
f3b68c9fff FN-8065: preview plans before refinement questions
Show a read-only plan preview at the Planning Mode deepening checkpoint.

- Persist pending plan details on the checkpoint question for fresh and restored sessions.
- Render formatted plan content and deliverables above refinement choices.
- Cover preview behavior and document the checkpoint flow.

Files changed:
 .../fn-8065-planning-checkpoint-plan-preview.md    |  7 +++
 docs/dashboard-guide.md                            |  3 +-
 packages/core/src/types.ts                         | 11 ++++
 .../dashboard/app/components/PlanningModeModal.css | 60 ++++++++++++++++++++++
 .../dashboard/app/components/PlanningModeModal.tsx | 44 ++++++++++++++++
 .../PlanningModeModal.planning-flow.test.tsx       | 24 ++++++++-
 .../planning-interview-formatters.test.ts          | 19 +++++++
 packages/dashboard/src/planning.ts                 | 10 ++++
 8 files changed, 175 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-8065

Fusion-Task-Lineage: 13cd52c3-af82-4723-a6b1-3366775213e1

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:54:33 -07:00
gsxdsm
c2475b012d FN-8064: add proactive task chat status updates
Task-detail chat now narrates engine progress and review outcomes in real time.

- Emit bounded, redacted status rows for step lifecycle and review paths.
- Present status entries with a distinct task-chat treatment.
- Cover status narration and diagnostic sanitization with engine tests.

Files changed:
 .changeset/fn-8064-proactive-chat.md               |   7 +
 docs/architecture.md                               |   1 +
 packages/dashboard/app/components/TaskChatTab.css  |  16 ++
 packages/dashboard/app/components/TaskChatTab.tsx  |   9 +-
 .../engine/src/__tests__/executor-prompt.test.ts   |  28 +++-
 .../engine/src/__tests__/proactive-status.test.ts  |  54 +++++++
 packages/engine/src/executor.ts                    | 176 ++++++++++++++++-----
 packages/engine/src/proactive-status.ts            | 117 ++++++++++++++
 8 files changed, 365 insertions(+), 43 deletions(-)

Fusion-Task-Id: FN-8064

Fusion-Task-Lineage: c6d0a9b5-0946-4bf4-8338-e982e1cbfd53

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:47:59 -07:00
gsxdsm
39d76fdabe FN-8062: normalize room message ordering
Normalize room chat snapshots to chronological display order.

- Reverse newest-first API snapshots before cache hydration and rendering.
- Version the room message cache and cover initial, refresh, recovery, SSE, and host layouts.
- Add a patch changeset for the chat transcript ordering fix.

Files changed:
 .changeset/fn-8062-room-message-order.md           |  7 +++
 .../components/__tests__/ChatView.rooms.test.tsx   | 26 ++++++++
 .../app/hooks/__tests__/useChatRooms.cache.test.ts |  8 +--
 .../app/hooks/__tests__/useChatRooms.test.ts       | 73 +++++++++++++++++++++-
 packages/dashboard/app/hooks/useChatRooms.ts       | 45 ++++++++-----
 packages/dashboard/app/utils/swrCache.ts           |  3 +-
 6 files changed, 140 insertions(+), 22 deletions(-)

Fusion-Task-Id: FN-8062

Fusion-Task-Lineage: 99bb313c-fb24-40e2-b33b-4811bde6d6cb

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:41:27 -07:00
gsxdsm
e87b51bd07 FN-8054: add pinned chat conversations
Add durable, scoped pinning for Direct chat conversations.

- Add pinned session persistence, migration coverage, and archive-safe row locking.
- Enforce a three-conversation per-project pin limit through the chat API.
- Add desktop and mobile pin controls, sorting, indicators, and regression tests.

Files changed:
 .changeset/fn-8054-pin-conversations.md            |  7 ++
 docs/dashboard-guide.md                            |  2 +
 .../postgres/satellite-db-injected-stores.test.ts  | 13 ++++
 packages/core/src/async-chat-store.ts              | 27 ++++++++
 packages/core/src/chat-store.ts                    | 63 ++++++++++++++++--
 packages/core/src/chat-types.ts                    |  9 +++
 .../core/src/postgres/migrations/0000_initial.sql  |  1 +
 .../postgres/migrations/0012_chat_session_pins.sql |  8 +++
 packages/core/src/postgres/postgres-health.ts      |  3 +
 packages/core/src/postgres/schema-applier.ts       | 30 ++++++++-
 packages/core/src/postgres/schema/project.ts       |  3 +
 packages/dashboard/app/api/legacy.ts               |  1 +
 packages/dashboard/app/components/ChatView.css     | 32 +++++++++-
 packages/dashboard/app/components/ChatView.tsx     | 74 ++++++++++++++++++++--
 .../dashboard/app/hooks/__tests__/useChat.test.ts  | 21 ++++++
 packages/dashboard/app/hooks/useChat.ts            | 72 +++++++++++++++++----
 .../dashboard/src/routes/register-chat-routes.ts   | 25 +++++++-
 17 files changed, 366 insertions(+), 25 deletions(-)

Fusion-Task-Id: FN-8054

Fusion-Task-Lineage: 088cb01c-582b-4f56-a222-214da90ff356

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:35:29 -07:00
gsxdsm
e40f76fef9 FN-8057: render planning questions as sanitized Markdown
Render AI-authored planning and interview questions with readable, sanitized Markdown.

- Reuse MailboxMessageContent for active and historical planning questions.
- Preserve question typography while spacing Markdown blocks and lists consistently.
- Cover Markdown formatting across planning, mission, milestone, and slice interviews.

Files changed:
 .changeset/fn-8057-planning-question-markdown.md   |  7 ++++
 .../app/components/ConversationHistory.css         | 18 ++++++++++
 .../app/components/ConversationHistory.tsx         |  6 +++-
 .../components/MilestoneSliceInterviewModal.tsx    | 12 +++++--
 .../app/components/MissionInterviewModal.tsx       | 12 +++++--
 .../dashboard/app/components/PlanningModeModal.css | 27 +++++++++++--
 .../dashboard/app/components/PlanningModeModal.tsx | 18 +++++++--
 .../__tests__/ConversationHistory.test.tsx         | 20 +++++++++++
 .../MilestoneSliceInterviewModal.test.tsx          | 39 ++++++++++++++++++++
 .../MissionInterviewModal.test.tsx                 | 31 ++++++++++++++++
 .../PlanningModeModal.ui-interactions.test.tsx     | 41 +++++++++++++++++++++-
 11 files changed, 221 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-8057

Fusion-Task-Lineage: cf04fc77-c15c-4ca5-a99a-80a9631a1c8c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:07:43 -07:00
gsxdsm
8f176e3b89 FN-8055: align active-agent indicators with task activity
Keep board and list activity styling synchronized with actual agent work.

- Centralize task activity detection across cards, lists, routing, and model-resolution surfaces.
- Show running workflow activity while suppressing stale, paused, stuck-killed, and terminal task states.
- Cover status-null workflow activity and terminal-state regressions.

Files changed:
 packages/dashboard/app/components/ListView.tsx     | 34 ++---------
 packages/dashboard/app/components/RoutingTab.tsx   | 17 +-----
 packages/dashboard/app/components/TaskCard.tsx     | 28 +++------
 .../app/components/__tests__/ListView.test.tsx     | 66 +++++++++++---------
 .../app/components/__tests__/TaskCard.test.tsx     | 44 ++++++++++++++
 .../app/components/effective-model-resolution.ts   | 18 +-----
 .../app/utils/__tests__/taskActivity.test.ts       | 71 ++++++++++++++++++++++
 packages/dashboard/app/utils/taskActivity.ts       | 59 ++++++++++++++++++
 8 files changed, 228 insertions(+), 109 deletions(-)

Fusion-Task-Id: FN-8055
Fusion-Task-Lineage: 9ce38d60-06c8-4050-83f4-263e2f765c86
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:01:56 -07:00
gsxdsm
274318aebf FN-8056: enforce task token budgets
Enforce configured task token budgets whenever session usage is persisted.

- Apply soft alerts and hard pauses atomically from all executor persistence paths.
- Exclude cache-read tokens from budget usage and dispatch budget notifications once.
- Document budget semantics and add regression coverage.

Files changed: .changeset/fn-8056-token-budget-enforcement.md     |   7 ++
 docs/settings-reference.md                         |   2 +
 packages/core/src/types.ts                         |   4 +-
 .../src/__tests__/session-token-usage.test.ts      | 101 ++++++++++++++++++++-
 .../src/__tests__/token-budget-enforcer.test.ts    |  81 ++++++++++-------
 packages/engine/src/executor.ts                    |  22 ++++-
 packages/engine/src/session-token-usage.ts         |   8 +-
 packages/engine/src/token-budget-enforcer.ts       |  98 +++++++++++++++++---
 8 files changed, 262 insertions(+), 61 deletions(-)

Fusion-Task-Id: FN-8056

Fusion-Task-Lineage: 5f5ed522-f950-42ce-b4fd-e0b1d45b5815

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 01:52:10 -07:00
gsxdsm
d501c3b207 FN-8053: align ChatView mobile header tests with drill-in flow
Update ChatView header contracts to enter the direct-thread pane before assertions.

- Add a shared mobile direct-thread helper for context-window tests
- Select the active session before mobile and floating header assertions
- Preserve rename coverage for the direct-thread session switcher

Files changed:
 .../components/__tests__/ChatView.context-window.test.tsx  | 14 ++++++++++++++
 .../components/__tests__/ChatView.core-contracts.test.tsx  |  9 +++++++++
 2 files changed, 23 insertions(+)

Fusion-Task-Id: FN-8053

Fusion-Task-Lineage: a491db31-04b1-4cb5-ac58-c3be297bfe45

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 01:45:39 -07:00
gsxdsm
a821bce236 FN-8030: move room thinking control into composer
Move room-level thinking effort from the crowded thread header into the composer Brain popover.

- Reuse the thinking-level control in a room-specific level-only mode.
- Preserve room thinking persistence and add desktop, mobile, and failure coverage.
- Update room-chat documentation and publish a patch changeset.

Files changed:
 .changeset/fn-8030-room-thinking-composer.md       |  7 +++
 docs/dashboard-guide.md                            |  2 +-
 .../app/components/ChatThinkingLevelControl.tsx    | 12 +++-
 packages/dashboard/app/components/ChatView.css     | 16 -----
 packages/dashboard/app/components/ChatView.tsx     | 54 +++++++---------
 .../__tests__/ChatThinkingLevelControl.test.tsx    | 20 ++++++
 .../components/__tests__/ChatView.rooms.test.tsx   | 72 +++++++++++++++++++---
 .../__tests__/ChatView.thinking-level.test.tsx     | 23 ++++---
 8 files changed, 137 insertions(+), 69 deletions(-)

Fusion-Task-Id: FN-8030

Fusion-Task-Lineage: 31054538-e620-412d-98ba-26fba34a6af8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 01:38:49 -07:00
gsxdsm
e46ffebde1 FN-7985: surface review budget exhaustion and configure replan cap
Expose exhausted Plan Review replan budgets for operator approval and allow workflows to configure the cap.

- Add validated numeric workflow setting support and a Plan Review replan-cap setting.
- Route configured cap exhaustion with a distinct approval reason and preserve fallback behavior.
- Display the budget-exhaustion state across task cards, lists, and details.
- Add tests, localized copy, documentation, and a minor changeset.

Files changed:
 .changeset/fn-7985-review-budget-approval.md       |  7 ++++
 docs/settings-reference.md                         |  9 +++--
 docs/workflow-steps.md                             |  2 +-
 .../builtin-workflow-settings-triage.test.ts       | 27 +++++++++++++--
 packages/core/src/builtin-workflow-settings.ts     | 17 ++++++++++
 packages/core/src/index.gate.ts                    |  1 +
 packages/core/src/index.ts                         |  1 +
 packages/core/src/workflow-ir-types.ts             |  4 +++
 packages/core/src/workflow-ir.ts                   | 27 +++++++++++++++
 packages/core/src/workflow-settings-resolver.ts    |  1 +
 packages/core/src/workflow-settings.ts             |  6 ++++
 packages/dashboard/app/components/ListView.css     | 19 +++++++++++
 packages/dashboard/app/components/ListView.tsx     | 22 +++++++++---
 packages/dashboard/app/components/TaskCard.css     | 18 ++++++++++
 packages/dashboard/app/components/TaskCard.tsx     |  6 ++--
 .../dashboard/app/components/TaskDetailModal.tsx   |  4 +--
 .../app/components/__tests__/ListView.test.tsx     | 30 +++++++++++++++++
 .../app/components/__tests__/TaskCard.test.tsx     | 17 ++++++++--
 .../app/components/workflow-setting-display.ts     | 11 ++++++
 .../dashboard/app/utils/reviewBudgetApproval.ts    | 11 ++++++
 .../triage-plan-review-replan-cap.test.ts          | 39 +++++++++++++++++++---
 packages/engine/src/triage.ts                      | 21 ++++++++----
 packages/i18n/locales/en/app.json                  |  2 +-
 packages/i18n/src/resources.d.ts                   | 19 ++++++++---
 24 files changed, 288 insertions(+), 33 deletions(-)

Fusion-Task-Id: FN-7985

Fusion-Task-Lineage: 125f101c-caca-45c2-8b40-996b2a31c019

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 01:32:23 -07:00
gsxdsm
375368e147 FN-8051: ensure PostgreSQL schemas initialize before plugin hooks
Ensure required PostgreSQL namespaces exist before plugin initialization on every boot.

- Create project, central, and archive schemas under the schema advisory lock before hooks run
- Cover marker-present databases with a plugin-hook schema availability regression test
- Add a patch changeset for the reliability fix

Files changed:
 .changeset/fn-8051-schema-init.md                  |  7 ++++
 .../src/__tests__/postgres/schema-applier.test.ts  | 43 ++++++++++++++++++++++
 packages/core/src/postgres/schema-applier.ts       | 12 ++++++
 3 files changed, 62 insertions(+)

Fusion-Task-Id: FN-8051

Fusion-Task-Lineage: a3b20683-a742-4a8c-9cfc-fbf316c5649b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 01:26:13 -07:00
gsxdsm
3f5d7c2147 FN-8049: preserve desktop geometry across sheet views
Prevent full-screen sheet opens from replacing saved desktop FloatingWindow geometry.

- Suspend geometry restoration and writes for sheet modal surfaces without adding storage keys.
- Preserve Artifact Gallery geometry at both narrow-width and short-height sheet breakpoints.
- Cover sheet persistence behavior and document desktop geometry restoration.

Files changed:
 docs/dashboard-guide.md                            |   3 +
 packages/dashboard/app/App.tsx                     |   4 +
 .../dashboard/app/components/ArtifactsGallery.tsx  |   3 +
 .../dashboard/app/components/FileBrowserModal.tsx  |   2 +
 .../dashboard/app/components/FloatingWindow.tsx    |  25 ++++-
 .../dashboard/app/components/GitHubImportModal.tsx |   4 +
 .../app/components/MissionInterviewModal.tsx       |   2 +
 .../dashboard/app/components/PrCreateModal.tsx     |   2 +
 .../app/components/ScheduledTasksModal.tsx         |   2 +
 .../app/components/WorkflowNodeEditor.tsx          |   2 +
 .../components/__tests__/FloatingWindow.test.tsx   | 118 ++++++++++++++++++++-
 .../app/hooks/__tests__/useViewportMode.test.ts    |  13 ++-
 packages/dashboard/app/hooks/useViewportMode.ts    |  15 +++
 13 files changed, 190 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-8049

Fusion-Task-Lineage: 4c659046-694a-42fa-aca1-e702c1d3842a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 01:19:43 -07:00
gsxdsm
4b7f0d2d0e fix(dashboard): theme every Settings checkbox and move all inline help behind ? icons
- One settings-scoped checkbox rule (accent, size, focus ring) so the Advanced-settings
  toggle, SettingsToggleRow, ntfy/webhook card headers, and MCP toggle stop falling
  back to the browser-default accent.
- Fix the empty/off-screen help bubble on mobile: .notification-provider-header and
  .settings-field-label-row are now positioned ancestors for SettingsHelpTip.
- Migrate every remaining inline <small> description across settings sections to the
  shared SettingsHelpTip "?" affordance (validation errors and live status stay inline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 01:06:43 -07:00
gsxdsm
5372dcc37d fix(dashboard): center quick-add control rows on mobile
Center each wrapped row below the quick-add textarea (workflow/steps,
option chips, icons+Save) so all rows share equal left/right insets on
mobile, instead of options hugging the left edge and Save hugging the
right. Desktop/tablet keep the left-options / right-Save toolbar layout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 00:48:23 -07:00
gsxdsm
a31c370375 FN-8045: add transactional handoff failure-injection seam
Ensure PostgreSQL review handoffs roll back all dependent writes after an injected late failure.

- Add a test-only failure injector after transactional handoff writes.
- Include workflow work in same-column retry transactions.
- Restore PG-backed handoff atomicity coverage and remove its quarantine.

Files changed:
 packages/core/src/store.ts                         |  24 +++
 packages/core/src/task-store/moves.ts              |  21 ++-
 .../in-review-handoff-atomic.test.ts               | 172 +++++++++++++--------
 packages/engine/vitest.config.ts                   |   1 -
 scripts/lib/test-quarantine.json                   |   5 -
 5 files changed, 151 insertions(+), 72 deletions(-)

Fusion-Task-Id: FN-8045

Fusion-Task-Lineage: 517e3000-9b88-4b0d-9b25-1a585eb8f322

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 00:44:35 -07:00
gsxdsm
c5aa5ecfc7 fix(dashboard): keep quick-add Save inline with its icon controls on mobile
Tighten the mobile primary-group gap to --space-xs and the icon-only
controls' min-width floor to 32px so the Save button no longer wraps to
its own line in the board quick-add composer. Touch-target height is
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 00:38:33 -07:00
gsxdsm
261901343e fix(core): split the domain project field from the RLS partition column (#2165)
## Problem

Migration 0006 made `project_id` the RLS isolation partition on every
`project`-schema table — stamped by a BEFORE INSERT trigger from the
`fusion.project_id` session GUC, with every PK/unique/FK rewritten to
composite `(project_id, …)`. Eleven tables **also** carried a
caller-supplied domain `projectId` on their TS types and wrote that
domain value into the same physical column.

When the domain value differs from the session GUC, the parent row lands
in the domain partition while child rows (`research_run_events`,
`experiment_session_records`, `eval_task_results`, …) land in the
session partition — and the composite FK fails with SQLSTATE 23503.
Appending an event to a project-owned research run could not persist.

## Fix

**Decision (operator): separate domain column; `project_id` stays the
partition.**

- **Migration `0011_owner_project_id.sql`** adds a nullable
`owner_project_id` domain column to the 11 conflated tables
(`research_runs`, `experiment_sessions`, `todo_lists`, `eval_runs`,
`chat_sessions`, `chat_rooms`, `ai_sessions`, `chat_token_usage`,
`project_insights`, `project_insight_runs`, `cli_sessions`), backfills
it from `project_id` (identical in production, so exact; the
`__legacy_unscoped__` sentinel backfills to NULL), and indexes it.
Idempotent, `to_regclass`-guarded per the 0007 pattern.
- **Stores** (`async-research-store`, `async-experiment-session-store`,
`async-todo-store`, `async-chat-store`, `async-ai-session-store`,
`async-eval-store`, `async-insight-store`, `cli-session-store`, …) stop
writing `project_id` entirely — the trigger/GUC owns the partition — and
map their domain `projectId` field to `owner_project_id` for both reads
and filters. TS types unchanged.
- **Applier** registers `OWNER_PROJECT_ID_SPLIT_VERSION = "0011"` and
advances `SCHEMA_BASELINE_VERSION`.

## Verification (re-run independently of the implementing agent)

- Core `tsc --noEmit`: exit 0 · `pnpm lint`: exit 0 · `pnpm
check:changesets`: exit 0 · `pnpm test:gate`: 185/185
- Full postgres suite: **5 failed / 807 passed** vs a **7 / 804**
baseline — the two conflation round-trips
(`satellite-db-injected-stores` ResearchStore + ExperimentSessionStore)
go green, zero new failures. The remaining 5 are pre-existing
unbound-harness `__meta`/identity failures, unrelated to this change.

🤖 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**
* Corrected project-scoped persistence and queries across AI sessions,
chats (rooms + token usage), evaluations/experiments, insights,
research, and todos by separating domain ownership from RLS
partitioning.
* Prevented foreign-key and row-level security violations when storing
or retrieving project-scoped data, including legacy records.
* **Database / New Features**
* Added migration 0011 introducing `owner_project_id` and backfilling
existing rows to preserve ownership while improving isolation.
* **Tests**
  * Updated migration-parity coverage to include the new baseline step.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 00:30:59 -07:00
gsxdsm
9b8edf06c4 fix(FN-2127): Quality experimental gate, done-task worktrees, hub layout (#2164)
## Summary

Follow-up on **#2127** (Quality plugin already on `main`). This PR only
lands the remaining Quality deltas that were not merged:

- **Experimental gate fix** — `TaskStore.getSettings()` is async; the
gate now awaits merged settings so enabling
`experimentalFeatures.qualityPlugin` actually works, and status-bearing
errors return structured `{ status, body }` instead of collapsing to
hard failures
- **Done-task QA worktrees** — when a task has no live worktree (typical
after land), preview/task runs create a disposable checkout under
`.fusion/quality-qa/` at the task branch or merge commit so processes
run the **done task’s code**, not project root
- **Hub layout** — shared `ViewHeader` + dashboard spacing/typography so
Quality matches Insights / Compound Engineering / Goals

Scoped to `plugins/fusion-plugin-quality/**` only (rebased onto current
`main`; duplicate plugin-landing commits dropped).

## Test plan

- [ ] Enable **Settings → Experimental → Quality Plugin**, restart if
routes were cold
- [ ] Quality hub: header matches other views; refresh + presets work
- [ ] Done task → QA tab → Start preview uses QA worktree at
branch/merge commit (not project root)
- [ ] Active task with live worktree still uses that worktree
- [ ] Flag off: clear experimental-disabled error (not generic empty
failure)
- [ ] `pnpm --filter @fusion-plugin-examples/quality test` (32 tests)
2026-07-16 00:16:12 -07:00
gsxdsm
9a34862586 refactor: package code organization waves 3–5 (#2148)
## Summary

Waves 3–5 of package code organization (plan:
`docs/plans/2026-07-14-001-refactor-package-code-organization-plan.md`).
Behavior-preserving peels after #2139 and #2143.

### Wave 3 — Merger + heartbeat recovery
- **`merger-errors.ts`** — verification/abort error classes
- **`merger-owned-landed.ts`** — ownership classification +
`Fusion-Task-Id` trailer
- **`merger-conflict-resolution.ts`** — conflict classify/auto-resolve
- **`agent-heartbeat-error-recovery.ts`** — durable error-recovery
budget helpers

### Wave 4 — Self-healing + dashboard API
- **`self-healing-constants.ts`** — public timing/budget constants
- **`self-healing-branch.ts`** — `isBranchAheadOfBase`
- **`app/api/client.ts`** — `api` / `ApiRequestError` / `buildApiUrl` /
`proxyApi`
- **`app/api/health.ts`** — health, engine status, updates +
`withProjectId`

### Wave 5 — Types tracking + merger parse + task CRUD
- **`types/task-tracking.ts`** — PR/issue/GitHub/GitLab tracking
contracts
- **`merger-git-parse.ts`** — `parseFailingFilesFromOutput`,
`parsePorcelainZ`, `parseShortstatSummary`
- **`app/api/tasks.ts`** — task list/detail/create/update/move client
surface
- Line-count baselines ratcheted down for `merger.ts`, `types.ts`,
`legacy.ts`

Public import paths stay on parent modules / `legacy.ts` / package
barrels via re-exports.

## Test plan
- [x] core/engine/dashboard typecheck (including `tsconfig.app.json`)
- [x] eslint on touched modules
- [x] `parse-porcelain-z` + merger parseFailing/getBranchChanged tests
- [x] dashboard `api-tasks` + legacy-prinfo/pr-types (69)
- [ ] CI merge gate

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added dashboard API support for task listing/detail, archiving,
creation, review updates, duplicate detection, bulk model updates,
moving tasks, and overlap repair.
- Added health/engine status and refresh/start controls, plus update
checking.

- **Bug Fixes**
- Improved dashboard API handling for non-JSON/HTML responses with
clearer errors, better URL routing for remote nodes, and project-scoped
queries.
- Strengthened automated recovery for heartbeat error/model-unavailable
scenarios and safer merge-conflict classification/auto-resolution.

- **Tests**
- Updated merge-conflict resolution and lifecycle test mocks to match
the updated git command behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-16 00:01:17 -07:00
gsxdsm
d6f94693b2 FN-8028: widen tablet chat message bubbles
Increase tablet agent-side chat bubble width while preserving responsive behavior.

- Raise the tablet assistant, streaming, and failure bubble cap to 92%.
- Update the responsive CSS contract and dashboard documentation.

Files changed:
 docs/dashboard-guide.md                                              | 2 +-
 packages/dashboard/app/components/ChatView.css                       | 5 ++++-
 packages/dashboard/app/components/__tests__/ChatView.core-contracts.test.tsx        | 4 ++--
 3 files changed, 7 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8028

Fusion-Task-Lineage: 2158a4c8-f07b-4e96-bcf2-80ebe6b08515

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 23:49:24 -07:00
gsxdsm
5ab46a6430 feat(dashboard): compact the GitHub import screen and move Import under the issue (#2163)
Mobile operator report: the import screen spent ~4 rows on chrome — a
provider row, a tab row, and a boxed ORIGIN/filter/Load stack — leaving
only **~9 issues visible**. Import also sat *above* the preview it acts
on, and a second Import in the list footer let you import an issue whose
body you had never opened.

## Before → After (measured at 412px)

| | before | after |
|---|---|---|
| control chrome | ~4 stacked bands (93px) | **one wrapping row (70px)**
|
| toolbar | boxed band, origin on its own line | **single 36px row** |
| issues visible | ~9 | **~13** |
| Import | list footer **and** preview header | **detail bottom bar
only** |

## Layout

- **Provider, type tabs, origin, filter and Load share one row.** It
wraps rather than clipping at the narrowest widths.
- **Load is icon-only** — the label survives as `aria-label`/`title`, so
the accessible name is unchanged (the pre-existing role+name query still
finds it, which is what proves nothing was lost for screen readers).
- **The labels filter is a popover.** Its trigger doubles as the readout
— it renders the active labels and takes an `is-active` cue — so
collapsing never hides applied state. Dismisses on outside pointerdown
or Escape; Escape `stopPropagation` keeps the modal from closing along
with it.
- **Origin stays visible as an inline chip** (per your call): it's
context for what you're importing, so it flattens from a stacked
ORIGIN/repo block rather than hiding in the popover.
- Removed the toolbar's `flex: 1 1 100%` mobile stacking — it dated from
when the toolbar was a full-width band and was forcing origin to claim
an entire line.
- Also neutralised `[data-theme="light"] .github-import-toolbar`, which
re-applied the band background later in the cascade at equal specificity
(light mode only).

## Actions — one place to import

Import + Close issue move from the preview header to a **bottom action
bar**: commit actions belong below the content they act on and within
thumb reach, matching the modal's own Cancel bar. The list footer's
duplicate Import is removed (Cancel stays — the modal still needs a
dismiss), so **an issue can no longer be imported sight-unseen**.

## Note for review — interaction with #551a2a3c1

`551a2a3c1` ("align import detail header") landed mid-work and
conflicted. Its panel-padding work is preserved untouched. Its header
rules were kept **as-is** because they remain correct for a lone label,
but its stated rationale — dropping `space-between` so "Close issue and
Import stay grouped as a pair at the end" — is moot now that those
actions live in the bottom bar. The comment is marked superseded rather
than left asserting something untrue.

## Verification

Measured in a real browser at 412px (jsdom has no layout, so the tests
pin structure and behaviour, not geometry): chrome 93→70px, toolbar a
single 36px row, ~13 issues visible, filter popover clamped inside the
viewport and autofocused, detail bar below the content with an unclipped
Import label. Re-verified after the rebase.

**90 tests pass** · gate green (294/122/63) · lint clean · typecheck
clean.

Seven existing tests encoded the old UI (labelled Load, always-open
filter input). They were **updated to the new contract rather than
appeased** — the filter assertions now exercise the whole affordance
(collapsed → open → filters), and FN-7657 persistence is asserted via
the *collapsed trigger*, proving both that state survives remount
**and** that a restored filter stays visible, which is the real risk
when a control collapses.

Two things worth knowing:

- The footer guard was **confirmed non-vacuous**: reintroducing the list
Import fails it.
- One new CSS rule is deliberately a child selector
(`.github-import-controls > *`) rather than naming
`.github-import-tabs`, because `GitHubImportModal.test.tsx` extracts
base rules with a naive first-match regex
(`/\.github-import-tabs\s*\{[^}]*\}/`) that a rule mentioning them
*above* the originals would silently hijack.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added a more compact, responsive mobile layout for the GitHub import
screen.
* Moved Import and Close issue actions to the preview’s bottom action
bar.
* Added a collapsible labels filter popover with keyboard and
outside-click dismissal.
  * Consolidated mobile controls into a single compact row.
  * Simplified the Load action to an accessible icon-only button.

* **Bug Fixes**
  * Removed duplicate Import controls from the list footer.
* Improved control sizing, wrapping, and preview action positioning on
narrow screens.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 23:48:47 -07:00
gsxdsm
81d4bee59b fix(settings): Source Control nav icons, Authentication as the landing section, CLI binary behind Advanced (#2162)
Follow-up to #2158. That PR was squash-merged while this last commit was
still in flight, so these four fixes never landed on main.

### Source Control had no icon in the nav
A section's own `icon` now wins over the generic scope glyph, which
becomes the fallback. `icon` previously only rendered when `scope` was
`undefined`, so **any** scoped section was forced to the globe/folder
pair and could not identify itself — Source Control was
indistinguishable from MCP Servers and Scheduling. Both Source Control
entries now carry a git-branch icon. Nothing is lost: these sections
spell their tier out in the label (`· Global` / `· Project`), and the
aria-label and tooltip still announce it.

### Settings opens on Authentication
Previously "General · Global". Nothing else in the product works until a
provider is connected — the dashboard's own empty state sends operators
to Settings for exactly this. Authentication leads the **AI & Models**
group rather than sitting under Integrations: connecting a provider and
picking the models it gates are one task, in that order. A test asserts
the landing section is never one the Advanced switch hides, so a
default-configured operator cannot land on a section their own nav does
not list.

### The `fn` CLI binary panel moved behind Advanced, at the bottom
It used to render *first* inside "General · Global" — an
install/version/path panel was the first thing an operator saw on
opening Settings. It is machine plumbing touched once, or when an
install breaks, so it belongs with the other specialist surfaces.

### Changing section starts you at the top of it
Sections keep no scroll of their own, so the container's offset carried
over: leaving a long section scrolled halfway and picking a short one
landed mid-content — on mobile, often past everything, on an apparently
blank screen. Guarded by a ref rather than by reading the highlight key,
because a search jump also changes `activeSection` and that key
self-clears ~1.6s later, which would re-run the effect and yank the
operator off the row they just jumped to.

## Verification
- Typecheck clean (`tsconfig.app.json` — the one that covers `app/`).
- Settings suites run against this branch and against plain main:
**identical 67-failure set, 0 new**. Those 67 are pre-existing on main
(51 scheduling-merge + 16 remote-notifications) and are untouched here.
- Browser-verified: lands on Authentication; Source Control renders
`lucide-git-branch`; CLI Binary is last and hidden with Advanced off;
section change resets scroll 1200 → 0 while a search jump still holds
its row.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


## Evidence

Both Source Control rows now carry a git-branch icon, sized and aligned
like their neighbours; Models keeps globe/folder.

![Settings nav showing git-branch icons on both Source Control
rows](https://raw.githubusercontent.com/Runfusion/Fusion/f70cda8eb75bcdf8e6a8d68bdaec430044383482/shots/nav-git-icons.png)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Settings now opens to **Authentication** by default.
  * Added a dedicated advanced-only **CLI Binary** settings section.
* Improved navigation icons for Authentication and Source Control
sections.

* **Improvements**
* Settings sections now reliably scroll to the top when switching
sections.
  * Search-result navigation preserves the selected result’s position.

* **Tests**
* Updated settings and mobile navigation coverage for the new default
section and labels.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 23:46:37 -07:00
gsxdsm
7aeefe21e3 fix(dashboard): stop clipping the composer Save button label on mobile (#2161)
The board composer's Save button rendered its label cut off on mobile
("Sav|").

## Root cause (measured, not guessed)

Reproduced in Chromium at a 412px viewport and measured the live layout:

- The primary action group needs **~275px** inside a **260px** column —
a 15px deficit.
- All five icon controls carry an explicit `min-width: 36px`
touch-target floor, so they **cannot** absorb it.
- Save's own automatic minimum size — which would normally floor a flex
item at its min-content width — is **zeroed by `overflow: hidden`**. Per
the flexbox spec, automatic minimum size applies only when `overflow` is
`visible`.

That `overflow: hidden` exists for a **vertical** reason
(FN-7680/FN-7683 height equalization). So a height fix silently made
Save the only horizontally-shrinkable control in the row: it absorbed
the entire deficit (**40px actual vs 55px needed**) and clipped its own
label.

## Fix

- Save is pinned to its content width (`flex: 0 0 auto; min-width:
max-content`) so it can never be squeezed. `overflow: hidden` stays — it
still owns the vertical clamp.
- The group may `flex-wrap: wrap` with `justify-content: flex-end`, so a
genuine deficit reflows to a second right-aligned line instead of
clipping.

**Not breakpoint-scoped** (FN-5751): the mechanism is width-driven, not
media-driven — mobile only trips it first because its 36px touch targets
are wider than the desktop chips. Where the row already fits, both rules
are inert.

This revises the older "wraps as one unit, never splitting Save from its
neighbors" intent: at widths where the row genuinely cannot fit, Save
wrapping to its own right-aligned line is strictly better than a clipped
label.

## Verification (in-browser, both breakpoints)

| | 412px (mobile) | 1400px (desktop) |
|---|---|---|
| label clipped | **no** (scrollWidth 67 === clientWidth 67) | no |
| Save width | 69px (full) | 69px |
| Save height | 36px — equal to icon siblings | unchanged |
| overflow | none (right edge 292 === container 292) | none |
| layout | wraps to a second right-aligned line | **no-op** — still one
line (group height 28px) |
| icon touch targets | all five still ≥36px | unchanged |

Gate green · lint clean · 288 dashboard composer tests pass.

## On the test

The CSS guard is a **string-match, not a layout proof** — jsdom has no
flex layout and cannot observe clipping, so the real proof is the
browser measurement above. The test exists so the invariant-bearing
declarations can't be silently dropped or re-scoped into a media query.
It was **confirmed non-vacuous**: 3 of its 4 cases fail against the
pre-fix CSS.

🤖 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 the Quick Entry Save button label being clipped on narrow mobile
screens.
* Improved action layout wrapping while preserving icon touch-target
sizing.

* **Tests**
* Added regression coverage to verify the Save button remains fully
visible across narrow layouts.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 23:45:53 -07:00
gsxdsm
db05a77fea FN-8026: fix idle reconnecting hints in interview modals
Keep reconnecting indicators scoped to active interview generation states.

- Hide transient reconnecting hints on persisted mission and milestone questions
- Limit subtask reconnecting hints to the generating state
- Cover active and persisted reconnecting behavior with modal tests
- Add a patch changeset for the dashboard fix

Files changed:
 .changeset/FN-8026-interview-reconnecting-hint.md  |  7 ++++
 .../components/MilestoneSliceInterviewModal.tsx    |  6 +++-
 .../app/components/MissionInterviewModal.tsx       |  6 +++-
 .../app/components/SubtaskBreakdownModal.tsx       |  6 +++-
 .../MilestoneSliceInterviewModal.test.tsx          | 37 ++++++++++++++++++++++
 .../__tests__/MissionInterviewModal.test.tsx       | 20 +++++-------
 .../__tests__/SubtaskBreakdownModal.test.tsx       | 19 ++++++-----
 7 files changed, 76 insertions(+), 25 deletions(-)

Fusion-Task-Id: FN-8026

Fusion-Task-Lineage: 60b2f741-6761-4fc0-bf50-cbddce5f5b6f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 23:39:12 -07:00
gsxdsm
513796b7e7 FN-8024: align insight task creation mock
Align the App task-creation mock with the current default-column behavior.

- Remove the obsolete triage column expectation from the insight task creation test.

Files changed:
 packages/dashboard/app/components/__tests__/App.test.tsx | 1 -
 1 file changed, 1 deletion(-)

Fusion-Task-Id: FN-8024

Fusion-Task-Lineage: f1dd7edd-8338-4367-b023-0adfe8ee4599

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 23:31:43 -07:00
gsxdsm
551a2a3c1e fix(dashboard): align import detail header and show translated titles in its title bar
The GitHub/GitLab import detail panel had no inset of its own, so it sat
flush against the window's left edge while FN-8015's resize gutter left a
gap on the right only — "Preview" was clipped and the whole header read as
misaligned on both the desktop window and the mobile sheet. Give the panel a
symmetric inset, letting that existing gutter supply the right side rather
than overriding it (which would push the inner scrollbar back into the
resize hot zone the gutter protects).

Also in the header: `space-between` spread three children apart and flung
"Close issue" into the middle, so the label now takes the free space and the
two actions stay grouped as a pair. Both actions size from one rule instead
of each inheriting its own .btn defaults, at a 40px touch target on mobile
where Import is the sheet's primary action. "Preview" becomes a muted
eyebrow matching the existing ISSUE #NNNN label.

Fix title truncation while here: `.floating-window__title` declared
text-overflow: ellipsis but was display:flex, which made the text an
anonymous flex item that text-overflow cannot act on, so titles hard-cut
mid-word. Every caller passes a plain string, so a block box makes the
existing declaration work as written.

Finally, the detail title bar kept the raw upstream title while the card
below showed the translation — one item displaying two different titles at
once. Both now read importTranslation.display.title, gated on activeTab to
match translateSelection so an item's number is never paired with the other
tab's title. The existing translation test now asserts both surfaces in both
directions; it fails without this change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 23:22:33 -07:00
gsxdsm
43e03d3ac2 FN-8035: consolidate done actions into card menu
Done-card archive and revert actions now use the existing three-dot menu.

- Remove the duplicate inline Actions dropdown and its state handling.
- Cover done-card archive and revert menu behavior through the unified context menu.

Files changed:
 packages/dashboard/app/components/TaskCard.tsx     | 74 ++--------------------
 packages/dashboard/app/components/__tests__/TaskCard.test.tsx | 71 +++++++++++++--------
 2 files changed, 50 insertions(+), 95 deletions(-)

Fusion-Task-Id: FN-8035

Fusion-Task-Lineage: 64f57e12-829c-445b-aab0-df3996af5502

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 23:17:59 -07:00
gsxdsm
08c546dc75 test(core): bind the U14 postgres harness to a project, as production does
The usage-events round-trip failed because the harness ran unbound. Production
binds `fusion.project_id` per connection (connection.ts) and only falls back to
`fusion.project_bypass=on` when no projectId is given, so an unbound harness
wrote blank project_ids that the migration-0006 trigger rewrote to
'__legacy_unscoped__' -- and helpers scoping on `layer.projectId ?? ""` then
looked for a literal '' the database never stores.

Unbound is a shape production forbids: AgentStore.backendProjectId throws on it
("Reject unbound backend heartbeat/run access instead of silently reading or
writing the legacy empty-string partition"). The harness was wrong, not the
product -- an earlier attempt to make the product accommodate the unbound
harness was reverted in b51de02a5.

Binds both the layer and the admin connection: the admin connection seeds
fixtures the layer reads back, so it must sit in the same partition or the
layer cannot see its own setup. Three reads that relied on the unbound default
now pass the project id, matching how production callers thread
`layer.projectId` -- getLiveTaskColumn resolves a missing id to the sentinel
partition, so omitting it looked in the wrong place once rows were bound.

No product code changes. 24/24.

The same binding does NOT fit the satellite suites and they are left alone:
satellite-fusiondir has a test asserting the unbound APIs fail closed (binding
defeats its premise) and another that binds two projects itself, so that
harness needs an opt-out parameter rather than a blanket bind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 23:06:20 -07:00
gsxdsm
beae12a4bf FN-8034: enforce component and token reuse
Document standing guidance that keeps UI implementations consistent with existing systems.

- Require reuse of components, primitives, hooks, and helpers before creating alternatives.
- Require dashboard styling to use design tokens and component-scoped CSS.
- Link the styling guide, token source, and documented solution patterns.

Files changed:
 AGENTS.md | 8 ++++++++
 1 file changed, 8 insertions(+)

Fusion-Task-Id: FN-8034

Fusion-Task-Lineage: f0435e22-8e8e-471e-b188-7e1a732c2e41

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 23:01:27 -07:00
gsxdsm
1d6a0449ce fix(engine): keep replan cards plannable when they carry prior steps
Tasks piled up in the Planning column and never moved. hasAdvancedPastPlanning
counted steps.length > 0 as proof a card had advanced past planning, but a
replan card legitimately retains the steps its previous planning pass
materialized. The still-in-planning guard therefore failed for every card
Plan Review sent back, so triage's specifyTask claim silently skipped its
status:"planning" write and re-claimed the same cards every poll — never
planning them, and starving healthy cards out of the maxTriageConcurrent
slots they held.

Steps are no longer advancement evidence while a card sits in a planner lane:
the "triage" column, and the merged "todo" planner lane used by plan-in-place
workflows when the card carries a planning status. Worktrees and
execution/terminal columns remain durable advancement evidence, preserving
FN-7977's protection against a recovery write clobbering a card that raced
ahead into execution.

The primary claim path now warns instead of returning silently; recovery-write
skips stay silent by design. The silence is why this stalled the planner for
hours undiagnosed.

Regression coverage asserts the invariant across both planner surfaces rather
than the reported repro alone: triage cards with and without an explicit
needs-replan status, plan-in-place todo replans, every parked-for-planning
status, and the advancement signals that must still fire.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 22:53:49 -07:00
gsxdsm
7b31d54b98 fix(FN-8004): make AI merge rejections actionable and stranded merges retryable (#2160)
Two follow-ups to FN-8004. Both were found by watching FN-8004's *own*
merge livelock for 40 minutes — it turned out to be blocked by the very
class of bug it was filed to fix.

## 1. AI merge rejections lost their reasons

The reviewer prompt said **both** of these:

> "**End with a single decision line**: `REVIEW_VERDICT:
approve|reject`"
> "**Then list each concrete reason as a bullet.**"

Those are impossible to satisfy at once. Reviewers obeyed "End with" and
wrote their reasoning *above* the verdict — but `extractRejectReasons`
only scanned lines *after* it. So every such rejection collapsed to the
placeholder `reviewer rejected the merge without a stated reason`, and
that placeholder was then handed to the corrective re-merge pass **as
its instruction**. The pass got no actionable feedback and just
re-rolled the merge.

The evidence, from FN-8004's own merge — the pattern repeated across
*both* attempts:

| | Attempt A | Attempt B |
|---|---|---|
| review pass 1 | rejected, no reason (03:46) | rejected, no reason
(03:57) |
| corrective pass | 1/3 | 1/3 |
| review pass 2 | **approved** `a3a3cc6a8` (03:49) | approved |

A reviewer that rejects and then approves identical content isn't
objecting — the reason was being thrown away. Each wasted cycle cost ~7
minutes, stretching the merge past main's ~8-minute churn window so
every attempt lost to a concurrent advance and rebuilt. **The livelock
was caused by the lost-reason bug.**

Fix: the parser recovers reasons from either side of the verdict (inline
→ after → before, nearest-first so the closing argument leads, capped at
8 so a long transcript can't flood the corrective prompt), skipping
severity/verdict/markdown scaffolding. The prompt ordering is now
unambiguous — reasons first, verdict last, nothing after it.

## 2. An orphaned merge-active stamp was un-retryable by hand

The Retry gate refused **every** merge-active status (`Task is not in a
retryable state (current status: landing)`), while self-healing cleared
stale stamps automatically minutes later. So a merger killed mid-flight
— crash, engine restart, operator SIGTERM — blocked the operator's own
escape hatch at exactly the moment they'd reach for it. FN-8004 hit
this: a killed merge left `landing` stamped and Retry 400'd for the full
sweep delay.

`isStaleMergeActiveStatus` now lives in the leaf
`merge-active-status.ts`, shared by `recoverStaleMergingStatus` and the
Retry gate — so **the manual path can never be stricter than the
automatic one**. This is the same one-concept-two-definitions bug as
FN-8004's transient classifier, which is why it's worth fixing
structurally rather than adding another special case.

A live merge stays protected by two independent signals: it holds the
in-process lease **and** refreshes `updatedAt` each phase. Staleness
fails closed on an unparseable timestamp.

One subtlety worth reviewing: the bypass feeds `isInReviewRetry` rather
than only the gate. A bare gate bypass would fall through to the generic
branch and move fully-executed work to `todo`, **re-running finished
work** — a bug this fix could easily have introduced.

## Verification

- Gate green (294 + 122 + 63) · lint clean · engine + dashboard
typecheck clean · `verify:fast` PASS
- 70 merger-suite tests green; all 7 pre-existing verdict-parser tests
still pass (backward compatible — none of them covered the verdict-last
layout, which is exactly why this shipped)
- **The route regression test was confirmed non-vacuous**: neutralizing
the fix fails the two "now retryable" cases while the three
live-merge-protection cases still pass, proving they guard real behavior
rather than the new code.
- Regression tests assert the invariant across every surface per *Fix
the Invariant, Not the Repro*: all five `ACTIVE_MERGE_STATUSES` (a
merger can die in any phase, not just the reported `landing`), both
live-merge signals, boundary conditions, fail-closed paths, and that
pre-existing retry paths are unchanged. Test files carry the required
`## Symptom Verification` and `## Surface Enumeration` sections.

🤖 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**
* AI merge rejections now reliably include concrete, correctly ordered
reasons, even when provided before the verdict line.
* Manual retry can recover tasks stuck in stale merge-processing states.
* Retry is still blocked for tasks tied to active merge activity or
recently updated/advancing merges.
  * Existing failed-merge retry behavior remains unchanged.

* **Reliability**
* Improved shared handling of “orphaned” merge-active detection across
the engine and dashboard.

* **Tests**
* Added/expanded coverage for merge-active staleness, retry eligibility,
and verdict/reason parsing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 22:43:24 -07:00
gsxdsm
471835de3d FN-8031: render planning summaries as Markdown by default
Render planning summary descriptions as formatted Markdown on first display.

- Initialize the planning summary view in Markdown preview mode.
- Update interaction tests for preview-first description editing.
- Add a patch changeset for the planning summary behavior.

Files changed:
 .changeset/fn-8031-planning-summary-markdown.md     |  7 +++++++
 .../dashboard/app/components/PlanningModeModal.tsx  |  6 +++++-
 .../PlanningModeModal.ui-interactions.test.tsx      | 21 +++++++++++++++------
 3 files changed, 27 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-8031

Fusion-Task-Lineage: 4e0647a4-a44c-4774-937f-c9e6144837de

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 22:25:09 -07:00
gsxdsm
889fbf709e FN-8022: fix stale GitHub route tests
Refresh GitHub route tests for asynchronous audit lookup and project-scoped conflict reclaim.

- Mock asynchronous run-audit reads for done-task diff resolution
- Cover file-diff responses resolved from audit commit SHAs
- Provide the test project ID for PR conflict reclaim routes

Files changed:
 packages/dashboard/src/__tests__/routes-github.test.ts | 47 ++++++++++++++++++++--
 1 file changed, 44 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-8022
Fusion-Task-Lineage: f7557c0d-f9fd-4f57-8b4f-aee9d0a29364
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 22:19:28 -07:00
gsxdsm
b51de02a54 Revert "fix(core): resolve unbound project ids to a real partition or no filter"
This reverts commit a048a619fc.
2026-07-15 22:14:14 -07:00