Commit Graph

10373 Commits

Author SHA1 Message Date
gsxdsm
4234d5d6da docs: drop the Command Center stat table, keep the graph images
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:27:12 -07:00
gsxdsm
f2c1a28eab fix(workspace): re-read task before workspaceWorktrees merge; FNXC format
Addresses the follow-up review on the foundation fixes:
- Re-read the task via store.getTask immediately before merging the per-repo
  entry, so a concurrent sibling-repo acquisition that landed since the initial
  read isn't clobbered by updateTask's wholesale map replace (narrows the
  read-modify-write window to the store lock; a fully atomic per-repo store-level
  merge remains a follow-up).
- Normalize the inline FNXC comment to the FNXC:Area yyyy-MM-dd-hh:mm: convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:26:40 -07:00
gsxdsm
9f0492e69f fix(review): address PR #1713 review findings
- base-commit-capture.ts: shell-quote integration branch with a real
  single-quoted POSIX literal instead of JSON.stringify (not shell-safe).
- TaskCard.tsx: memo compares full workspaceWorktrees values, not just key
  sets, so a same-key worktreePath/branch change re-renders.
- TaskDetailModal.tsx: gate/render workspace summary off hydrated workingTask.
- worktree-acquisition.ts: null the singular worktree/branch columns in the
  workspaceWorktrees write so isWorkspaceTask stays true; wrap non-fatal
  post-acquire observability so logEntry/audit can't re-escalate to fatal.
- agent-tools.ts: register sub-repo worktree via onAcquired unconditionally
  (idempotent) so a resumed/already-acquired path is tracked after restart.
- executor.ts: DB liveness fallback also checks task.workspaceWorktrees paths.
- executor-workspace.test.ts: root non-git assertion runs in fx.rootDir (".").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:22:48 -07:00
gsxdsm
f4a9c65509 fix(review): address PR #1714 review findings
- base-commit-capture: POSIX single-quote integration branch refs instead of
  JSON.stringify (double quotes are subject to $-expansion in the shell)
- executor: add per-repo no_commits guard to the workspace verifyWorktreeInvariants
  branch (parity with the singular path), gated by the same task-wide no-commit
  eligibility
- executor: reviewWorkspacePerRepo failure message now states the per-repo verdict
  list is partial (evaluation stops at first failure)
- worktree-acquisition: defensively wrap non-fatal/outer-catch logEntry/audit so a
  logging throw cannot promote a non-fatal error to fatal or mask the original error
- docs/plans: add code-fence language tags and fix MD028 blank-line-in-blockquote

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:21:49 -07:00
gsxdsm
accb32e9b6 fix(review): address PR #1711 review findings
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:19:15 -07:00
gsxdsm
dd8129a271 docs: reframe README as a software factory and refresh feature media
- Lead with "a software factory, run by a multi-agent orchestrator" and
  emphasize the plan/build/review/ship assembly-line framing.
- Move the Quick start section directly above "The flow".
- Re-render the workflow GIFs (Tokyo Night, Shadcn Light, Dark Gray) to
  pan across the graph nodes with no lingering selection.
- Refresh the agent chat GIF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:17:12 -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
64e87f9a12 feat(workspace): Phase C U3 — per-repo land lease (serialize same-sub-repo lands)
landWorkspaceTask now holds a per-repo land lease around each landOneRepo call:
a new activeSessionRegistry kind "workspace-repo-land" keyed on the sub-repo
absolute path, registered synchronously before the per-repo try and released in
a finally (on success and failure, only yanking our own taskId+ownerKey entry —
never a foreign/different-kind entry). Two workspace tasks landing the same
sub-repo serialize; the loser throws the retryable WorkspaceRepoLandBusyError,
which reuses the U2 partial-land retry/park machinery (consume a mergeRetry,
backoff re-enqueue up to MAX skipping landed repos, then operator-park). Disjoint
sub-repos never falsely serialize.

The lease is for serialization / clean-room-collision avoidance, not ref
correctness — advanceIntegrationBranchRef's CAS already makes interleaved
update-ref safe. Distinct from the execution-phase "workspace-repo-acquire" lease
(different kind, different lifecycle phase, each ignores the other's entry).

3 new tests (serialize, independence, release-on-failure); oracle (56) + U1/U2
(idempotency) 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:56:41 -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
5191e1f22d FN-6911: defer Droid CLI startup probes
Defer Droid CLI validation and discovery so startup no longer spawns or hangs on droid.

- Register the Droid provider without boot-time validation or model discovery side effects.
- Trigger CLI validation only when a Droid stream starts and expose explicit model discovery.
- Add regression coverage for non-interactive droid process spawning and startup probe behavior.
- Add a patch changeset for the published Fusion CLI package.

Files changed:
 .changeset/fn-6911-droid-cli-no-boot-spawn.md      |  5 ++
 .../commands/__tests__/droid-cli-extension.test.ts | 15 +++-
 packages/droid-cli/index.ts                        | 33 ++++----
 packages/droid-cli/src/__tests__/index.test.ts     | 90 +++++++++-------------
 .../src/__tests__/discover-models.test.ts          |  7 +-
 .../src/__tests__/probe.test.ts                    |  8 ++
 .../src/__tests__/process-manager.test.ts          | 74 ++++++++++++++++++
 .../src/__tests__/startup-probes.test.ts           |  5 +-
 8 files changed, 160 insertions(+), 77 deletions(-)

Fusion-Task-Id: FN-6911

Fusion-Task-Lineage: ef4bc3df-bfe8-416a-b701-64f752faea30
2026-06-21 23:44:26 -07:00
gsxdsm
a91388198b FN-6899: make right dock persistent
Make the right dock a persistent far-right surface with its own collapse control.

- Default the right dock to visible and preserve a collapsed rail instead of hiding it entirely.\n- Remove Header right-dock toggle props and routing so More views remains a menu and left-sidebar mode has no duplicate Header toggle.\n- Update docs, changeset, and regression tests for persistent dock behavior.\n\nFiles changed:\n .changeset/fn-6899-click-revealed-right-dock.md    |  5 ++\n docs/dashboard-guide.md                            |  6 +-\n packages/dashboard/app/App.tsx                     |  1 -\n .../mobile-feature-access-regression.test.tsx      | 32 ++------\n packages/dashboard/app/components/Header.tsx       | 57 +++-----------\n packages/dashboard/app/components/RightDock.css    | 18 +++++\n packages/dashboard/app/components/RightDock.tsx    | 86 ++++++++++++----------\n .../app/components/__tests__/Header.test.tsx       | 57 +++-----------\n .../app/components/__tests__/RightDock.test.tsx    | 31 ++++++--\n .../app/components/useRightDockController.tsx      |  4 +-\n 10 files changed, 132 insertions(+), 165 deletions(-)

Fusion-Task-Id: FN-6899

Fusion-Task-Lineage: 96c4ba70-eb73-4034-8254-6a192402d905
2026-06-21 23:37:25 -07:00
gsxdsm
79e53e8d97 fix(workspace): remove unused acquireWorkspaceRepoWorktree import
The foundation imports acquireWorkspaceRepoWorktree in executor.ts but
deliberately stops before wiring it into the executor lifecycle, so the import
is unused and fails @typescript-eslint/no-unused-vars (the sole Lint failure on
this PR). Remove the dead import; it is reintroduced with real usage in the
session-scoping follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 23:37:12 -07:00
gsxdsm
744ed098a5 feat(workspace): Phase C U1 — per-repo merge loop (landOneRepo + landWorkspaceTask)
Extracts the per-repo land mechanics out of runAiMerge's inline clean-room
closure into an exported landOneRepo(store, repoRootDir, branch, integrationBranch,
ctx): pre-merge prune (rooted at the sub-repo), the clean-room temp worktree,
mergeAndReview, landSquash, and the CAS concurrent-advance retry that advances ONE
local integration ref — no remote push. runAiMerge is rewired as the single-repo
caller (its task-global finalization unchanged); the merger-ai suite (56 tests)
stays green as the byte-for-byte oracle.

landWorkspaceTask loops a workspace task's acquired sub-repos (sorted keys),
re-resolving each repo's integration branch with the shared override stripped
({...settings, integrationBranch: undefined, baseBranch: undefined}) so each
sub-repo lands on its own origin/HEAD, calls landOneRepo per repo, and aggregates
repo-tagged results — land-as-you-go on each repo's LOCAL ref (D2/D5). It does NOT
finalize/move the task (finalize-once + landed-tracking + idempotent retry are U2).

Door routing (KTD2): the engine dispatch and the user-facing CLI `fn task merge`
+ dashboard merge doors route workspace tasks to landWorkspaceTask so manual merge
works; store.mergeTask, aiMergeTask, and the runAiMerge chokepoint guard keep
throwing WorkspaceTaskMergeError as defense-in-depth.

New two-repo fixture tests: both repos land + no-push assertion, per-repo
override-stripped resolution onto distinct branches, repo-B conflict partial land
(task not moved), defense-in-depth throws. Gate green: typecheck, lint, build,
test:gate (649+58).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 23:31:43 -07:00
gsxdsm
8d815f00cf docs: refresh README with feature showcase and media
Shrink the wordmark and add a "See it in action" section showcasing
Command Center, selectable workflows, agent chat, multi-agent chat
rooms, and agent mail. Each feature pairs a looping GIF with value
copy; Command Center adds live fleet stats, graph highlights, and
split light/dark color-theme grids.

New screenshots and GIFs committed under demo/assets/ — Tokyo Night
plus Shadcn Light and Shadcn Dark Gray variants. Workflow GIFs show
the Stepwise coding graph with node-level zoom/pan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 23:24:03 -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
edd79a87dc docs(workspace): Phase C plan — per-repo merge loop (U5/U6/U7), forks resolved 2026-06-21 23:15:38 -07:00
gsxdsm
7fd14eb88c FN-6907: rename task documents to artifacts
Rename the task-modal Documents tab to Artifacts and include task-scoped media outputs alongside task documents.

- Add shared artifact media rendering for global and task-local artifact cards.
- Surface image, video, audio, document, and generic artifacts in the task Artifacts tab.
- Update tab labels, empty states, counts, translations, tests, docs, and release notes for the Artifacts wording.

Files changed:
 .changeset/fn-6907-task-artifacts-tab.md           |   5 +
 docs/dashboard-guide.md                            |   5 +-
 .../dashboard/app/components/ArtifactMedia.tsx     |  55 +++++++
 .../dashboard/app/components/DocumentsView.tsx     |  47 +-----
 .../dashboard/app/components/TaskDetailModal.tsx   |   3 +-
 .../dashboard/app/components/TaskDocumentsTab.css  |  33 +++++
 .../dashboard/app/components/TaskDocumentsTab.tsx  | 109 ++++++++++++--
 .../TaskDetailModal.attachments-and-tabs.test.tsx  |   4 +-
 .../TaskDetailModal.definition-actions.test.tsx    |  20 +--
 .../components/__tests__/TaskDocumentsTab.test.tsx | 160 ++++++++++++++++++++-
 packages/i18n/locales/en/app.json                  |  16 ++-
 packages/i18n/locales/es/app.json                  |  16 ++-
 packages/i18n/locales/fr/app.json                  |  16 ++-
 packages/i18n/locales/ko/app.json                  |  16 ++-
 packages/i18n/locales/zh-CN/app.json               |  16 ++-
 packages/i18n/locales/zh-TW/app.json               |  16 ++-
 16 files changed, 436 insertions(+), 101 deletions(-)

Fusion-Task-Id: FN-6907

Fusion-Task-Lineage: a1318ed5-4d47-42f8-8b6c-fe91506e11fb
2026-06-21 23:07:55 -07:00
gsxdsm
14114f5f51 docs(workspace): note Phase B review hardening in the U2 changeset 2026-06-21 23:07:35 -07:00
gsxdsm
453ed92dbf fix(review): Phase B workspace hardening — fail-closed scope guard, review conjunction, .changeset carve-out
ce-code-review (4 personas) on Phase B. No P0; the review conjunction was
confirmed safe (no false-done — empty map and per-repo throws both route to
UNAVAILABLE, which blocks). Applied:

P1: the fn_task_done scope-leak guard now fails CLOSED in workspace mode — a
per-repo capture throw blocks completion ("refusing as a precaution") instead of
the outer .catch returning {blocked:false} and letting an incomplete check pass.
A scoped task that acquired ZERO sub-repo worktrees is now blocked rather than
silently passing scope enforcement.

P2: reviewWorkspacePerRepo breaks on the first non-APPROVE repo so a later repo's
throw can't discard an already-determined REVISE (callers were seeing UNAVAILABLE
instead). captureWorkspaceModifiedFiles isolates each per-repo capture in
try/catch so one repo's throw can't skip the modifiedFiles write. The .changeset
always-allowed carve-out is honored in workspace mode: the scope-leak branch now
filters repo-LOCAL paths via the (previously dead) workspace-paths.ts
deriveRepoScopeSubset helper through the same filter as the singular path, so a
sub-repo .changeset/* no longer falsely blocks fn_task_done. All four per-repo
loops iterate sorted keys for deterministic offending-repo reporting; the dead
repoRel callback param and the duplicate path-normalizer are removed.

Verified safe (no change): the reviewer semaphore releases on throw (try/finally),
and per-repo reviewers inherit the task abort via session disposal.

Deferred to Phase C: extracting a workspace-executor.ts module (before the merge
loop lands). Gate green: typecheck, lint, build, test:gate (649+58).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 23:02:46 -07:00
gsxdsm
f4d2fa2ece FN-6910: hide subtask quick-add behind experiment
Hide the AI subtask-breakdown quick-add action unless the experimental flag is explicitly enabled.

- Gate Subtask Breakdown callbacks from App on the default-off subtaskBreakdown experiment.
- Remove Subtask quick-add buttons from inline create and quick entry surfaces when no callback is wired.
- Add settings, quick-add, documentation, and changeset coverage for the new experiment toggle.

Files changed:
 .changeset/fn-6910-subtask-breakdown-flag.md       |  5 ++++
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/App.tsx                     |  8 ++++---
 .../dashboard/app/components/InlineCreateCard.tsx  | 27 ++++++++++++----------
 .../dashboard/app/components/QuickEntryBox.tsx     | 27 ++++++++++++----------
 .../dashboard/app/components/SettingsModal.tsx     |  2 ++
 .../components/__tests__/InlineCreateCard.test.tsx | 13 +++++++++++
 .../components/__tests__/QuickEntryBox.test.tsx    | 12 ++++++++++
 .../components/__tests__/SettingsModal.test.tsx    | 13 +++++++++++
 9 files changed, 81 insertions(+), 28 deletions(-)

Fusion-Task-Id: FN-6910

Fusion-Task-Lineage: a7738b1f-7b41-438d-bd94-79ef56928262
2026-06-21 23:02:16 -07:00
gsxdsm
c78b44ce4c FN-6909: allow narrower list sidebar
Lower the desktop list-view sidebar minimum width while keeping resize behavior covered.\n\n- Reduce the shared list sidebar clamp from 200px to 120px.\n- Update keyboard resize expectations for stored widths below the new minimum.\n\nFiles changed:\n packages/dashboard/app/components/ListView.tsx               |  2 +-\n .../dashboard/app/components/__tests__/ListView.test.tsx     | 12 ++++++------\n 2 files changed, 7 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-6909

Fusion-Task-Lineage: 0bf345af-c94d-4f73-bb03-e7e43a6bb398
2026-06-21 22:57:01 -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
0367fa54d9 docs(workspace): Phase B implementation plan (U3/U4) 2026-06-21 22:44:53 -07:00
gsxdsm
81edbeefbd feat(workspace): Phase B U2 — per-repo review (both sites) + fn_task_done verify + scope-leak
In workspace mode both review entry points and the completion guards now iterate
every acquired sub-repo. A shared reviewWorkspacePerRepo loops task.workspaceWorktrees
and invokes the existing single-cwd reviewStep once per repo (cwd = the sub-repo —
the reviewer agent runs its own git diff there), aggregating repo-tagged verdicts
as a conjunction: the task is reviewed only if every repo APPROVEs; the first
non-APPROVE repo's verdict becomes the aggregate. Both call sites loop — the
in-session fn_review_step tool AND the step-inversion seam (createReviewStepTool
and the stepReview workflow seam) — so no review surface silently scopes to the
non-git root (FN-5893). reviewStep itself stays single-cwd; the callers loop.

fn_task_done completion verification iterates per repo: verifyWorktreeInvariants
(from U1) already covers all worktrees, and evaluateTaskDoneScopeLeak now loops
each sub-repo (cwd + repo.baseCommitSha, repo-prefixed touched files vs the
repo-prefixed declared File Scope), blocking on the first repo with off-scope
files and naming it. Both return shapes preserved (ReviewResult; {blocked,message}).

New workspace-paths.ts repo-prefix helper (deriveRepoForPath/splitRepoScopedPath/
deriveRepoScopeSubset; segment-wise longest-prefix match, unscoped fallback) —
master U5 reuses it. Singular non-workspace path unchanged. 16 new fixture tests.
Gate green: typecheck, lint, build, test:gate (649+58).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 22:44:40 -07:00
gsxdsm
7034b55288 FN-6887: add footer terminal launcher
Move terminal access from the header into a footer launcher and resizable bottom panel.

- Add a TerminalLauncher footer control with dock, resize, collapse, and pop-out affordances.
- Extend TerminalModal to support bottom-panel layout, drag resizing, and persistent panel state.
- Remove terminal/script controls from header overflow while preserving compact Mailbox and tool ordering.
- Update executor footer spacing, dashboard docs, changeset, and focused terminal/header tests.

Files changed:
 .changeset/fn-6887-terminal-footer-panel.md        |   5 +
 docs/dashboard-guide.md                            |   2 +
 packages/dashboard/app/App.tsx                     |   6 +-
 .../app/__tests__/tablet-header-controls.test.tsx  |  95 +---
 .../dashboard/app/components/ExecutorStatusBar.css |   8 +
 .../dashboard/app/components/ExecutorStatusBar.tsx |  27 +-
 packages/dashboard/app/components/Header.css       |  27 -
 packages/dashboard/app/components/Header.tsx       | 549 +--------------------
 .../dashboard/app/components/TerminalLauncher.css  | 180 +++++++
 .../dashboard/app/components/TerminalLauncher.tsx  | 306 ++++++++++++
 .../dashboard/app/components/TerminalModal.css     | 117 +++++
 .../dashboard/app/components/TerminalModal.tsx     | 360 +++++++++++++-
 .../__tests__/ExecutorStatusBar.test.tsx           |  52 +-
 .../app/components/__tests__/Header.test.tsx       | 304 ++----------
 .../components/__tests__/TerminalLauncher.test.tsx |  57 +++
 .../components/__tests__/TerminalModal.test.tsx    | 111 +++++
 16 files changed, 1282 insertions(+), 924 deletions(-)

Fusion-Task-Id: FN-6887

Fusion-Task-Lineage: 755f28b1-1ba5-43f8-b13c-264e31507658
2026-06-21 22:43:34 -07:00
gsxdsm
fc9423e465 feat(workspace): Phase B U1 — per-repo change capture, contamination, and verify
In workspace mode the executor now captures changes and verifies worktree
invariants per acquired sub-repo instead of degrading to empty against the
non-git root. Post-session capture (:7898) gains a workspace branch that loops
task.workspaceWorktrees and reuses captureModifiedFiles(repo.worktreePath,
repo.baseCommitSha, …) per repo — inheriting resolveDiffBaseRef's merge-base
fallback (repo baseCommitSha may be undefined) and the filterFilesToOwnTaskCommits
contamination/divergence audit — then prefixes each repo's files with the repo
path into task.modifiedFiles. Branch attribution runs per sub-repo (cwd), never
against the root. The no-op assertCleanBranchAtBase is not iterated.

verifyWorktreeInvariants is un-stubbed for workspace mode: it iterates every
workspaceWorktrees entry asserting toplevel match + HEAD on fusion/<id>, and
returns the FIRST failing repo while preserving the exact discriminated union
{ok:true} | {ok:false; reason:'wrong_toplevel'|'wrong_branch'|'no_commits';
observed; expected} (the :10889 consumer switches on reason for requeue/handoff)
— the new repo field is additive. Singular non-workspace path unchanged.

Real two-repo fixture tests (capture A+B repo-prefixed vs own base, undefined-base
fallback, foreign-commit contamination audit, wrong_branch verify failure,
single-repo regression). Gate green: typecheck, lint, test:gate (649+58).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 22:29:25 -07:00
gsxdsm
8f4897d3aa FN-6905: add build preflight to velocity measurement
Add a non-measured build setup step so velocity baselines do not misclassify missing dist artifacts as lane time.

- Run a default `pnpm build` preflight before measured test velocity lanes, with an explicit skip flag for pre-built CI.
- Add injectable command-runner coverage for preflight ordering, failure reporting, and skip behavior.
- Document the preflight behavior in the generated baseline report and testing docs.

Files changed:
 docs/test-velocity-baseline.md                    |   2 +
 docs/testing.md                                   |   4 +-
 scripts/__tests__/test-velocity-baseline.test.mjs | 159 ++++++++++++++++++++++
 scripts/test-velocity-baseline.mjs                |  38 +++++-
 4 files changed, 195 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-6905

Fusion-Task-Lineage: 3016a542-4395-4d06-9f2e-1a91f4939e07
2026-06-21 22:29:13 -07:00
gsxdsm
cf6718f3c1 FN-6892: show default model for configured prompt nodes
Prompt workflow nodes with inline prompts or names now summarize their default model instead of appearing unconfigured.

- Return the localized Default model summary for model prompt nodes without pinned provider/model settings when prompt or name is present.
- Cover direct prompt summary cases and all built-in workflow prompt nodes to prevent Not configured regressions.
- Add localized summary text and workflow-step documentation for default-model prompt nodes.

Files changed:
 docs/workflow-steps.md                             |  2 +-
 .../nodes/__tests__/node-summary.test.ts           | 32 ++++++++++++++++++++++
 .../dashboard/app/components/nodes/node-summary.ts |  7 +++++
 packages/i18n/locales/en/common.json               |  1 +
 packages/i18n/locales/es/common.json               |  1 +
 packages/i18n/locales/fr/common.json               |  1 +
 packages/i18n/locales/ko/common.json               |  1 +
 packages/i18n/locales/zh-CN/common.json            |  1 +
 packages/i18n/locales/zh-TW/common.json            |  1 +
 9 files changed, 46 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-6892

Fusion-Task-Lineage: 5892429d-22ee-495e-bc40-06cbf81ee471
2026-06-21 22:14:15 -07:00
gsxdsm
c4c8961c1e FN-6903: preserve workflow quick-create visibility
Optimistically attach newly quick-created tasks to the active workflow lane until workflow metadata refetches.

- Update board and list quick-create paths to cache the selected workflow for created tasks immediately.\n- Refresh board-workflows metadata after optimistic assignment so authoritative state reconciles.\n- Cover board/list workflow-lane quick-create visibility with regression tests.\n- Document the workflow-filtered quick-create behavior and add a patch changeset.\n\nFiles changed:\n .../fn-6903-workflow-lane-create-visibility.md     |   5 +\n docs/dashboard-guide.md                            |   2 +-\n packages/dashboard/app/components/Board.tsx        |  34 ++-\n packages/dashboard/app/components/ListView.tsx     |  36 ++-\n ...d-quickcreate-workflow-lane-visibility.test.tsx | 319 +++++++++++++++++++++\n 5 files changed, 390 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-6903

Fusion-Task-Lineage: dd2c6fa1-f2e8-4777-aa3c-69d000efb1b1
2026-06-21 22:04:32 -07:00
gsxdsm
3817ada788 FN-6901: refresh weekly test velocity baseline
Refresh the weekly test velocity report with the latest captured baseline data.

- Advance the documented baseline from 2026-W25 to 2026-W26.
- Record the latest gate, changed-only test, quarantine, and boot-smoke measurement status.
- Append the new measurement row to the persisted test velocity history.

Files changed:
 docs/test-velocity-baseline.md     |  22 +++----
 scripts/test-velocity-history.json | 116 +++++++++++++++++++++++++++++++++++++
 2 files changed, 127 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-6901

Fusion-Task-Lineage: 06f42104-b3c5-4a26-86ee-fb2791f7006d
2026-06-21 21:48:40 -07:00
gsxdsm
d78b8a5c4c FN-6900: keep Git Manager tabs visible on mobile
Keep the Git Manager section tab strip usable in mobile modal layouts.

- Prevent the mobile Git Manager sidebar from shrinking away and preserve horizontal tab scrolling.
- Use token-sized tab touch targets and remove duplicate breakpoint rules that could override the canonical mobile layout.
- Cover mobile tab rendering, section switching, and CSS breakpoint invariants in dashboard tests.

Files changed:
 packages/dashboard/app/components/ScriptsModal.css |  53 ++-------
 .../components/__tests__/GitManagerModal.test.tsx  | 118 +++++++++++++++++++--
 .../__tests__/core-modals-mobile.test.tsx          |   7 +-
 3 files changed, 126 insertions(+), 52 deletions(-)

Fusion-Task-Id: FN-6900

Fusion-Task-Lineage: e9506053-c80d-49ea-bb80-34db51dd50f4
2026-06-21 21:41:19 -07:00
gsxdsm
d5fa8654f7 fix(review): Phase A workspace hardening — tool errors, activeWorktrees, non-fatal acquire
ce-code-review (5 personas) on Phase A. No P0; the workspace-root-removal path
was ruled out and the contract changes verified additive. Applied:

P1: fn_acquire_repo_worktree now catches WorkspaceRepoAcquireBusyError (and
generic failures) and returns a sanitized retryable isError instead of an
uncaught throw into the agent loop; runContext is forwarded so audit/log keep
attribution. Per-repo acquired worktree paths are now registered into the
executor's activeWorktrees Set (via an onAcquired callback) — previously the Set
only held the browse-only root, making the U1 per-repo liveness invariant hollow.
Post-acquire identity-guard install and base-SHA capture are now non-fatal
(log-and-continue): a hook/branch failure no longer strands the on-disk worktree
(the worktree is usable without the guard; an undefined baseCommitSha is already
an accepted state).

P2: the KTD3 settings-strip also strips settings.baseBranch (resolveFromSettings
falls back integrationBranch → baseBranch, so a shared baseBranch leaked); the
workspaceWorktrees write re-reads the task fresh before merging to avoid a
sibling-repo clobber on sequential acquires (store-level atomic merge deferred to
Phase B); the busy-path logging is wrapped so it can't mask the busy error; the
TaskCard memo compares key-sets not counts; the stuck-kill no-op for workspace
tasks is now logged; the exclusivity check-then-act synchrony is documented.

Residuals (Phase B): per-repo worktree teardown, orphan-scan coverage, reaper
dedup, store-level atomic merge.

Gate green: typecheck, lint, build, test:gate (649+58), affected (25 + TaskCard 251).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:33:56 -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
gsxdsm
1fa3691f1f docs(workspace): Phase A implementation plan (U1/U2/U10) 2026-06-21 21:07:32 -07:00
gsxdsm
023e4b057d feat(workspace): Phase A U3 — dashboard "doesn't look broken" floor
Workspace tasks (no task.worktree, populated workspaceWorktrees) now render in
existing task views without crashing or going blank. New read-only
WorkspaceWorktreesSummary component (placeholder "N repos acquired" + a flat
repo→worktree/branch list — within the "doesn't look broken" ceiling, not a rich
status UI); TaskCard and TaskDetailModal nil-guard on isWorkspaceTask. Single-repo
rendering unchanged. CONCEPTS.md notes workspace-task merges are non-atomic
(repos land independently on local integration refs; partial-land is local and
operator-resettable). Tests 8/8; TaskCard regression 251/251.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:07:20 -07:00
gsxdsm
09bd01baf0 feat(workspace): Phase A U1 — executor session scoping for workspace mode
In workspace mode (loadWorkspaceConfig present), the executor now skips the
root acquireTaskWorktree({rootDir}) and every intervening rootDir git preflight
(base-commit capture, contamination, identity-guard, verifyWorktreeInvariants),
runs the agent session rooted at the non-git workspace root (cwd=rootDir,
browse-only; task.worktree never set), and tracks activeWorktrees as a per-task
Set<path>. scopePromptToWorktree is a no-op in workspace mode. The non-workspace
path is unchanged (every change branches on this.workspaceConfig; a single-repo
task holds a one-element Set).

Converted every activeWorktrees consumer to membership semantics (feasibility-
verified list): findActiveWorktreeOwner, hasActiveWorktreeBinding, the FN-6736
phantom-binding reclaim, listWorktreeHolders (flat-maps a Set into N holder rows
— verified the FN-6782 reaper keys off taskId only, so slot accounting is
unaffected), the conflict-set iteration, the three deleteActive* unregister
resolvers (loop every path), cleanup, getWorktreePath (undefined for a
multi-worktree workspace task), and the verifyWorktreeInvariants singular
resolution (gated off in workspace mode — per-repo verify returns in Phase B).

Rewrote executor-workspace.test.ts from vi.mock-the-subject to a real two-repo
git fixture harness (_workspace-fixture.ts, shared with later units), 13 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:07:20 -07:00
gsxdsm
5b33da9268 FN-6882: move toolbar tools into right dock
Move desktop toolbar tools into the right dock while keeping Files as the inline dock view.

- Remove desktop toolbar buttons and overflow menu entries for Activity, Activity Log, GitHub Import, Git Manager, Files, and Automation.
- Convert right-dock registry entries into launcher actions for modal tools and keep Files/plugin entries as expandable inline views.
- Update right-dock selection, expansion, documentation, tests, and release notes for the new tools rail behavior.

Files changed:
 .changeset/fn-6882-toolbar-to-right-sidebar.md     |   5 +
 docs/dashboard-guide.md                            |  10 +-
 packages/dashboard/app/App.tsx                     |   2 +-
 .../app/__tests__/tablet-header-controls.test.tsx  |   6 +-
 packages/dashboard/app/components/Header.css       |   3 -
 packages/dashboard/app/components/Header.tsx       | 115 +-----------
 packages/dashboard/app/components/RightDock.tsx    |  50 +++--
 .../app/components/RightDockExpandModal.tsx        |  10 +-
 .../app/components/__tests__/Header.test.tsx       | 112 +++++------
 .../app/components/__tests__/RightDock.test.tsx    | 189 +++++++++++--------
 .../__tests__/overflowViewRegistry.test.tsx        |  73 +++++---
 .../app/components/overflowViewRegistry.tsx        | 204 ++++++---------------
 .../app/components/useRightDockController.tsx      |  10 +
 13 files changed, 323 insertions(+), 466 deletions(-)

Fusion-Task-Id: FN-6882

Fusion-Task-Lineage: 4b423b3e-ff82-41d4-83f9-7cff23361e81
2026-06-21 20:55:28 -07:00
gsxdsm
e4a810e9b4 fix(FN-6880): address PR review feedback (#1712)
- Reject failure-condition edges inside optional-group templates (the single-pass
  walk surfaces template failures as the group's outcome, so an internal failure
  edge was silently dead) — Greptile P2.
- flowToIr: a container/group node (foreach/loop/optional-group) is v2-only — its
  presence now forces v2 serialization (an inserted optional-group on a plain
  workflow no longer serializes as invalid v1) — CodeRabbit.
- Disabled optional-group bypass routes a plain success with no distinguishing
  value, so an outcome:* edge can't preempt success routing (inertness) — CodeRabbit.
- Downgrade heuristic: presence of a legacy optionalSteps key (incl. []) keeps v2.
- Resolver docblock corrected (config-less groups resolve to a fallback entry).
- Strengthen tests: assert both inserted groups + v2 round-trip; failure-edge
  rejection case.
- Changeset: bump to major (removed exported WorkflowOptionalStep type).
- Plan: record U7a as delivered in this cohort; only the workflow-step seam
  infra removal remains deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:47:31 -07:00
gsxdsm
beaf52bb50 FN-6898: stabilize ci-status plugin tests
Rescue the ci-status plugin test suite by making CI polling deterministic and network-free.

- Stub global fetch for the full suite so refresh handlers and interval polls cannot reach ci.example.com.
- Share the mock task fixture across refresh and task-move tests.
- Cover tracked-branch and empty-branch refresh paths plus interval polling behavior.

Files changed:
 .../src/__tests__/index.test.ts                    | 145 ++++++++++++++++-----
 1 file changed, 115 insertions(+), 30 deletions(-)

Fusion-Task-Id: FN-6898

Fusion-Task-Lineage: 3758d995-bda9-4ab9-add7-e6a3f710dc6f
2026-06-21 20:40:59 -07:00
gsxdsm
68d3c5820e docs(FN-6880): capture optional-group toggle-id collision learning
Document the code-review P1 as a logic-errors learning: a per-task graph
toggle (enabledWorkflowSteps, keyed by optional-group node id) collided with
the legacy step-template namespace and was silently remapped by the store
resolver, bypassing an enabled group. Cross-references the per-task-override
blast-radius cousins as the id-namespace-collision variant of that class.
Seeds an "Optional step group" entry in CONCEPTS.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:33:32 -07:00
gsxdsm
316d2659b8 fix(review): workspace-merge park must use status:'failed' to avoid re-enqueue loop (U0)
Post-fix verification review (correctness + adversarial + reliability, unanimous
P0) found that the earlier retry-burn fix introduced an infinite loop: parking a
WorkspaceTaskMergeError task with status:null + mergeRetries:0 passes every
auto-merge eligibility gate (canMergeTask short-circuits only on status==='failed'),
so the cooldown sweep re-enqueues it every tick → guard re-throws → re-park, forever.

- Park with status:'failed' (keep mergeRetries:0). canMergeTask now blocks the
  auto-sweep; a human's manual merge still works because it flows through the
  manual-resolver branch (rejectMergeResolvers), which bypasses canMergeTask — so
  'failed' does not block manual retry (the original comment's worry was wrong).
- Detect the error via `err instanceof Error && err.name === "WorkspaceTaskMergeError"`,
  matching the VerificationError/MergeAbortedError convention and bundle-safe across
  the @fusion/core→@fusion/engine boundary (drops the now-unused class import).
- Document that the dispatch door guard is a fast-fail only; the unconditional
  chokepoint guard inside runAiMerge is the authoritative enforcement.
- Add a regression test asserting the auto-merge park sets status:'failed' (not null).

Gate green: lint, typecheck, build, test:gate (649+58), project-engine (81).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:29:46 -07:00
gsxdsm
4fec139927 FN-6881: move stash recovery into Git Manager
Move stash recovery into the Git Manager while retiring the standalone dashboard route.

- Add a Recovery section to Git Manager that hosts the existing StashRecoveryView.
- Remove stash recovery from top-level, overflow, mobile, and lazy-loaded view registries.
- Preserve orphaned-stash counts on Git Manager entry points and migrate saved stash-recovery routes back to Board.
- Update dashboard docs, lazy-load inventory, tests, and add a published package changeset.

Files changed:
 .changeset/fn-6881-stash-recovery-git-manager.md   |  5 +++
 AGENTS.md                                          |  3 +-
 docs/dashboard-guide.md                            |  9 ++--
 packages/dashboard/app/App.tsx                     | 13 ------
 .../app/__tests__/lazy-loaded-views-docs.test.ts   | 11 ++---
 .../dashboard/app/components/GitManagerModal.tsx   | 19 +++++++-
 packages/dashboard/app/components/Header.css       |  9 ++++
 packages/dashboard/app/components/Header.tsx       | 22 +++-------
 .../dashboard/app/components/LeftSidebarNav.tsx    |  4 --
 packages/dashboard/app/components/MobileNavBar.tsx | 16 +------
 .../components/__tests__/GitManagerModal.test.tsx  | 51 ++++++++++++++++++++++
 .../app/components/__tests__/Header.test.tsx       | 21 +++++++++
 .../components/__tests__/LeftSidebarNav.test.tsx   | 10 ++---
 .../app/components/__tests__/MobileNavBar.test.tsx | 10 +++++
 .../app/components/__tests__/RightDock.test.tsx    |  4 +-
 .../__tests__/overflowViewRegistry.test.tsx        |  3 +-
 .../app/components/overflowViewRegistry.tsx        | 10 -----
 packages/dashboard/app/hooks/__tests__/useViewState.test.ts       | 28 ++++++++++++
 packages/dashboard/app/hooks/useViewState.ts       | 19 +++++++-
 packages/dashboard/src/view-chunk-manifest.ts      |  1 -
 20 files changed, 184 insertions(+), 84 deletions(-)

Fusion-Task-Id: FN-6881

Fusion-Task-Lineage: 467d34ec-8a6a-46db-8eb8-cb0216c031da
2026-06-21 20:28:33 -07:00
gsxdsm
15d427bc11 FN-6886: move planning mode into sidebar view
Planning Mode now opens as a top-level embedded dashboard view instead of a header modal affordance.

- Add Planning to the left sidebar navigation and persisted task-view registry.
- Mount PlanningModeModal as an embedded main-content view while preserving initial-plan and resume-session payloads.
- Remove legacy desktop and compact header planning buttons so compact layouts have one canonical MobileNavBar planning entry.
- Update dashboard navigation tests and add a published package patch changeset.

Files changed:
 .changeset/fn-6886-planning-sidebar-view.md        |   5 +
 packages/dashboard/app/App.tsx                     |  47 ++++++--
 .../app/__tests__/tablet-header-controls.test.tsx  |  16 +--
 packages/dashboard/app/components/AppModals.tsx    |  20 ----
 packages/dashboard/app/components/Header.tsx       |  50 +-------
 .../dashboard/app/components/LeftSidebarNav.tsx    |  14 +++
 .../dashboard/app/components/PlanningModeModal.css |  23 ++++
 .../dashboard/app/components/PlanningModeModal.tsx |  29 +++--
 .../app/components/__tests__/App.test.tsx          |  57 ++++-----
 .../app/components/__tests__/Header.test.tsx       | 132 +++------------------
 .../components/__tests__/LeftSidebarNav.test.tsx   |  10 ++
 .../PlanningModeModal.planning-flow.test.tsx       |  25 ++++
 packages/dashboard/app/hooks/useModalManager.ts    |   5 +-
 packages/dashboard/app/hooks/useViewState.ts       |   7 +-
 14 files changed, 188 insertions(+), 252 deletions(-)

Fusion-Task-Id: FN-6886
Fusion-Task-Lineage: 18111cc7-ef2e-40a0-8272-220c01390ae2
2026-06-21 19:52:16 -07:00
gsxdsm
e5382f0d8c refactor(FN-6880): retire the legacy optional-steps declaration surface (U7a)
Optional steps are now graph-native optional-group nodes, so the dead
declaration model is removed: the WorkflowOptionalStep type + WorkflowIrV2
.optionalSteps field + validateOptionalSteps (core), and the editor's
declaration AUTHORING surface — WorkflowOptionalStepsPanel, optionalStepsOf,
and the flowToIr/serializeGraph optionalSteps threading (dashboard). A legacy
persisted optionalSteps key is tolerated (ignored) at parse. The per-task
TOGGLE surfaces (dropdown, inline card, modal, Workflow tab) are unchanged —
they consume ResolvedWorkflowOptionalStep, which stays. The workflow-step seam
infrastructure removal remains a separate documented follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:40:41 -07:00
gsxdsm
a38acaf864 fix(FN-6880): pass optional-group toggle ids through enable resolution (review P1)
Code review found that enabling a built-in optional-group whose node id collides
with a WORKFLOW_STEP_TEMPLATES id (browser-verification) was silently bypassed:
resolveEnabledWorkflowSteps materialized a WorkflowStep row and stored its id
instead of the group node id, so the executor's enabledWorkflowSteps.includes(
node.id) check never matched. Pass the task's workflow optional-group ids through
untouched on both create-with-enable and update/toggle paths (new
resolveAllOptionalGroupIds + optionalGroupIdSet). Add colliding-id regression
tests. Also (review P3) record the group's own outcome on the disabled-bypass
path so a disabled group is fully context-inert, matching the enabled path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:28:42 -07:00
gsxdsm
2db99ec6fd FN-6894: widen workflow switcher menus
Workflow switcher dropdowns now size open menus to fit long workflow names without widening the collapsed trigger.

- Add menu width calculation that combines measured workflow names, option decorations, trigger width, and viewport bounds.
- Measure option names with a canvas when opening/repositioning the dropdown.
- Cover long-name, viewport clamp, trigger sizing, and CSS overflow behavior in WorkflowSwitcher tests.
- Document the open-listbox sizing behavior in the dashboard guide.

Files changed:
 docs/dashboard-guide.md                            |  2 +-
 .../dashboard/app/components/WorkflowSwitcher.tsx  | 49 +++++++++++++-
 .../components/__tests__/WorkflowSwitcher.test.tsx | 78 +++++++++++++++++++++-
 3 files changed, 123 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-6894

Fusion-Task-Lineage: 3f2f8129-3f85-484d-9c0f-b6ebe673b6a9
2026-06-21 19:23:51 -07:00
gsxdsm
7240b77c67 fix(review): harden R7 workspace merge guard + deprecation warning (U0)
Applies ce-code-review (autofix) feedback — 5 reviewers, P1s corroborated.

F1 [P1, ×4 reviewers] Guard the merge chokepoint, not just the 4 doors. The
per-caller `getTask().catch(()=>null); if(t) assert` pattern failed open on a
transient read, and runAiMerge re-read the task unguarded — so a workspace
task could reach git work against the non-git root. Added a named
WorkspaceTaskMergeError and call assertNotWorkspaceTaskMerge inside runAiMerge
(the sole merge path) and the deprecated aiMergeTask body; door guards remain
as fast-fail defense-in-depth.

F2 [P1] The dispatch catch treated the guard throw as a merge failure and set
mergeRetries=MAX, permanently blocking manual retry. It now recognizes
WorkspaceTaskMergeError and parks without burning retries.

F3 [P2] Deprecation-warning test asserted toBeLessThanOrEqual(1) — vacuously
true on zero emissions. Now resets the per-project flag and asserts the
warning fires exactly once and not again on a second deterministic merge.

F6 [P2] The once-per-process warning flag suppressed the notice for all other
projects in a multi-project host; now keyed per project (Set by cwd).

F5/F7/F8 [P3] @deprecated propagated to the aiMergeTask barrel re-export; CLI
runTaskMerge guard moved inside the formatted try/catch; FNXC placeholder
timestamps corrected; test .at(-1) -> length index.

Documented as residual (deferred to master-plan U8, not bugs in U0's window):
self-healing auto-finalize + store.mergeTask are additional merge-completing
paths not hardened here — workspace tasks are not end-to-end runnable until
master-plan Phase A, and U8 makes self-healing workspace-aware.

Gate green: typecheck (29 projects), lint, build, test:gate (649+58),
affected tests (206+4).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:19:55 -07:00
gsxdsm
9ce9f74b5c FN-6880: add sidebar New Task action
Add a persistent New Task entry to the left sidebar so task creation is available from project views.

- Wire the left sidebar to the existing New Task dialog trigger from App.
- Render an accessible, token-styled New Task CTA above sidebar navigation with collapsed rail support.
- Cover the new sidebar affordance behavior and document it in the dashboard guide.

Files changed:
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/App.tsx                     |  1 +
 .../dashboard/app/components/LeftSidebarNav.css    | 27 +++++++
 .../dashboard/app/components/LeftSidebarNav.tsx    | 18 +++++
 .../components/__tests__/LeftSidebarNav.test.tsx   | 83 ++++++++++++++++++++++
 5 files changed, 130 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-6880

Fusion-Task-Lineage: 7d9cffd4-c216-4250-9615-51e7c16438c2
2026-06-21 19:17:06 -07:00
gsxdsm
0c031b8fe8 chore(FN-6880): changeset + record deferred legacy-retirement scope
Add the minor changeset for the optional-group feature (U1-U6) and document in
the plan why the full legacy optional-steps retirement (U7) is deferred: the
workflow-step seam is shared engine infrastructure across ~9 files and the
dashboard still carries the prior declaration authoring surface (~10 files), so
removing the core type without that cleanup breaks the build. The new model is
the live path; the legacy declaration surface is inert pending a focused follow-up.

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