aedee4b8231bf050c3240a00ab6645ede5d87ee9
161 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
866d0280c8 |
test(dashboard): drop px literals from the AgentActivityPanel token comment
The mobile-styles guard forbids raw px anywhere in the stylesheet, comments included; the FN-8866 token-fix comment mentioned the named steps' pixel values and tripped it. Reworded — CSS rules unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
9673f15c11 |
fix(dashboard): repair undefined spacing tokens, settings-search gaps, and census/browser-lane test drift
Dashboard bare-run repair, census/token cluster. Real product bugs: the Command Center activity panel (FN-8866) and structural-mail badge (FN-8872) referenced undefined --space-* tokens, zeroing their gaps/padding — mapped to the defined named scale; the settings search index lagged FN-8829/FN-9021 additions and FN-8855's requiredChecks entry had no scroll anchor (now a SettingsTextRow). Test-side: the theme census learns FN-8730's intentional midnight theme, and the Chromium touch-resize suite self-gates with describe.runIf per the sibling browser-lane convention (CI/FUSION_BROWSER_SMOKE_REQUIRE still fail loudly; all 62 tests still run where Chromium exists). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b7604a94bf |
FN-9041: remove agent state-change activity logs
Remove durable agent state-change events and hide retained state-change rows from activity displays. - Stop AgentStore update and reconciliation paths from writing state-change activity events. - Filter historical state-change events in activity stores and panels while retaining live roster notifications. - Document the retained activity contract, add coverage, and include a patch changeset. Files changed: .changeset/fn-9041-removal.md | 7 ++++ docs/agent-activity-contract.md | 4 ++ docs/architecture.md | 2 +- docs/dashboard-guide.md | 2 +- .../src/__tests__/agent-activity-writers.test.ts | 23 ++++++----- packages/core/src/agents/agent-store.ts | 28 +++++-------- .../app/components/agentsOrgChartActivity.ts | 12 ++++++ .../command-center/AgentActivityPanel.tsx | 25 +++++++---- .../__tests__/AgentActivityPanel.test.tsx | 48 ++++++++++++++++++++++ .../app/hooks/__tests__/agentActivityStore.test.ts | 39 +++++++++++++++++- packages/dashboard/app/hooks/agentActivityStore.ts | 3 +- 11 files changed, 153 insertions(+), 40 deletions(-) Fusion-Task-Id: FN-9041 Fusion-Task-Lineage: 532724b1-5945-4904-b5cd-2c27909805de Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
aac090d0c3 |
FN-8866: add Command Center agent activity timeline
Add a Command Center live agent activity log with historical navigation. - Stream and paginate organization-wide agent activity with timeline filters. - Link activity rows to agent details and task views while reusing feed presentation. - Add localized copy, documentation, a minor changeset, and coverage for live and scroll-back behavior. Files changed: .changeset/fn-8866-agent-activity-surfaces.md | 7 + docs/dashboard-guide.md | 1 + packages/dashboard/app/App.tsx | 12 ++ packages/dashboard/app/components/ActivityFeed.tsx | 77 ++++---- packages/dashboard/app/components/AgentsView.tsx | 13 +- .../__tests__/AgentsView.focus-agent.test.tsx | 59 ++++++ .../command-center/AgentActivityPanel.css | 98 +++++++++ .../command-center/AgentActivityPanel.tsx | 99 ++++++++++ .../components/command-center/CommandCenter.tsx | 9 + .../__tests__/AgentActivityPanel.mobile.test.ts | 15 ++ .../AgentActivityPanel.sse-integration.test.tsx | 96 +++++++++ .../__tests__/AgentActivityPanel.test.tsx | 121 ++++++++++++ .../__tests__/CommandCenter.test.tsx | 27 ++- .../__tests__/agentActivityCursor.test.ts | 47 +++++ .../__tests__/useAgentActivity.test.tsx | 14 ++ .../command-center/agentActivityCursor.ts | 75 +++++++ .../command-center/agentActivityPresentation.tsx | 8 + .../components/command-center/useAgentActivity.ts | 218 +++++++++++++++++++++ .../app/components/dashboard/MainContent.tsx | 19 ++ .../MainContent.agent-activity-navigation.test.tsx | 127 ++++++++++++ .../dashboard/app/components/dashboard/types.ts | 3 + packages/i18n/locales/en/app.json | 30 ++- packages/i18n/locales/es/app.json | 30 ++- packages/i18n/locales/fr/app.json | 30 ++- packages/i18n/locales/ko/app.json | 30 ++- packages/i18n/locales/pt-BR/app.json | 30 ++- packages/i18n/locales/zh-CN/app.json | 30 ++- packages/i18n/locales/zh-TW/app.json | 30 ++- 28 files changed, 1312 insertions(+), 43 deletions(-) Fusion-Task-Id: FN-8866 Fusion-Task-Lineage: 817ae76e-52c6-4221-8642-df757e773627 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
cb57093d03 |
refactor: domain folder layout (types, API, core, engine) (#2398)
## Summary Wave 17 organizes Fusion into **domain folders** (stacks on #2397). ### Layout - **core/types/** — board, task, agents, settings, merge, workflow, mesh, … - **core/src/** — agents, ai, async-stores, workflows, tasks, config, db, … - **dashboard/app/api/** — client, tasks, agents, git, missions, planning, … - **engine/src/** — agents, auth, execution, merge, missions, overseer, worktree, … Root keepers retained for large entrypoints (`store.ts`, `executor.ts`, `merger.ts`, …). Public barrels (`@fusion/core`, `@fusion/engine`, `app/api.ts` → legacy) stay stable. ## Test plan - [x] `@fusion/core` typecheck - [x] `@fusion/engine` typecheck (pre-existing playwright-core noise only) - [ ] CI merge gate **Stack:** #2394 → #2397 → **this PR** |
||
|
|
34ed2d1ffb |
FN-8750: redesign resolved GitHub issues table
Improve the resolved GitHub issues table across desktop, tablet, and mobile layouts. - Add responsive table styling with semantic links and readable metadata. - Add table hooks and regression coverage for layout and token use. - Capture desktop and mobile layout smoke screenshots. Files changed: ...mmand-center-css-token-canonicalization.test.ts | 15 ++ .../components/command-center/areas/GithubArea.tsx | 37 +++-- .../areas/__tests__/areas.github-signals.test.tsx | 27 ++-- .../app/components/command-center/areas/areas.css | 151 +++++++++++++++++++++ .../dashboard/scripts/browser-layout-smoke.mjs | 120 +++++++++++++++- screenshots/fn-8750-resolved-github-desktop.png | 3 + screenshots/fn-8750-resolved-github-mobile.png | 3 + 7 files changed, 333 insertions(+), 23 deletions(-) Fusion-Task-Id: FN-8750 Fusion-Task-Lineage: b229bad6-7d32-4a04-9681-c4184c46c015 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f2f6795010 |
FN-8635: keep worktree slider visible
Keep Command Center capacity controls visible and correctly editable across settings states. - Render Max worktrees in the shared full-width range wrapper. - Preserve capacity values after load failures and explain disabled worktree limits. - Add control tests, browser geometry coverage, documentation, and a release changeset. Files changed: .changeset/fn-8635-worktrees-slider.md | 7 + docs/dashboard-guide.md | 2 +- .../command-center/CommandCenterControls.css | 6 + .../command-center/CommandCenterControls.tsx | 63 +++++--- .../__tests__/CommandCenterControls.test.tsx | 76 ++++++++- packages/engine/e2e/fn-8635-worktrees-slider.mjs | 180 +++++++++++++++++++++ 6 files changed, 310 insertions(+), 24 deletions(-) Fusion-Task-Id: FN-8635 Fusion-Task-Lineage: fb9c2a46-3c5c-4871-bab4-c43af20cb4de Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
95410b5de6 |
FN-8638: add Factory Light dashboard theme
Add a daylight industrial theme that persists across dashboard and desktop startup. - Register Factory Light in persisted theme types, selectors, and bootstrap validators. - Define Factory Light tokens and preview swatches for light and dark modes. - Cover theme registration and rendered token contracts, and document the new option. Files changed: .changeset/fn-8638-factory-light-theme.md | 7 ++ docs/dashboard-guide.md | 3 +- docs/settings-reference.md | 2 +- packages/core/src/types/execution-and-ui.ts | 2 + .../app/__tests__/factory-light-theme.test.ts | 106 +++++++++++++++++++++ .../dashboard/app/components/ThemeSelector.css | 14 +++ .../components/__tests__/ThemeDropdown.test.tsx | 2 +- .../components/__tests__/ThemeSelector.test.tsx | 2 +- .../__tests__/CommandCenterControls.test.tsx | 2 +- packages/dashboard/app/components/themeOptions.ts | 1 + packages/dashboard/app/index.html | 2 +- packages/dashboard/app/public/theme-data.css | 86 ++++++++++++++++- packages/desktop/src/renderer/index.html | 1 + 13 files changed, 223 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-8638 Fusion-Task-Lineage: 3b78bc31-0f03-4299-8f5f-1a69ac7c604a Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
bcaa48390b |
FN-8627: add Sage color theme
Add the Sage palette across persisted dashboard and desktop theme selection paths. - Register Sage in core, dashboard bootstrap, desktop, and selector metadata. - Add dark and light Sage tokens plus independently resolvable swatches. - Cover registration, token, selector, and documentation updates. Files changed: .changeset/fn-8627-sage-theme.md | 7 ++ docs/dashboard-guide.md | 3 +- packages/core/src/types/execution-and-ui.ts | 2 + .../dashboard/app/__tests__/sage-theme.test.ts | 101 +++++++++++++++++++++ .../dashboard/app/components/ThemeSelector.css | 14 +++ .../components/__tests__/ThemeDropdown.test.tsx | 2 +- .../components/__tests__/ThemeSelector.test.tsx | 2 +- .../__tests__/CommandCenterControls.test.tsx | 2 +- packages/dashboard/app/components/themeOptions.ts | 1 + packages/dashboard/app/index.html | 2 +- packages/dashboard/app/public/theme-data.css | 86 +++++++++++++++++- packages/desktop/src/renderer/index.html | 1 + 12 files changed, 217 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-8627 Fusion-Task-Lineage: fd4353b3-1e0c-4c7e-84dd-bcad2815178c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
cde02b423d |
FN-8632: align Command Center concurrency controls
Align Command Center capacity controls so their slider tracks remain visually synchronized. - Use a two-column grid for the surviving per-project capacity sliders. - Stretch slider cards and bottom-align range inputs despite optional running-count captions. - Add regression coverage and a patch changeset for the layout correction. Files changed: .changeset/fn-8632-concurrency-layout.md | 7 ++++ .../command-center/CommandCenterControls.css | 22 ++++++---- .../__tests__/CommandCenterControls.test.tsx | 47 +++++++++++++++++++++- 3 files changed, 67 insertions(+), 9 deletions(-) Fusion-Task-Id: FN-8632 Fusion-Task-Lineage: c59f52fc-0e5b-4633-98fa-64b8a60621d0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
24ef266e48 |
FN-8628: add Factory Dark dashboard theme
Add a low-light industrial dashboard color theme with first-paint support and release documentation. - Register Factory Dark across persisted theme types, selector metadata, and desktop/dashboard bootstrap validators. - Define dark and light Factory Dark tokens, swatches, and selector styling. - Cover theme registration, tokens, bootstrap behavior, and UI theme-option counts. - Add a minor @runfusion/fusion changeset and document the theme. Files changed: .changeset/fn-8628-factory-dark-theme.md | 7 ++ docs/dashboard-guide.md | 3 +- docs/settings-reference.md | 2 +- packages/core/src/types/execution-and-ui.ts | 2 + .../app/__tests__/factory-dark-theme.test.ts | 106 +++++++++++++++++++++ .../dashboard/app/components/ThemeSelector.css | 14 +++ .../components/__tests__/ThemeDropdown.test.tsx | 2 +- .../components/__tests__/ThemeSelector.test.tsx | 2 +- .../__tests__/CommandCenterControls.test.tsx | 2 +- packages/dashboard/app/components/themeOptions.ts | 1 + packages/dashboard/app/index.html | 2 +- packages/dashboard/app/public/theme-data.css | 86 ++++++++++++++++- packages/desktop/src/renderer/index.html | 1 + 13 files changed, 223 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-8628 Fusion-Task-Lineage: 6f3c7cd9-0130-482d-8aa8-ca47d48b134f Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
df73bbc14a |
fix(tests): clear the persisted Command Center sub-tab between cases (7 of 8 main reds) (#2971)
`main` is red in the dashboard backfill lane. This fixes **7 of the 8** failures. All 8 bisect to #2420 (`4f929acc10`): parent `189f237a07` passes 9/9, that commit fails 5. ### Cause — test-order pollution, not a product bug #2420 made Command Center restore its sub-tab on remount, because the view unmounts on navigation by design: ```ts const [activeTab, setActiveTab] = useState<SubViewId>( () => (getCommandCenterState(projectId)?.activeTab as SubViewId | undefined) ?? "overview", ); ``` The panel's test id is derived from that tab (`data-testid={\`command-center-panel-${activeTab}\`}`), and these files click through to other tabs — `tokens`, `team`, `github`, `system`, `mission-control`. Neither `beforeEach` cleared storage, so the **first** case left `mission-control` persisted and every later case rendered `command-center-panel-mission-control`: ``` → Unable to find an element by: [data-testid="command-center-panel-overview"] ``` Nothing in that message points at a previous test, which is what made it look like a component regression. **Confirmed as ordering rather than breakage:** each failing case passes when run alone with `-t`. The "mutation" here is `main` itself — without the `localStorage.clear()` these files fail 7; with it, 11/11. ### Scope Two lines plus the note explaining why they exist, so the next person who adds a tab-switching case knows the persistence is per-project and sticky. **No product code touched** — the persistence behaviour in #2420 is correct and stays as-is. **Verified:** 11/11 across both files, `tsc -p tsconfig.app.json` 0 errors, lint clean, FNXC gate exit 0. Test-only, no changeset. ### The 8th failure is NOT fixed here, deliberately `MainContent.planning-project-remount.test.tsx` fails because #2420 moved Planning out of `MainContent` (its branch now returns `null`) into `PlanningKeepAlive`, mounted by `App.tsx`. The product side is right — the host **is** keyed (`App.tsx:1956`): ```jsx <PlanningKeepAlive key={`${currentProject.id}:${modalManager.planningEntryGeneration}`} … /> ``` so project switches still remount and I found **no cross-project leak**. But that test was `FNXC:ProjectSwitchModalReset` coverage for a leak-class invariant (Planning carrying a previous project's stream/session), and **nothing asserts it at the new location**: the keep-alive test covers navigation reveal, not project switching, and `App.test.tsx` has no test for the host key. Deleting that `key=` today would fail no test. Restoring it needs an App-level test, which is a bigger change than this fix and worth keeping separate. Detailed on #2420. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4f929acc10 |
fix(dashboard): stop over-aggressive component unmounts (keep-alive for planning, terminals, popups) (#2420)
Implements
docs/plans/2026-07-22-001-fix-dashboard-remount-churn-plan.md: every
confirmed source of unnecessary unmount/remount churn in the dashboard,
plus a keep-alive layer for conversation- and terminal-bearing surfaces.
## What changed
**Keying / component identity (U1–U3)**
- Streaming chat segment key no longer embeds `entries.length` — an
expanded thinking block stays expanded while entries stream into it
(R1).
- Dock task list keys `TaskCard` rows by `task.id` (occurrence suffix
only for the duplicate-id anomaly) instead of `id-index` — no remount on
reorder/filter/status change (R2).
- `ProviderStatusBadge` / `GitHubStatusBadge` hoisted out of
ModelOnboardingModal's render body (R3); MCP server rows key by
`server.name` alone (R4).
**Keep-alive layer (U4–U6)**
- New shared `KeepAliveView` wrapper: visible = in-flow flex child;
hidden = out-of-flow `position:absolute; inset:0` with
`visibility:hidden; pointer-events:none` + `aria-hidden` (never
`display:none`, so xterm geometry never collapses).
- Planning Mode renders as a kept-alive sibling of the MainContent
switch after first open (per-project latch mirroring Quick Chat). While
hidden, the session-list SSE, recovery poll, and elapsed ticker suspend
via a new `active` prop; reveal re-subscribes and refreshes the sessions
list once. Payload-carrying entry points (initial-plan handoff, resume)
and project switches remount via a new
`modalManager.planningEntryGeneration` key, preserving pre-keep-alive
fresh-open semantics. `recordResumeEvent` instrumentation records
`remount` on first activation and `route-active` on reveal.
- Task-detail Terminal / Worktree-terminal / Planner-chat tabs stay
mounted-but-hidden after first open (per-task latches; task switch/close
still disposes fully). `SessionTerminal` gains `active`: reveal refits +
forces a font remeasure, and if the WS died while hidden it re-runs the
full attach lifecycle (dead-socket recovery).
- Popped-out task windows hide via FloatingWindow `hidden` instead of
leaving the render array; `TaskDetailContent` gains `active` so hidden
popups close their SSE/EventSource channels while the terminal WS stays
open. `visiblePoppedOutTaskEntries` remains the Escape-shortcut
consumer.
**Planning Mode internal-transition audit (U7)**
- Audit findings: session-list mode and mobile list/detail flips are
CSS-class transitions over one always-mounted detail pane (no
state-discarding unmounts); re-selecting the active session is an
early-return visibility restore; session switching intentionally reloads
from the session row (stream re-attach for generating sessions);
remaining index keys are on stateless lists. No product-code defects
found; regression tests now lock the always-mounted invariant on desktop
+ mobile.
**Cheap-view state (U8)**
- CommandCenter (active sub-tab + date range) and DevServerView
(selected script/task + typed-but-unsent command) persist per project
via `modalPersistence` and restore after their (intentional) unmount
round-trips. Also fixed the candidate auto-fill effect clobbering a
customized non-empty command.
## Symptom Verification
- **Original symptom:** streaming thinking blocks collapsed mid-stream;
terminals reconnected and lost scroll/input on tab flips; Planning Mode
lost in-flight interviews on navigation; popped-out windows vanished
off-view; dock cards remounted on reorder.
- **Exact reproduction:** (1) expand a thinking block during a stream;
(2) run a command in the Terminal tab, flip to Plan and back; (3) start
a planning interview, navigate Board and back; (4) pop out a task with
board/list-only scoping and switch views; (5) change a dock task's
status.
- **Assertion it is gone:** component-identity/instrumentation tests in
TaskChatTab, SessionTerminal, TaskDetailModal
(worktree/planner-chat/tabs), PlanningModeModal keep-alive +
internal-transitions, App keep-alive round-trip, and
App.taskPopupViewGating assert no remount and preserved state for each
repro, across desktop and mobile breakpoints.
## Verification
- File-scoped vitest: 23 files / 1091 tests green (all touched suites
plus FloatingWindow, TerminalModal, TaskPlannerChatTab,
lazy-loaded-views guard, App suites).
- `pnpm verify:fast`: PASS (13 steps — scoped typecheck/build, CLI
build, boot smoke).
- `pnpm check:changesets`: passes; changeset
`fix-dashboard-remount-churn` (`@runfusion/fusion` patch, labeled
format).
- Known pre-existing failures NOT caused by this branch (verified
failing at base
|
||
|
|
ba40942a10 |
batch-dashboard-app: 75 → 2 across packages/dashboard/app — the last two are deliberate, not missed (#2772)
**Batch branch is live: `batch-dashboard-app`.** Push conversions here as commits rather than opening per-file PRs — that is the CI-run bottleneck this model removes. **One-line ownership note for you to arbitrate:** you have addressed me as U11, U12 and U7 at different points, so the `u12 worker -> batch-dashboard-app` mapping is ambiguous from my side. I claimed it because `dashboard/app` is where I have done the most work this session (TaskContextMenu, Column, TaskCard, TaskDetailModal, columnRoles, taskActivity) and I know which of its guards are load-bearing fallbacks. **If another worker is the intended owner, say so and I will hand the branch over rather than both of us pushing to it** — two workers on one shared branch is exactly what silently discarded a reviewed fix in #2645 today. ## The work order (measured at branch point, tests excluded) **75 guards across 32 files.** Largest: `TaskContextMenu.tsx` 9 · `Column.tsx` 7 · `ListView.tsx` 6 · `TaskDetailModal.tsx` 4 · then a long tail of 3s, 2s and 1s. Full per-file list is in the committed work order so feeders can claim without re-measuring. ## Two rules this surface keeps tripping on **1. A literal after `??`, or in the `else` of a `flags ?` ternary, is a DEGRADED-MODE answer — not an unconverted guard.** Two real states reach it: the **pre-load window** (board renders before the workflows fetch resolves) and a card stranded on an id its workflow no longer declares. In both, `columnFlagsById` has no entry at all. Deleting the fallback does not remove a decision — it substitutes "no role" silently, and affordances vanish during first paint. Those sites reach 0 by **marking**, not deleting. Expect `TaskContextMenu.tsx` and the `utils` files to be **mostly marks**. A "9 → 0" that deleted 9 fallbacks is a regression wearing a green census. **2. A marker excuses ONLY the construct it is attached to** — the statement or function holding the literal, not a sibling declaration. This has cost three passes, two of them mine; my first attempt on `reliability-metrics.ts` scored **1 of 6**. **Verify by the count moving, not by the comment existing.** With the ratchet gate-blocking, a mis-marked batch either wedges the gate or locks the miss into a re-recorded baseline. ## Status Opening commit is the work order only — **0 of 75 converted so far.** I am near the end of my context, so I am establishing the branch and the shared list rather than starting conversions I cannot finish cleanly. Feeders can begin immediately; I will keep the branch rebased. My other PR **#2762** (`live-agent-count.ts` 6 → 0) is green and unconflicted — per your rule it should land rather than fold into a batch, and it is `packages/core` so it belongs to batch-core anyway. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Task UI now resolves workflow “column roles” per task to drive diffs/merge details, routing/steering, progress/runtime visibility, and review badges. * Right-dock/overflow views and dev-server now use per-task column traits for “executing” behavior and dependency-based “Up Next” eligibility. * **Bug Fixes** * Fixed bulk action selection/delete/archive eligibility and prevented cross-workflow role leakage. * Made in-review/stale-paused-review, stuck, and effective executor/validator model logic role-aware. * **Tests** * Added regression coverage for degraded-flag behavior and ensured resolved-flag props aren’t ignored. * Added a static check to fail builds on inert optional flag seams. * **Documentation** * Updated batch work-order and mega-batch branch guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- ## Late addition: the seam gate was masking a real offender `scripts/check-inert-flag-seams.mjs` matched call sites by NAME, so two same-named functions in different modules were conflated. I had documented that as a known false-positive source and moved on — reports mentioning `sortTasksForDisplayColumn` are noise, read past them. That annotation was the damage. Core's `sortTasksForDisplayColumn` genuinely never receives its `columnFlags` argument outside its own tests. The dashboard's separate function of the same name (`app/components/taskSorting.ts`), called with up to five arguments from `Lane`/`Board`/`ListView`, was raising the arg-count max and clearing core's seam. The offender was behind a row everyone had been told to skip. The gate now records the module each callee is imported from and matches it against the seam's declaring module. **Measured, by reverting the change:** the scan prints `17 seams, all supplied` and emits **no row** for the function. With the change, it is reported. Both directions watched. Reported on #2783 rather than fixed from outside — core owns it, and "wire the flags" vs "drop the parameter and let the literal stay counted" is their judgment call. TEMPORARY allow-list entry carries it meanwhile; the existing staleness check fails the moment the site becomes supplied, so the entry cannot outlive the fix. Two known limits remain, both inherent to name matching and both documented in the script: the one-supplier floor, and the `__tests__` exclusion (hence the two permanent `ALLOWED` entries). ## And the one-supplier floor, closed the same way I wrote in the section above that the floor "hasn't cost anything yet." That is verbatim the reasoning that kept the imported-shadow bug alive, so I closed it instead of leaving the note. `best < arity` asked only whether SOME caller supplied the argument. One correct call site cleared the seam while every sibling took the legacy fallback — the `isTaskStuck` defect class, where two of three sites omitted the flags and the gate stayed green because the third was right. Review caught that one. A partially-supplied seam is the harder of the two: wholly-unsupplied is uniformly wrong, this works on the board you tested and degrades on the column you did not. **Measured:** dropping the flags argument at `Column.tsx`'s supplied call site produces `supplied by 5/6 call sites; omitted at packages/dashboard/app/components/Column.tsx:1 (of 2)`; restoring returns `all supplied at every call site`. Red and green both watched. Two real omissions found, both on `isNearDuplicateCanonicalInactive`: - **`TaskDetailModal.tsx`** — deliberate, and it **corrects a note I left at that site**. The old note said hoisting the flags state was "the actual fix." It is not, for this call: the flags in scope describe the *modal's* task, and the canonical is a **different task** on a column this component never resolves. Passing them would type-check, read as a conversion, and answer about the wrong task — exactly what `column-role-degraded-flags.test.ts` exists to catch. Supplying it correctly needs a fetch, which is a data change and out of scope. - **`core/task-store/branch-group-ops.ts`** — genuinely wireable (the impl is async and already holds `store` and `canonicalId`). Reported on #2783, not edited from outside. Exemptions for this class are keyed by **call site** (`<file>::<function>`), not by function name. A name-level entry would waive every site of a partially-supplied seam, which is backwards — its other sites are correct and are the reason the omission is worth reporting. Both entries carry the same staleness check as the name-level list and cannot outlive their fix. Remaining known limit, now the only one: the `__tests__` exclusion, which makes a test-only export read as having no callers. That is what the two permanent `ALLOWED` entries are. ## The `__tests__` exclusion, and two allow-list entries built on false reasons Named as the "last remaining limit" above, so it got closed too. The scan now reads test files for call sites — but counts them **separately**, and a test never clears a seam. That direction is the dangerous one: counting test callers as suppliers would have re-hidden core's `sortTasksForDisplayColumn`, whose only suppliers are its own tests. Measured by lifting its exemption: still reported. Both permanent allow-list entries claimed the scanner couldn't see their callers. **Both reasons were false**, and reading tests is what proved it: - **`evaluateMergeBlockerGuard`** — zero callers in tests either. Its only reference in the repo is its own declaration; never registered as a trait hook; the `evaluateDefaultWorkflowGuards` reader its file header credits does not exist. The `lifecycleColumns` conversion went onto dead code, and its note describes a crossing the guard cannot make. Reported on #2783, including the two things I am explicitly *not* concluding (no `"guard"` hook is registered in production; whether that is residue or a dropped registration needs core's intent). - **`isRecoverableMissingWorktreeReviewFailure`** — 5 test call sites. It wraps `...WithProgress`/`...NoProgress`, the live pair called from `self-healing.ts`, both supplying `reviewColumns`. Entry kept, true reason recorded. ### A wrong turn, recorded because it is the failure mode this PR is about I first classified no-production-caller seams as *informational* when they weren't re-exported from a package index, reasoning that a public export might be called externally. That silently downgraded `sortTasksForDisplayColumn` — a confirmed real offender — from failing to a footnote. Publication status has nothing to do with whether there is production behaviour to be wrong. Reverted to the simple rule: no production caller means inert, and it fails. It is worth stating plainly because it is the exact shape of everything else in this PR: a change that made the gate read *cleaner* while making it catch *less*, and it type-checked, passed every test, and would have reviewed fine. ### Where that leaves the check Every blind spot named in this PR has now been closed, and **each one produced a real defect within minutes of closing it** — imported shadows, the one-supplier floor, the `__tests__` exclusion. Four verified findings went to core, one to engine. I would not read the remaining ~240 guards' green gates as evidence that they are clean; I would read them as untested. ## Two guards for one question, one of them worse Having hardened the script, I checked its older twin rather than assuming it was fine. `resolved-flags-seams-have-suppliers.test.ts` carried its own copy of the trailing-flags-parameter check — written before the script existed — with **all three** holes the script has since closed. **Measured on one reintroduced defect** (dropping the flags argument at `Column.tsx`'s supplied `isNearDuplicateCanonicalInactive` call): | | result | |---|---| | `scripts/check-inert-flag-seams.mjs` | `supplied by 5/6 call sites; omitted at .../Column.tsx:1 (of 2)` | | this test's arity half | **3 passed** | Deleted the arity half. Redundancy between a strong and a weak check isn't redundancy — it's a green result available to whoever runs the weak one, and there was no signal at the call site telling you which you were looking at. The **props-shape half stays**: it has no twin in the script, and I confirmed it still fires by reintroducing the original `PrPanel` defect (outer component stops destructuring `taskColumnFlags`) — it reports `PrPanel declares taskColumnFlags but never takes it`. Dashboard app suite: **113 files / 3921 tests** (was 3922 — the deleted case is the difference). ## The gate started catching defects as they landed Syncing with main brought in three fresh conversions from other workers. The hardened check flagged all three immediately — the first time these guards have fired on someone else's landed code rather than on my own. - **`TaskCard`** — `getRunningOptionalGateBadge(task)` omitted flags while *both* `ListView` sites supplied. Fixed, and `taskColumnFlags` added to the `useMemo` deps: no `exhaustive-deps` rule here, so a memo that reads flags without listing them keeps the first-paint `undefined` answer and reproduces the bug through staleness instead of omission. - **`TaskTokenStatsPanel`** — `getTotalAgentActiveMs` omitted while `TaskCard` supplied, so the same runtime number came from the real column on a card and from legacy ids in the detail modal. Now takes `columnFlags`, supplied from `detailColumnFlags` — correct here because the panel renders the modal's **own** task, unlike the near-duplicate canonical above. - **`ListView` ×2** — passed `columnFlagsById.get(task.column)`, the cross-workflow **union**. A task whose own workflow doesn't declare that column gets a *neighbour workflow's* traits. The landed comment justified it as "this list already owns `columnFlagsById`" — exactly the reasoning `column-role-degraded-flags.test.ts` exists to reject. It failed on merge and is how I found this. Also: the `getTotalAgentActiveMs` exemption I was carrying **self-retired**. Main wired the seam, the staleness check failed the entry, and I removed it. That mechanism has now paid for itself once. ### Pre-existing, NOT from this PR: `App.test.tsx` is red on main `app/components/__tests__/App.test.tsx` fails **10 of 141** identically with my changes, with my changes stashed, and with main's own `App.tsx` restored. Not mine, and not in the merge gate. **Bisected on clean `main` checkouts, so this is measured rather than inferred:** | commit | date | result | |---|---|---| | `main~400` (`41d60f0355`) | 2026-07-25 | **140 passed** (140 tests) | | `main~275` (`74d6513fae`) | 2026-07-27 | 3 failed / 141 | | `main~210` (`d2ce1ba8b5`) | 2026-07-29 | 10 failed / 141 | | `main` (`6fc98fd6c7`) | 2026-07-30 | 10 failed / 141 | So it is **not one regression** — it degraded in two stages across 2026-07-25 → 07-29, and the test file itself changed in that window (140 → 141 tests). Three commits touched it there: `73b2a32e2b`, `f26cbedf4f`, `f157bf7460`. That window overlaps the workflow-owned lifecycle migration, which is suggestive but not something I confirmed. The failures are render-level, not assertion-level — `Unable to find an element with the text: + New Task`, `Unable to find role="dialog"`, `Unable to find ... Back nav task`. The board appears to render nothing. That reads like a real regression or a harness mismatch after the lifecycle migration, not a flake, so I have deliberately **not** quarantined it — quarantine is for flakes, and using it here would hide the signal. Flagging for whoever owns `App.tsx`. My suites: `app/__tests__` **113 files / 3921 tests** green, `tsc` 0, lint 0, census `--strict` 0, seam gate 0. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e9e63d8e0f |
consolidate/capacity: --strict was red on main (my #2621), 14 stale baselines, routines seeding a deleted column, worktrees-off audit (#2652)
Capacity unit consolidation. Three coherent themes, small commits inside. ## Census before/after (`node scripts/lifecycle-column-census.mjs`) | | before | after | |---|---:|---:| | triage column guards (the bar) | 10 | **10** | | `--strict` on main | ❌ **RED** | ✅ green | | baseline staleness | 14 files stale | **0** | This branch does **not** move the triage bar — its remaining 10 are moves.ts (dies with the flag), the dashboard cluster, and one deliberate site. It fixes the instrument that measures the bar, plus a live defect the comparison count cannot see. --- ## 1. `--strict` was RED on clean `origin/main`, and it was my fault ``` packages/dashboard/src/routes/register-task-workflow-routes.ts: 22 -> 23 ``` My merged #2621 added a v1-IR pre-WIP fallback answering a greptile P1 and shipped no marker or baseline update, so the program's measuring instrument has been failing on main since it landed. Fixed **at the site** with a `DELIBERATE-LITERAL` marker, not by bumping the baseline. That branch runs only when the IR declares no columns and no nodes, so there is no role to resolve — `resolveLifecycleColumns` returns nothing and the legacy pre-implementation ids are the only pre-WIP signal that exists there. It is *unconvertible*, not unfinished; the sibling `else` two lines down is the trait path for every IR that can answer. A rise that is genuinely correct belongs where a reader will see it. ## 2. The baseline was stale for 14 files — a hole, not cosmetics A stale allowance lets converted guards return while the check stays green. Measured gaps: ``` self-healing.ts allows 126, tree has 111 executor.ts allows 112, tree has 104 moves.ts allows 44, tree has 39 default-workflow-hooks allows 25, tree has 7 mission-feature-sync allows 5, tree has 0 MissionControlPanel allows 4, tree has 0 (+8 more) ``` **Only two of the fourteen are mine.** The other twelve are already-merged conversions by other workers where nobody re-recorded. Re-recorded all fourteen here rather than waiting for twelve PRs, because until it happens the ratchet is not holding the 779 it exists to hold. Flagging it plainly: those drops are other people's work being locked in, not mine being claimed. ## 3. Routines created tasks into the column U11 deleted The routine editor's "Target Column" defaulted to `triage`. That value is submitted as the create step's `taskColumn`, and an **explicit** column bypasses the workflow entry-column resolution added for column-less creates (#2589) — so every routine saved with the untouched default seeded its tasks into a column the board does not declare. Defaulting to `todo` would be the same mistake one column over: a custom workflow declaring no `todo` is seeded into an undeclared column just as surely, because an explicit column overrides entry resolution whatever its value. So the default sends **nothing** and each workflow's own intake resolution decides. The `triage` **option** is removed too, not merely un-defaulted — fixing the initializer alone left the operator able to pick the deleted column one click away, and it was the option labelled "Planning", the name the merged `todo` column now displays. Removing it retires that label inversion as well. Found by scanning **membership** forms rather than comparisons: the comparison census cannot see a `?? "triage"` default, so no count showed this and nobody was looking. Revert-proof — restoring the default fails with *"the default must not name a column at all"*. ## 4. "Worktrees off is INERT" had one unaudited reader The constraint was that `maxWorktrees` become genuinely inert, "not set very high and not skipped by convention". `resolveWorktreeCapacityLimit` returns `null` for that, and its unit tests can only prove the **resolver** is right — they cannot see a second reader, which is the only way the constraint breaks. Audited every `maxWorktrees` read that bounds anything. **Exactly two:** `scheduler.ts` (the admission gate, via the resolver, single call site, optional gate snapshot) and `self-healing.ts`'s `enforceWorktreeCap` — `(settings.maxWorktrees ?? 4) * 2`, a **raw** read. The second is **not a bug** and is left alone: it bounds worktree *directories on disk* and only removes *idle* ones. Worktrees still exist in OFF mode, so that bound must keep applying or idle directories accumulate unbounded. Recorded consequence: in OFF mode the number still governs disk retention while gating no admission — an edge you scoped out. The note says explicitly **not** to unify the two readers: routing hygiene through the resolver returns `null` in OFF mode and silently removes the disk bound, which is a leak dressed as a simplification. New ratchet requires every file bounding on `maxWorktrees` to be named with a reason, and rejects a **stale** allowlist entry. Proven by injecting `active >= (settings.maxWorktrees ?? 4)` into `hybrid-executor.ts`. --- ## Deliberately NOT included - **My own census script.** #2633 landed the canonical one, and it is better than mine — an AST classifier *plus* an independent text classifier with `--compare`, and a baseline that fails on unrecorded **drops** as well as rises. Mine only caught rises. I deleted mine rather than ship a second measuring instrument; three copies of "strip comments" is the drift shape this program keeps paying for, so the worktree ratchet now imports #2633's `stripComments`. - **My TaskContextMenu fix.** Superseded, and by a better answer: main's `isPureIntakeColumn` (intake *without* hold) keeps the merged Planning column shown and suppresses only a bare Ideas capture, which resolves the exact hold-lane objection coderabbit raised against my version. I briefly clobbered that merged work by checking my old file out wholesale, caught it in the diff, and reverted. ## Verification `pnpm lint` clean · core + dashboard `tsc` clean · census suite 23/23 · worktree ratchet 8/8 · RoutineEditor 49/49 · `routes-task-retry-planning-column` 16/16 · `lifecycle-column-census --strict` exits 0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- ## Added after review (all four greptile threads were real, and two of them mattered) **The routine fix was half a fix.** `routine-runner.ts:515` *and* `cron-runner.ts:982` both did `column: (step.taskColumn as Column) || "triage"` **after** the step is read, so every routine — including ones saved through the fixed editor — still created tasks into the deleted column. Both now omit it. **The advanced steps editor MANUFACTURED the defect.** `ScheduleStepsEditor.tsx` had three `triage` defaults: the new-step template (`:64`), the per-step initializer (`:95`), and the select still offering it (`:344`). So the path I had *not* fixed produced the bug by default, on fresh data. Template names no column; initializer coerces a persisted `triage`; `triage` removed from the options; empty submits `undefined`. **Four pre-existing tests pinned the defect** and are rewritten to the corrected invariant rather than appeased: | test | asserted | |---|---| | `cron-runner`: "defaults column to triage when taskColumn is not set" | `column: "triage"` | | `ScheduleStepsEditor`: "adds a create-task step..." | `taskColumn` toBe `"triage"` | | `ScheduleStepsEditor`: "allows saving create-task step..." | the legacy column is **resubmitted** | | plus the explicit-column case added beside each, so the fix cannot swallow a deliberate choice | **The allowlist hole was the worst finding.** `AUDITED_BOUNDS` was keyed by FILE, so every bounding expression in an allowlisted file was exempt — a second raw bound in `scheduler.ts` stayed green, the one case that ratchet exists for. Per-expression now, and making it so **immediately surfaced a real second bound the file-level version was hiding** (`maxWorktreesGate.used >= maxWorktreesGate.limit`, safe by construction since the snapshot is `undefined` in OFF mode). Proven by injection. ## Found while re-reading my own deletion, not reported A **rendered tooltip** still named a deleted cap. The "Queued to plan" badge read *"planning starts when a concurrency slot frees up (maxConcurrent / globalMaxConcurrent)"*. The cross-project cap is gone — capacity is two numbers per project — so it told operators their planning waited on a limiter they can no longer find a setting for. Names the surviving dimension only now. ## Coding (Ideas): enforcing #2651 rather than repeating it I took the unowned coding-ideas IR merge, concluded it must not be done, then found **#2651 had already implemented, reverted and documented exactly that** — with better grounding than my own argument. It added no test, so nothing stops the next person reaching the same dead end. So this ships their reasoning as a ratchet, not a second opinion: triage discovery keys on the column's `autoTriage`, so a merged column is either never scanned (cards sit on a bootstrap stub until the **capacity hold** releases them, sending **unplanned** work into in-progress — worse than stalling) or scanning wins and the manual gate is gone. Their scope caveat is kept: `autoTriage` is a general trait field, so only *this preset's* collapse is dead, not manual intake as a concept. The registry does not reject the merged shape, which is why prose was not enough. ## Verification (re-run) `pnpm lint` clean · core + engine + dashboard-app `tsc` clean · `lifecycle-column-census --strict` exits 0 ("every file matches its baseline exactly") · routine-runner 24/24 · cron-runner 156/156 · ScheduleStepsEditor 41/41 · RoutineEditor 49/49 · worktree + coding-ideas 12/12. TaskCard has 2 failures **pre-existing on main** — confirmed identical with my changes stashed. --- ## Bears directly on the closing bar: this PR already removes the 67-guard ratchet slack Measured on current `origin/main` with the census itself: ``` tree total: 787 baseline total: 854 SLACK: 67 FILES ABOVE BASELINE (1): +1 packages/dashboard/src/routes/register-task-workflow-routes.ts (22 -> 23) FILES BELOW BASELINE: 13, totalling 68 unrecorded conversions -18 core/default-workflow-hooks.ts (25->7) -15 engine/self-healing.ts (126->111) -8 engine/executor.ts (112->104) -5 core/task-store/moves.ts (44->39) -5 engine/mission-feature-sync.ts (5->0) -4 core/live-agent-count.ts (10->6) ``` **The slack is not regression — it is 13 files of merged conversions nobody re-recorded**, against exactly **one** rise. This PR re-records the baseline **854 → 782 across 140 files**, which closes it. **And the "+3 that slipped in" is +1, and it is mine.** `register-task-workflow-routes.ts 22 → 23` is the v1-IR pre-WIP fallback my #2621 added; it is justified (that branch runs only when the IR declares no columns or nodes, so there is no role to resolve) but it shipped with no marker and no baseline update — which is why `--strict` has been **red on main since it merged**. Fixed here at the site with a `DELIBERATE-LITERAL` marker rather than by bumping the baseline, because a rise that is genuinely correct belongs where a reader will see it. Sequencing note for the auto-lowering change: if this lands first, that work is purely the mechanism (auto-lower, or fail with tighten instructions) rather than a cleanup, and the two re-records will not collide in the same file. Also worth carrying into that mechanism, from building the same guard here: **`--update` must refuse to RAISE.** An earlier version of mine wrote current counts verbatim, so a developer who added a literal and ran the documented update command locked the regression in as the new ceiling — the mirror of the high-water problem. Lowering can be unattended; raising should be a hand edit with the reason recorded. ## Third piece of residue from my own deletion `updateGlobalConcurrency` in the dashboard API client PUT to `/api/global-concurrency`, a route removed when the machine-wide cap went. Zero callers; the only reference was the `legacy.ts` barrel re-export. Deleted both. `fetchGlobalConcurrency` **survives on purpose** — the GET route remains and serves live utilization telemetry to the footer and Command Center; nothing gates on it. That is the third: after the second raw `maxWorktrees` reader and the "Queued to plan" tooltip. A deletion is not finished when the enforcement goes — the client, the label and the tooltip outlive it. --- ## Re-greened the dashboard API tests: 117 failures on main, ONE root cause These would have polluted the closing verification pass, and nobody owned them. `api()` builds headers via `new Headers(...)` and returns `Object.fromEntries(headers.entries())` — and `Headers.entries()` **lowercases every key**, so the object reaching `fetch` is `content-type`, not `Content-Type`. `ab87d0d80` then added `x-fusion-client: dashboard-ui` for run-audit attribution. Both changes are correct; neither is visible at a call site, so **114 assertions across 7 files** kept asserting the old shape and went red together. Fixed by naming the shape **once** in `app/test/apiRequestHeaders.ts` rather than patching 114 literals — restating a shared fact 114 times is what made a two-line client change look like 117 failures. Deliberately not a loose `objectContaining`: these tests are the only thing pinning that the attribution header is sent *at all*. **117 → 4.** The remaining 4 are unrelated pre-existing CSS failures (`task-detail-modal-tablet-width` ×3, `space-token-defined` ×1) — confirmed identical on clean main with my changes stashed. ### A gap this surfaced, recorded not papered over Three routes failed in the *opposite* direction — they send the old shape because they call `fetch()` **directly**, bypassing `api()`, so they never get the attribution header. `client.ts` claims the opposite: > "Applied once here rather than per-call so no future mutation route has to remember it." That does not hold for a route that bypasses the helper it is applied in. **Measured in `app/api/`: 8 files make direct `fetch()` calls and 7 include mutations (POST/DELETE)** — among them `ai-sessions.ts`'s DELETE, which is the same class as the four-delete incident the header was added for. So the attribution fix has a hole in exactly its motivating case. Not fixed here: routing those onto `api()` is a behaviour change across the API layer and belongs to its owner, not to a test re-green. Those assertions use a separate `API_JSON_HEADERS_NO_ATTRIBUTION` constant so the gap stays **visible** — if a route is later moved onto `api()`, its test fails and points at the note explaining why. --- ## This branch takes the triage bar 10 → 5, and makes `--strict` green `node scripts/lifecycle-column-census.mjs` on this branch reports **triage 5**, against **10** on `origin/main`. The five removed are the ScheduleStepsEditor template/initializer/option and the RoutineEditor default/option — the automation paths that were creating tasks into the deleted column. **`--strict` was also RED on clean main, twice over, and both causes were the same mistake:** a thorough written rationale the tool cannot read, because the marker was not where the census looks. The census reads a comparison node's **leading comments**; a `DELIBERATE-LITERAL` in the JSDoc above the enclosing function or declaration does not reach the comparison inside it. | site | why it is legitimate | why the tool could not see it | |---|---|---| | `columnRoles.ts:80` `isHoldColumnRole` | degrades to `columnId === "todo"` only when a column has **no resolved traits** — identical in kind to `LEGACY_PRE_IMPLEMENTATION_COLUMN_IDS` directly above, which escapes counting only because a Set is a membership form | rationale written, **no marker token** | | `MissionControlPanel.tsx` ×3 | the SDLC funnel **alias table** — maps `to-do`/`ready`/`review`/`shipped` onto one display stage with an explicit `other` bucket, and nothing branches on it | marker in the JSDoc; the comparisons are arrow bodies **inside the array literal**, which it does not reach | The second only surfaced because converting the `triage` stage to a Set removed its count and exposed the siblings — red gate, justification sitting three lines above, unreachable. Both are markers, no behaviour change. Neither is a conversion candidate: resolving the funnel table to traits would **drop the non-column aliases it exists to accept**. **For the auto-lowering work:** the marker-placement rule is now the recurring trap — three instances, three different authors, including me. A marker that does not register is indistinguishable from no marker, and the failure mode is a red gate with a written explanation nobody can act on. If the census accepted a marker anywhere in the enclosing declaration's comments, none of the three would have happened. Baseline re-recorded per the tool's own instruction ("Re-record the baseline in the SAME PR that lowered the count"). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Task “Actions” menus no longer appear on bare cards in the Planning column. - Routines, scheduled tasks, and create-task steps now respect each board’s configured workflow intake column instead of using a retired default. - Legacy tasks saved with the retired intake column are migrated to automatic workflow resolution. - Target-column selection now offers only “Automatic (workflow intake)” and “Planning,” removing the obsolete option. - Capacity/planning messaging and related UI tooltip text were clarified; concurrency cap updates are managed per project. - **Tests** - Added/updated coverage for workflow intake resolution, create-task target column behavior (including legacy coercion), capacity safeguards, and API request consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
dc50425e98 |
docs: correct 104 future-dated FNXC timestamps across 61 files (#2680)
## What The FNXC convention exists so a reader can place a note against the change that motivated it. A stamp dated *after* the edit landed defeats exactly that. This is program-wide drift, not one author's slip — I contributed to it in my own commits this week, which is how I noticed it. ## Measured, on this tree **104 stamps across 61 files** dated later than the day they were written, from one day ahead to **2026-10-19 (81 days)**: | count | date | count | date | count | date | |---|---|---|---|---|---| | 50 | 2026-07-31 | 6 | 2026-08-05 | 3 | 2026-08-13 | | 17 | 2026-08-01 | 1 | 2026-08-07 | 1 | 2026-08-19 | | 7 | 2026-08-02 | 1 | 2026-08-12 | 2 | 2026-08-26 | | 11 | 2026-08-03 | | | 3 | 2026-10-19 | An earlier number I circulated was ~70. That came from a narrower pathspec and was wrong; **104** is the measurement. ## How Each stamp is rewritten to the date of the commit that introduced **that line**, via per-line `git blame` — deliberately *not* stamped uniformly with today's date. A uniform stamp swaps a wrong date for a different wrong date and flattens the ordering that makes these comments navigable; blame preserves it. Times of day are untouched, and a blame date in the future is clamped rather than trusted. ## Why the verification is listed A docs sweep across 61 files is precisely where a stray edit hides, so the safety claims are mechanical rather than asserted: - every changed line begins with a comment marker — **no code touched**; - **no test asserts an FNXC date later than today**, so no `toContain` assertion on embedded source text can be silently invalidated (several such assertions do exist); - CSS files, which carry several of those assertions, are outside the pathspec. ## Verified lint clean · merge gate green (487 + 158 + 10 + 71) · `census --strict` exit 0 · tsc clean for core, engine, and dashboard (`tsconfig.app.json`). **No behavior change.** Comment text only. ## Not done here A guard preventing recurrence. A check that rejects an FNXC stamp dated after the commit would stop this returning, but it needs a decision about where it runs (lint rule vs. gate) and it is a behavior change to CI — it does not belong riding inside the sweep it would police. |
||
|
|
cef1b08af3 |
U12: the census baseline follows the count down — and goes in the merge gate (#2661)
Coordinator item 2. The census had the right mechanism and no teeth. ## The gap `--strict` already fails on a rise **and** on an unrecorded drop — that logic was correct. But nothing blocking ran it, so the baseline drifted to **854 while the tree held 787**. That is **67 guards of regression that would have merged silently**: a high-water mark wearing a ratchet's name. This is the same shape as the ceilings I tightened in #2647, one level up. Worth saying plainly: I fixed the vitest ratchet's slack by hand and did not check whether the *authoritative* instrument had the same problem. It did, and by a much larger margin. ## Three changes 1. **`--strict` runs in `test:gate`.** The baseline cannot go stale again without a red gate. 2. **Baseline re-recorded: 854 → 785** across 14 files (`triage` 38 → 9). 3. The single RISE is resolved honestly rather than absorbed. ## The +3 investigation One file rose: `register-task-workflow-routes.ts` **22 → 23**. #2621 replaced one `task.column === "todo"` with `task.column === "triage" || task.column === "todo"` — a net **+1** that also reintroduced a `triage` literal, while the PR title reported *"count 0 → 0"*. Not an accusation. There was no gate for the author to check against, and a hand-counted claim in a PR title is exactly the thing that goes wrong without one. Change 1 is the fix. **The literal is justified and stays**, marked `DELIBERATE-LITERAL` rather than converted. It is the **v1-IR arm**: a v1 workflow yields no role assignments, so `resolveLifecycleColumns` returns nothing and the legacy pre-implementation ids are the only pre-WIP signal available. The `else` branch directly below already resolves intake/hold for every v2 workflow. Converting this arm would not finish anything — it would delete the only answer v1 boards have and admit `in-progress`/`in-review` cards into a rebound that clears worktree, branch and retry counters, which is the regression #2621 was fixing. ## Both directions proven | direction | probe | result | |---|---|---| | rise | add `t.column === 'in-review'` | `live-agent-count.ts: 6 -> 7`, exit 1 | | drop | convert one guard | `self-healing.ts: allows 111, tree has 110`, exit 1 | **The drop probe took three attempts to test honestly, and the first two "passed" while proving nothing:** 1. I renamed a receiver (`task.column` → `Probe`) — the classifier is **fail-closed**, so an unknown receiver is still counted and the number never moved. 2. I targeted a site in `hold-release.ts` that carries a `DELIBERATE-LITERAL` marker — not counted as a column guard at all, so removing it changed nothing. Only removing a counted comparison outright moved the number. Both false negatives came from me assuming the probe worked because the command exited the way I expected. ## On auto-rewrite vs fail-and-instruct You offered either. The script already does **fail-and-instruct**, with `--update-baseline` as the explicit re-record, and I kept it that way rather than making the test rewrite the baseline during a run. Reason: a silent downward rewrite means a conversion PR's own diff never shows the number moving, so "census before/after in the PR body" becomes unverifiable — the reviewer would have to re-derive it. Failing with the new number in the message puts it in the diff where a human sees it, and it costs one command. ## Verification `pnpm lint` clean. `pnpm test:gate` green with the census in it — `every file matches its baseline exactly` (10 / 132 / 487 / 71). Note for the fleet launch: with `--strict` gating, **every** conversion PR must now re-record the baseline in the same PR. That is the intended cost, and it makes the fleet's "baseline must shrink by exactly the converted count" rule mechanically enforced instead of a review instruction. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
177c2309d9 |
consolidate/u11: a hold column is a planner lane only if it precedes wip (real defect in merged code) + funnel aliases (triage 11 -> 10) (#2645)
**Consolidation branch for u11/u7.** Supersedes #2624. Contents changed substantially while it sat unmerged — this body reflects what is actually in it now. ## Measured with the authoritative census, not grep `node scripts/lifecycle-column-census.mjs` — **triage guards 11 → 10.** ## 1. A real defect in merged code: a hold column is only a planner lane if it precedes implementation Found by greptile on #2616, verified by me, fixed here at the source because that PR cannot land. `resolveLifecycleColumns` returns `hold` as the **first** hold-trait column in declared order, with no positional constraint relative to wip (`workflow-lifecycle-traits.ts`: `hold: first(LIFECYCLE_ROLE_FLAGS.hold)`). A workflow using a hold trait for a **mid-pipeline wait** — a pause after implementation starts — therefore had that column returned as its planner lane, and `reconcileMissionFeatureState` demoted the feature to `triaged`. The mission board reported started work as not-yet-started: silent, and wrong in the direction that makes a roadmap lie. This is my defect, introduced in #2610. **Why it survived:** every lineage anyone has tested puts the hold *in front* of wip, so the default and Ideas boards are unaffected and no existing test could see it. **The fix is positional, with a deliberate asymmetry.** A hold column counts only when it appears before wip in declared order. When wip cannot be located the hold is left **out** rather than guessed — including it wrongly demotes live work on the roadmap, while excluding it wrongly costs only a `triaged` transition the next reconcile re-applies. Mutation-verified: dropping the positional test fails the mid-pipeline case and nothing else. ## 2. MissionControlPanel funnel aliases Assessed and **deliberately not trait-converted**. These are heuristic *name aliases* for a canonical SDLC stage — the matcher already accepts `signal`/`backlog`/`ready`/`shipped` because it buckets arbitrary boards, with an `other` fallback. Post-#2515 a default board's planning cards sit in `todo` and count at the Todo stage, leaving Planning at zero: the funnel reporting where cards *are*, not a guard that stopped firing. Hoisted to a named set so it stops reading as unconverted. This is the **DISPLAY-ALIAS** class the census still lacks — receiver *is* a column id, purpose is presentation rather than a lifecycle decision. `DocumentsView`'s status dot is the other one. Without that bucket a ratchet will keep demanding conversions that make the product worse. ## What I dropped, because main's version was better The original #2624 carried a `TaskContextMenu` conversion. #2626 landed `isPureIntakeColumn` — intake **without** hold — while mine treated any intake-flagged column as intake. That's wrong for a **merged Planning column**: it carries both traits, cards there wait for capacity and have real actions, so I would have suppressed the menu where it belongs — a new regression in place of the one I was fixing. Theirs is correct. Mine is gone, along with its now-invalid test and a helper nothing else used. ## Verification - merge gate green (482 + 132 + 10), engine tsc clean, dashboard tsc clean, lint clean - 7 planner-lane tests green, mutation-verified No changeset: `@fusion/engine` and `@fusion/dashboard` are private. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
31e49b684a |
TAKING default-workflow-hooks.ts + executor.ts + live-agent-count.ts + 6 dashboard files: reopen semantics by role, and the census's blind spot in both directions (13 sites) (#2628)
Batched conversion of every lifecycle-column guard I hold, plus the three the census could not see. **Six files to zero, repo-wide 60 → 49 by a comment-stripped unanchored sweep.** Each conversion has an isolated revert proof and a paired negative case, and the one code move is a separate commit from the behavior changes. ## Per-file before → after Counts from a comment-stripped, unanchored `(===|!==) ["']triage["']` sweep over `packages/*/src` + `plugins/*/src`, excluding tests. | file | before | after | note | |---|---:|---:|---| | `core/default-workflow-hooks.ts` | 4 | **0** | | | `core/task-store/moves.ts` | 5 | **4** | only the flag-ON mirror converted; the flag-OFF inline block is the parity reference and stays | | `engine/executor.ts` | 3 | **0** | **absent from the 45-guard list** — see below | | `core/live-agent-count.ts` | 2 | **0** | duplication removed; answer deliberately unchanged | | `engine/replan-target.ts` | 2 | **0** | both were comment prose, not guards | | `core/agent-prompts.ts` | 3 | **0** | ROLE comparisons, never column guards | | `engine/usage-limit-detector.ts` | 2 | **0** | ROLE comparisons | | `dashboard/app/components/DocumentsView.tsx` | 1 | **0** | real column guard | | `dashboard/app/components/TaskChatTab.tsx` | 2 | **0** | ROLE | | `dashboard/app/components/AgentLogViewer.tsx` | 1 | **0** | ROLE | | `dashboard/app/components/effective-model-resolution.ts` | 1 | **0** | ROLE | | `dashboard/app/hooks/useTasks.ts` | 1 | **0** | ROLE | | `dashboard/…/command-center/MissionControlPanel.tsx` | 1 | 1 | alias table, marked `DELIBERATE-LITERAL` with its reason | ## The census errs in BOTH directions This is the finding I would most like carried into the remaining work. - It **flagged 10 sites that were never column guards.** `role === "triage"` / `agentType === "triage"` compare an **AGENT ROLE**. The planner *lane* is named `triage` and keeps that name — U11 removed the *column*. Worse than noise: the obvious "finish the migration" edit is to rename the role, and that silently empties the planner's prompt template and mis-binds its model markers. `PLANNER_AGENT_ROLE` now names it, so the two vocabularies are distinguishable by grep and a rename fails loudly (revert proof: 4 tests, two of them pre-existing). - It **missed 3 real guards in `executor.ts`**, because the pattern matches `column`/`toColumn`/`fromColumn` and those locals are named `from` and `originColumn`. A census keyed on variable names will keep missing guards wherever a local was named for its role in the function. ## Two real defects, not tidying **1. A renamed board could merge with its re-review never run.** `default-workflow-hooks.ts` is named for the default workflow, but the store runs it on the flag-ON path for *every* workflow — the trait registry resolves hooks by trait id, not by workflow. Its reopen predicates listed the default lineage's column names, so on a renamed board **no reopen effect fired at all**. One of them clears `workflowStepResults`, which `getTaskMergeBlocker` reads: a card bounced out of review carried its old `passed` result back in, and that satisfies the merge gate. Same regression the graph-owned-crossing carve-out exists to prevent, arriving through the other door. (Two smaller ones rode along: failure state never cleared on a renamed reopen, and an operator dragging a card back to the queue never parked it, so the scheduler re-dispatched what they had just pulled back.) **I forgot the carve-out on my first pass, and that was worse than not converting.** A role-resolved clear plus a *name*-matched exemption means a renamed board takes the clear and never the exemption, destroying the remediation input the graph had just written. My own paired negative test caught it. **2. The last-resort recovery for completed-but-stranded work did not exist off the default lineage.** In `recoverCompletedTask`, `promotedFromPlannerColumn` was false on a renamed board, so finished work resting in the planning lane was never promoted — the code fell through to `handoffTaskToReview` straight from the planning column, and role adjacency has no planning → review edge, so the handoff was rejected and the card stayed stuck with its work complete. I converted the promotion **target** too: resolving the lane and then moving to a literal `in-progress` is the half-conversion I have already been burned by twice this program, where the guard starts admitting cards and the move then sends them to a column the board does not declare. ## E2E evidence `renamed-board-reopen.pg.test.ts` drives a **real PostgreSQL store** and a real `moveTask` on a workflow whose columns carry the standard traits under non-default names. The unit tests cannot show this: if `moves.ts` passed `undefined`, every unit case still passes via the no-basis fallback while the real board keeps the old behavior. **Proof it is load-bearing: forcing `moveLifecycleColumns` to `undefined` fails 2 of 3.** The executor suite covers both the split-role and the MERGED post-U11 shape. ## Revert proofs, isolated per site | change reverted | result | |---|---| | reopen predicate → literal names | 4 of 10 fail | | reopen field clears → literal names | 2 of 10 fail | | `userPaused` hold lane → literal `todo` | 1 of 10 fail | | graph carve-out → literal names | 1 of 10 fail | | store passes `undefined` lifecycle columns | 2 of 3 fail (real PG) | | `promotedFromPlannerColumn` → literals | 3 of 7 fail | | two-hop condition → `=== "triage"` | 1 of 7 fails | | promotion target → `"in-progress"` | 3 of 7 fail | | `isPlannerColumnFor` → literals | 1 of 7 fails | | live-agent-count: one arm dropped | 2 of 11 fail | | DocumentsView: trait branch removed | 3 of 7 fail | | planner role renamed to `"planner"` | 4 fail (2 pre-existing) | Every conversion is paired with a negative case (a forward move, a not-a-planner-lane card, a default-lineage card, a renamed column with no traits), so neither "always fire" nor "never fire" can pass for "resolve the role". ## Deliberately NOT converted, with reasons - **`moves.ts` flag-OFF inline block (4).** That branch *is* the legacy path, kept verbatim so the two can be parity-checked. Converting it erases the reference implementation. - **`live-agent-count.ts`'s no-flags fallback.** Reachable, and there is nothing to resolve from — `enrich…FromFlags` exists for callers with board flags rather than an IR, so a column missing from that map is the renamed case. "Not intake" is as much a guess as "todo is intake", and Running/Waiting are complements, so a card matching neither arm is reported as neither and the footer's queued total under-reports it. The real fix is at the caller; four new cases pin that flags override the legacy answer **in both directions**. What did change is the duplication: two hand-written copies of one rule now call one named function. - **`MissionControlPanel`'s `FUNNEL_STAGES`.** An alias table of column *names* where `triage` sits beside `signal` and `backlog`. Command Center aggregates across projects, so there is no single workflow to resolve traits from — the honest conversion is a data change, not a predicate change. - **`DocumentsView` with no traits.** Same no-basis rule; the documents list is full of historical columns absent from the current board. A case asserts a renamed column with no traits still reads as "working", documenting the gap rather than hiding it. ## Fixture findings Each cost a red run that looked like the code under test: - a `merge-blocker` column needs a reachable merge-class node, or `parseWorkflowIr` rejects the workflow; - a back-edge must be `kind: "rework"`, and a rework edge is legal only **into** a node with `config.reworkRegion: true`; - a workflow gets role-level transitions only when it declares wip + review + complete + **archived** plus a planning lane — without the archived column, adjacency falls back to order-derived neighbours and `checking -> queued` is not a legal move at all; - `recoverCompletedTask` only *reaches* the promotion seam when nothing is left to gate; without passed `plan-review`/`code-review` rows it re-enters the workflow graph and returns first, so a naive fixture silently tests the wrong branch and every assertion reads "no moves happened" for an unrelated reason. ## Verification - `pnpm test:gate` **71/71** - new suites: 10/10 reopen-semantics, 3/3 renamed-board-reopen (real PG), 7/7 executor-planner-lanes, 7/7 documents-status-dot, 4/4 planner-role-is-not-a-column - neighbours: 132 + 10 + 482 (gate shards), 350/351 engine planning/replan suites, 64/64 agent-prompts, 51/51 usage-limit-detector, 11/11 live-agent-count, 11/11 dashboard hook/log suites - the single engine failure (`executor-fast-mode-workflows.test.ts` › "raw fast mode still invokes non-executable review seam nodes") **reproduces with my changes stashed** — pre-existing on `origin/main` - typechecks clean for core, engine, and dashboard-app (`tsconfig.app.json`; `tsconfig.json` checks nothing under `app/`); `pnpm lint` clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
18d654a5ff |
capacity, part 3: delete the globalMaxConcurrent setting, API and UI (#2529)
Part 3 of the capacity simplification, and the half that removes the **knob**. Enforcement (shared semaphore, runtime wiring) went in #2509; this removes everything an operator or API client can still see, so nothing is left readable-but-ignored. ## Deleted Settings key + schema default · CentralCore’s `getGlobalConcurrencyState` / `updateGlobalConcurrency` / `acquireGlobalSlot` / `releaseGlobalSlot` and the `concurrency:changed` event · the whole Global Concurrency block in `async-central-core` · `PUT /api/global-concurrency` · the Scheduling · Global settings section · the footer and Command Center global sliders · the dead `getGlobalConcurrencyLimit` reader whose only caller went in #2509. ## Kept, deliberately **`GET /api/global-concurrency` survives as telemetry only** — live `currentlyActive` / `projectsActive` from CentralCore’s side-effect-safe source. “How busy is this machine?” is still a real question once the cap that used to answer it is gone. It no longer reports `globalMaxConcurrent`/`queuedCount`: those came from the deleted cap and from slot bookkeeping production code never incremented, so publishing them was publishing zeros dressed as state. **`useGlobalConcurrency` becomes read-only.** Everything that existed to *persist* went with the cap — the 500 ms debounce, the save-state machine, the commit-on-close/unmount flush, the slider clamp, the `interactive` gate. The module-level shared store is **kept**: its original justification (two mounted consumers drift apart with private copies) holds for a polled read exactly as it did for a cap, and one fetch now serves both. The live “N running (all projects)” readout survives in both surfaces, moved onto the per-project row. ## Two sections become one Scheduling · Global existed to host exactly one control. With it deleted the section renders an empty pane, so the Global/Project pair merges back into **“Scheduling”**. An empty nav entry is a promise of settings that are not there. ## One real fix found on the way `SchedulingSection`’s `concurrencyLoading` gated the **project** concurrency inputs on the **global**-concurrency fetch — never the right source, since `maxConcurrent` and `maxWorktrees` come from the settings form. It is repointed at the form’s own load, preserving the invariant it existed for: a concurrency input stays disabled until its live value arrives, so an operator cannot overwrite a resolved limit with a blank fallback. ## Migration A stored `globalMaxConcurrent` is **ignored** — it is a project-blob key nothing reads, so dropping it needs no schema change. The `central.global_concurrency` **table** is dropped in a follow-up; this slice stops seeding and reading it first, so that drop has no live writer to race. ## Verification, and how the wider suite was controlled `pnpm lint` clean · core/engine/dashboard `tsc` clean · `pnpm test:gate` green (309 + 10 + 71) · dashboard settings/footer/command-center/hooks **2237/2237** · core `central-core-backend` 9/9. The broader dashboard suite shows failures, and I checked rather than assumed: running the suspect files on **clean main** reproduces `api-git` (49), `TaskDetailModal.rendering` (28) and `settings-mobile` (17) identically. Two were genuinely mine — `SettingsModal.scheduling-merge` (0 on main, 17 on this branch: my nav rename) and one `settings-mobile` picker case asserting `scheduling` is a scoped pair — and both are fixed. Tests for deleted behaviour are removed with it (footer confirm/cancel/flush/dedupe, global marker geometry, the hook’s PUT case, the CentralCore slot cases), each carrying a note on what it guarded and where the surviving **project-side** equivalent lives. Fixture-only references were updated, not deleted. Nothing booted. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
743df98aa4 |
capacity, part 1: merge pinned at 1, worktrees-off mode, and one dead knob deleted (#2502)
First slice of the capacity simplification. Operator: *"just have two
capacity — overall per project agent count and max worktrees. Remove all
other capacities and counts."* Plus two later additions: **merge is
always 1, fixed**, and **worktrees off ⇒ limit by total agents only**.
Three independently revertable commits. No limiter is added anywhere;
one is deleted, one is made structurally absent, and one is pinned.
---
## 1. Merge concurrency ratcheted at 1 (test-only)
I was asked to add a limiter if merge concurrency could be raised. **It
cannot** — there is no setting, workflow property, pool or trait config
anywhere that raises it, so this adds no code and pins what already
holds.
Serialization lives in the **pump**: `drainMergeQueue`’s `mergeRunning`
re-entrancy latch, `activeMergeTaskId` as a single-slot identity, the
`mergeBodyInFlight` next-generation latch, and one `ProjectEngine` per
projectId.
**Not** in the merge-queue lease, which is a per-task ROW (`primaryKey
[projectId, taskId]`) — two tasks can hold leases simultaneously by
construction, and it has exactly one caller (the worktree-reuse
handoff). Ordinary merges never take it. A lease-level test would have
been describing an invariant that layer has never held.
The second half guards the other direction: a merge-concurrency
*setting* would not fail the pump ratchet — it would sit unread until
someone wired it up.
**Revert-proof:** deleting the latch → `expected 1 times, but got 2
times`; deleting the `finally` → latch-stuck; injecting
`maxConcurrentMerges: 2` → fails naming the key; injecting a
`maxParallelLanes` merge-trait field → fails naming the field. Sources
restored byte-identical after each injection.
## 2. `worktreesEnabled` — off means the worktree limit cannot bind
No worktrees-off mode existed (no
`worktreesEnabled`/`useWorktrees`/`worktreeMode` anywhere — only
worktree *configuration*).
**Why not `maxWorktrees: 0`, which needs no new key:** it deadlocks. `??
4` keeps `0` (not nullish), the gate is `used >= limit`, so `0 >= 0`
holds **on an empty board** and nothing ever dispatches — while the
operator-visible reason reads `gate=maxWorktrees; used=0/0`, a limiter
that looks like it is working while the board is dead. It also needs the
Command Center `{min:1}` clamp relaxed. So `0` costs the gate rewrite
*and* the clamp change *and* encodes a mode as a magic value.
**Off is absence, not a big number.** `resolveWorktreeCapacityLimit`
returns `number | null`; `ConcurrencyGateDiagnostic.maxWorktreesGate` is
now optional, so consulting a worktree limit in OFF mode does not
type-check. A gate holding `Infinity` can start binding again the moment
someone "fixes" a comparison; an absent gate cannot.
That paid for itself immediately: making it nullable surfaced a
**second, independent** worktree gate (`activeWorktrees >= maxWorktrees`
early-return) that a skip-by-convention approach would have missed
silently.
**Scope, deliberately:** this is a statement about *counting*, not
isolation. It does not make concurrent agents safe to share one checkout
and builds nothing toward that — the non-worktree paths that exist today
are fallbacks to the operator’s own tree, one of which caused FN-8600.
**Revert-proof:** a resolver ignoring the flag turns both OFF scheduler
tests red while every ON test stays green — they reuse the *same*
fixture (5 in-progress, limit 4) that pre-existing tests prove blocks,
so the pair moves in opposite directions. Removing `disabled:` reddens
the UI test.
## 3. `maxTriageConcurrent` deleted — it controlled nothing
**Measured: zero enforcement reads.** The only `.maxTriageConcurrent`
reference in the repo was a route echoing it back in `/config`. FN-8453
removed the pool it gated and left the knob shipping in
`DEFAULT_SETTINGS`, the settings type, the section registry, the API
response and six i18n catalogs, doing nothing, for releases.
Historical FNXC comments are **updated, not deleted** — they explain a
real past incident; they now say "planning admission slot" so they stop
implying a live setting. Tombstoned so it cannot return.
`/config` loses a field; safe in-repo since `fetchConfig`’s own return
type never declared it.
---
## Two corrections worth recording
- I earlier reported `maxWorktrees` had **no** Settings UI. Wrong —
`WorktreesSection.tsx:47`; my grep was truncated by `head`. It changed
the placement (toggle beside it, rather than a duplicate key in
Scheduling).
- I planned to assert the queued-reason string is rewritten in OFF mode.
Measured that it is **unreachable**: when `maxConcurrent` binds, the
sweep bails before the per-task reason and logs nothing. The test
asserts absence instead.
Two near-misses caught before commit: a pre-existing FN-7505 guard
caught my *new* key missing a description mapping; and editing i18n via
`json.load/dump` silently dropped unrelated duplicate keys
(`autoUpdateAndRestart` in `fr`) — Python keeps only the last of a
duplicated key. Redone textually, every catalog re-validated.
## Verification
`pnpm lint` clean · core/engine/dashboard/i18n typecheck clean · `pnpm
test:gate` green (309 + 10 + 71) · capacity/worktree suites 11/11 ·
engine merge-invariant + scheduler 45/45 · dashboard settings 114/114.
Rebased onto current main and re-verified.
Nothing was booted at any point.
🤖 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 project setting to enable or disable running tasks in
worktrees.
* Disabling worktrees removes worktree capacity limits from task
scheduling.
* The “Max Worktrees” setting is disabled when worktree execution is
turned off.
* **Changes**
* Removed the unused triage concurrency setting from configuration and
dashboard responses.
* Updated scheduling diagnostics and queue messages to reflect disabled
worktree capacity limits.
* Added localized labels and help text for the new setting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
f26cbedf4f |
fix(dashboard): close the code-review findings on the mobile tab-discard work
An 11-reviewer pass over f157bf7460..f5163d8351 found defects in the mobile tab-discard change set itself. This fixes them. Silent data loss (the recurring defect class): - AgentDetailView reconnect refetched limit:100 and replaced wholesale, so 380 displayed lines vanished with no "Load older" and no indicator; it now reconciles through the shared logStreamReconcile helper. - useActivityLog.loadMore past the cap discarded the page it had just fetched while advancing the cursor and leaving hasMore true, so the feed silently stopped paginating behind a live-looking button. - useAgentLogs: loadMore and resyncFromServer had no mutual exclusion, a no-overlap resync discarded explicitly paged-back history, a resync outliving the reconnect delay left an unmarked gap, and the live-tail trim could evict the gap marker itself. - useLiveTranscript's resync overwrote live entries that raced the refetch. The premise itself was not fully delivered: - useProjects, useNodes, and useMeshState never called clearInterval, so they polled the whole time the tab was hidden. useProjects is mounted for the entire session, so the page never went idle -- the primary mechanism this work depends on. All three now use the shared visibility gate. - sse-bus fired onReconnect twice per reconnect cycle and fanned out ~28 subscribers in one tick, against a ~6-connection-per-origin cap on a waking radio. The successful open is now the single authority, and the fan-out uses the same exported stagger primitive as the polling path rather than a second copy of the slot formula. - A channel first subscribed during the hidden window opened a live EventSource and keepalive; suspension is now a module-level condition openChannel consults, and a channel opened inside the grace window re-arms it. Credentials and correctness: - The service worker persisted every GET /api/* to durable Cache Storage, including /api/settings with daemonToken, githubAuthToken, gitlabAuthToken and ntfyAccessToken in plaintext, with no exclusion and no purge path -- "Clear all cached data" only walked localStorage. Now gated, bounded, and genuinely purgeable. - useTasks cleared its own snapshot when the mount revalidation failed on a waking radio, so the board blanked and the next restore was empty too. Suspension-class failures no longer destroy the cache. - A single-row SSE update reset lastFetchTimeMs to now while an hours-old hydrated snapshot was on screen, re-marking every in-progress card stuck. - ListView's "Select all visible tasks" acted on the full filtered set while only 50 rows rendered, so a bulk delete reached rows the operator could not see. Column's search window reset keyed on a boolean, so refining a query kept the expanded window. Tests that could not fail: - App.test.tsx mocked TerminalModal as isOpen ? <div/> : null, making the unmount-on-close invariant unobservable; MockEventSource kept its listeners after close(), so cases passed with their onReconnect handlers deleted. - The SSE resync ratchet scanned only hooks/, exempting ~13 component call sites -- the exact regression it exists to prevent. - MissionControlPanel's bespoke poll and the xterm scrollback constants and WebGL disposal had no coverage at all. Verified: tsc -p tsconfig.app.json clean, pnpm lint clean, pnpm check:changesets clean, 877 tests passing across 36 scoped files. Known unrelated red: MailboxView.test.tsx's FN-8407 CSS guard fails at HEAD too -- this diff adds no @media rule and no .mailbox-view--mobile selector, the only two things that assertion inspects. Left alone deliberately. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f157bf7460 |
fix(dashboard): harden visibility suspension, log caps, and mobile board UX
Suspend poll/SSE work when the tab is hidden, cap log buffers, restore board scroll more reliably, and improve list windowing/live tickers with related tests and a mobile-tab retention changeset. |
||
|
|
2a2b157cb9 |
FN-8585: fix dashboard composer test source reads
Stabilize dashboard composer tests when Vitest launches from the workspace root. - Resolve dashboard test source fixtures relative to the app directory. - Migrate affected component tests away from cwd-relative CSS reads. - Enforce the fixture convention in test hooks and document it. Files changed: docs/testing.md | 4 +++ package.json | 6 ++-- .../__tests__/AuthTokenRecoveryDialog.test.tsx | 3 +- .../components/__tests__/ChatView.mobile.test.tsx | 5 +-- .../__tests__/EngineControlMenu.test.tsx | 11 ++---- .../components/__tests__/FloatingWindow.test.tsx | 5 +-- .../app/components/__tests__/ListView.test.tsx | 5 +-- .../__tests__/MissionInterviewModal.test.tsx | 3 +- .../app/components/__tests__/MobileNavBar.test.tsx | 3 +- .../app/components/__tests__/NewTaskModal.test.tsx | 3 +- .../__tests__/PlanningModeModal.initial.test.tsx | 3 +- .../PlanningModeModal.ui-interactions.test.tsx | 7 ++-- .../components/__tests__/PrCreateModal.test.tsx | 3 +- .../__tests__/QuickChat.persist.test.tsx | 3 +- .../components/__tests__/QuickEntryBox.test.tsx | 3 +- .../components/__tests__/ReportActionMenu.test.tsx | 9 ++--- .../app/components/__tests__/ReportModal.test.tsx | 3 +- .../__tests__/ShadcnColorPicker.test.tsx | 3 +- .../components/__tests__/TerminalModal.test.tsx | 3 +- .../components/__tests__/ThemeDropdown.test.tsx | 9 ++--- .../__tests__/WorkflowNodeEditor.test.tsx | 5 +-- .../WorkflowOptionalStepsDropdown.test.tsx | 3 +- .../components/__tests__/WorkflowSwitcher.test.tsx | 5 +-- .../app/components/__tests__/board-mobile.test.tsx | 4 +-- .../__tests__/CommandCenterControls.test.tsx | 6 ++-- .../__tests__/SystemControlsArea.test.tsx | 5 +-- .../__tests__/SystemStatsArea.test.tsx | 3 +- .../command-center/areas/__tests__/areas.test.tsx | 3 +- .../__tests__/KeyboardShortcutsSection.test.tsx | 3 +- .../app/test/__tests__/cssFixture.test.ts | 35 +++++++++++++++++++ packages/dashboard/app/test/cssFixture.ts | 12 +++++++ .../check-no-cwd-relative-dashboard-test-reads.mjs | 39 ++++++++++++++++++++++ 32 files changed, 162 insertions(+), 55 deletions(-) Fusion-Task-Id: FN-8585 Fusion-Task-Lineage: 83a35fb6-a29d-4e97-b282-1054c68b8cc9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
ec535b5f3c |
fix(dashboard-tests): stub Element.prototype.scrollIntoView in SystemControlsArea suite
The rebuild-job effect schedules jobSectionRef scrollIntoView in a rAF; jsdom elements lack the method, so a frame firing before unmount threw an unhandled error that failed the run even with all assertions passing. Module-level stub follows the ChatView.message-edit convention; the per-test spy still overrides it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1e05793876 |
fix(ci): green full-suite bookkeeping after origin/main cutover (#2392)
## Summary Restores green merge-gate and package-default suites after repeated `origin/main` merges brought workflow-graph ownership cutover drift into CI. - Align engine/dashboard/core tests with post-cutover contracts (`moveTaskIf`/`deleteTaskIf`, graph handoff, worktree-pool reclaim via `removeWorktree` + `RemovalReason`, multi-step RESUMING parse, soft-pause merge requester, graph-terminal failure surfaces). - Small product fixes needed for real regressions uncovered by the suite: soft-delete refuse before graph routing, skip DUPLICATE step-heading withhold when an explicit marker is present, PG schema applier guards, and related bookkeeping (research promote tool inventory / migration seed, stop shell `psql` in PG admin DDL). - Quarantine/ledger hygiene only where required by standing rules; no timeout/worker appeasement. ## Verification - `pnpm test:gate` ×2 green - `@fusion/engine` full package suite green (~9083 tests) - Targeted core/dashboard clusters green (schema applier, agent-runs UI, settings descriptions, mobile close) ## Test plan - [x] `pnpm test:gate` (twice) - [x] `pnpm --filter @fusion/engine test` - [ ] CI full suite / PR checks on this branch - [ ] Confirm no unrelated product behavior changes beyond the listed regression fixes <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for `roadmap-item` native structure kinds, including native structure embeds and metadata validation. * Added Stable and Beta release channel options in General settings. * Added per-action reporting target configuration with clearer “unset” guidance. * **Bug Fixes** * Improved heartbeat/prompt behavior when patrol is disabled. * Prevented deleted tasks from continuing through execution. * Made recovery for explicit duplicate redirects more permissive. * Hardened database migration and test database cleanup to reduce flaky failures. * **Documentation** * Updated settings text for release channels, reporting targets, and inheritance/unset behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
cd51e1c0d8 |
FN-8471: add color theme filtering
Add a searchable shared color-theme picker for Settings and Command Center. - Filter translated theme labels case- and diacritic-insensitively - Preserve keyboard navigation, focus management, and selection behavior - Document the picker and add a minor release changeset Files changed: .changeset/fn-8471-theme-filter.md | 7 + docs/dashboard-guide.md | 3 +- .../dashboard/app/components/ThemeDropdown.css | 32 ++++ .../dashboard/app/components/ThemeDropdown.tsx | 172 +++++++++++++++------ .../components/__tests__/ThemeDropdown.test.tsx | 106 +++++++++++++ .../components/__tests__/ThemeSelector.test.tsx | 1 + .../__tests__/CommandCenterControls.test.tsx | 1 + 7 files changed, 277 insertions(+), 45 deletions(-) Fusion-Task-Id: FN-8471 Fusion-Task-Lineage: 1f73dfb8-18bb-48e6-a3ed-0ee3a200cf03 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
d486bf49dd |
FN-8456: add Dawn dashboard color theme
Add a persisted Dawn indigo-and-amber color theme across dashboard and desktop first paint. - Register Dawn in theme persistence, selector metadata, and pre-hydration validation. - Define dark and light Dawn tokens plus mode-aware selector swatches. - Cover persistence, theme registries, token completeness, and selector previews with tests. Files changed: .changeset/fn-8456-dawn-theme.md | 7 ++ docs/dashboard-guide.md | 3 +- docs/settings-reference.md | 2 +- .../core/src/__tests__/global-settings.test.ts | 8 ++ packages/core/src/types/execution-and-ui.ts | 2 + .../dashboard/app/__tests__/dawn-theme.test.ts | 98 ++++++++++++++++++++++ .../dashboard/app/components/ThemeSelector.css | 14 ++++ .../components/__tests__/ThemeDropdown.test.tsx | 22 ++--- .../components/__tests__/ThemeSelector.test.tsx | 2 +- .../__tests__/CommandCenterControls.test.tsx | 7 +- packages/dashboard/app/components/themeOptions.ts | 1 + .../dashboard/app/hooks/__tests__/useTheme.test.ts | 12 +++ packages/dashboard/app/index.html | 2 +- packages/dashboard/app/public/theme-data.css | 86 ++++++++++++++++++- packages/desktop/src/renderer/index.html | 1 + 15 files changed, 248 insertions(+), 19 deletions(-) Fusion-Task-Id: FN-8456 Fusion-Task-Lineage: 44d9eb05-210d-4be8-8d35-c66ac4857194 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
eef5eb751e |
FN-8453: unify concurrency accounting and indicators
Unify live-agent capacity accounting across engine and dashboard. - Derive Running and Waiting from workflow traits and durable agent liveness. - Apply unified limits to planner, executor, and merge admission while updating dashboard indicators. - Remove duplicate concurrency controls and document the unified operator model. Files changed: .changeset/fn-8453-unified-concurrency.md | 7 + docs/agent-tool-surface-full-loop.md | 4 +- docs/architecture.md | 2 +- docs/dashboard-guide.md | 4 +- docs/settings-reference.md | 4 +- .../skill/fusion/references/fusion-capabilities.md | 4 +- .../core/src/__tests__/live-agent-count.test.ts | 91 ++++---- packages/core/src/index.gate.ts | 6 + packages/core/src/index.ts | 6 + packages/core/src/live-agent-count.ts | 107 ++++++--- packages/dashboard/app/App.tsx | 28 ++- packages/dashboard/app/api/board-workflows.ts | 2 + packages/dashboard/app/components/Column.tsx | 6 +- .../dashboard/app/components/EngineControlMenu.tsx | 26 --- .../dashboard/app/components/ExecutorStatusBar.tsx | 38 ++- .../dashboard/app/components/SettingsModal.tsx | 1 - .../app/components/__tests__/Column.test.tsx | 6 +- .../__tests__/EngineControlMenu.test.tsx | 10 +- .../__tests__/ExecutorStatusBar.test.tsx | 32 ++- .../command-center/CommandCenterControls.tsx | 26 --- .../settings/sections/SchedulingSection.search.ts | 9 - .../settings/sections/SchedulingSection.tsx | 13 -- .../app/hooks/__tests__/useExecutorStats.test.ts | 12 +- packages/dashboard/app/hooks/useExecutorStats.ts | 50 ++-- .../src/__tests__/project-store-resolver.test.ts | 11 +- packages/dashboard/src/project-store-resolver.ts | 14 +- .../register-config-mcp-pi-settings-routes.ts | 3 +- packages/engine/src/__tests__/concurrency.test.ts | 123 +++++++++- .../engine/src/__tests__/project-engine.test.ts | 34 +++ packages/engine/src/__tests__/triage.test.ts | 7 +- packages/engine/src/concurrency.ts | 207 ++++++++++++++++- packages/engine/src/project-engine.ts | 151 ++++++++++-- packages/engine/src/scheduler.ts | 82 ++++++- packages/engine/src/triage.ts | 254 +++++++++++++-------- .../lib/dashboard-browser-safe-core-modules.json | 5 + 35 files changed, 991 insertions(+), 394 deletions(-) Fusion-Task-Id: FN-8453 Fusion-Task-Lineage: 12cfa5df-675d-4fce-b17e-932376544239 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
0908e75290 |
FN-8455: add Calm dashboard color theme
Add a persisted Calm theme with slate, sage, and misty light palettes. - Register Calm across core settings, dashboard selectors, and web/desktop first-paint validators. - Define Calm theme tokens and selector swatches for dark and light modes. - Cover persisted selection, previews, and bootstrap validation with tests. - Document the new theme and add a minor release changeset. Files changed: .changeset/fn-8455-calm-theme.md | 7 ++ docs/dashboard-guide.md | 3 +- docs/settings-reference.md | 2 +- packages/core/src/__tests__/global-settings.test.ts| 8 ++ packages/core/src/types/execution-and-ui.ts | 2 + packages/dashboard/app/__tests__/calm-theme.test.ts| 98 ++++++++++++++++++++++ packages/dashboard/app/components/ThemeSelector.css| 14 ++++ packages/dashboard/app/components/__tests__/ThemeDropdown.test.tsx | 22 ++--- packages/dashboard/app/components/__tests__/ThemeSelector.test.tsx | 2 +- packages/dashboard/app/components/command-center/__tests__/CommandCenterControls.test.tsx | 2 +- packages/dashboard/app/components/themeOptions.ts | 1 + packages/dashboard/app/hooks/__tests__/useTheme.test.ts | 12 +++ packages/dashboard/app/index.html | 2 +- packages/dashboard/app/public/theme-data.css | 86 ++++++++++++++++++- packages/desktop/src/renderer/index.html | 1 + 15 files changed, 245 insertions(+), 17 deletions(-) Fusion-Task-Id: FN-8455 Fusion-Task-Lineage: c2c4624e-7012-491d-bd79-d3de570018f7 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
527f734ad4 |
FN-8454: add Aurora dashboard theme
Add the Aurora color theme across dashboard and desktop theme surfaces. - Register Aurora as a selectable global theme with matching UI styles and metadata - Load Aurora theme data in dashboard and desktop entry points - Document the theme and cover selection, token, and settings behavior Files changed: .changeset/fn-8454-aurora-theme.md | 7 ++ docs/dashboard-guide.md | 3 +- docs/settings-reference.md | 2 +- .../core/src/__tests__/global-settings.test.ts | 8 ++ packages/core/src/types/execution-and-ui.ts | 2 + .../dashboard/app/__tests__/aurora-theme.test.ts | 98 ++++++++++++++++++++++ .../dashboard/app/components/ThemeSelector.css | 14 ++++ .../components/__tests__/ThemeDropdown.test.tsx | 51 ++++++++++- .../components/__tests__/ThemeSelector.test.tsx | 2 +- .../__tests__/CommandCenterControls.test.tsx | 2 +- packages/dashboard/app/components/themeOptions.ts | 1 + .../dashboard/app/hooks/__tests__/useTheme.test.ts | 12 +++ packages/dashboard/app/index.html | 2 +- packages/dashboard/app/public/theme-data.css | 91 ++++++++++++++++++++ packages/desktop/src/renderer/index.html | 1 + 15 files changed, 290 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-8454 Fusion-Task-Lineage: cbae0854-b884-4744-a2fa-f738a71ceb32 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
087fd8f881 |
FN-8429: fix live activity snapshot metrics
Keep Live activity counts current and project-scoped rather than date-range derived. - Exclude soft-deleted tasks from live board column totals - Share SSE-refreshed live snapshots between Overview and Mission Control - Count all in-progress aliases and current active sessions/runs - Cover live refresh, date-range independence, and deleted-task behavior Files changed: docs/dashboard-guide.md | 2 +- .../command-center-remaining-analytics.pg.test.ts | 12 ++- packages/core/src/command-center-live.ts | 15 +++- .../components/command-center/CommandCenter.tsx | 43 +++------- .../command-center/MissionControlPanel.tsx | 46 +++++++---- .../__tests__/CommandCenter.test.tsx | 91 ++++++++++++++++++---- .../command-center/liveSnapshotMetrics.ts | 32 ++++++++ 7 files changed, 174 insertions(+), 67 deletions(-) Fusion-Task-Id: FN-8429 Fusion-Task-Lineage: a29a92a1-1d27-4927-9e19-9c42e66a0674 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
365874f7f9 |
FN-8406: consolidate Command Center report actions
Move the guided report flow to System while ensuring its menu reliably overlays dashboard content. - Portal the shared ReportActionMenu with a defined dropdown/modal stacking scale. - Make System the sole Command Center report home and retain Copy diagnostics as a local action. - Update regression coverage, documentation, and the published package changeset. Files changed: .changeset/fn-8406-report-home-zindex.md | 7 ++ docs/dashboard-guide.md | 4 +- .../dashboard/app/components/ReportActionMenu.css | 5 +- .../dashboard/app/components/ReportActionMenu.tsx | 72 ++++++++++++- .../components/__tests__/ReportActionMenu.test.tsx | 12 +++ .../components/command-center/CommandCenter.css | 32 ------ .../components/command-center/CommandCenter.tsx | 59 ++++------- .../__tests__/CommandCenter.test.tsx | 8 +- .../__tests__/SystemControlsArea.test.tsx | 94 +---------------- .../command-center/areas/SystemControlsArea.tsx | 112 ++++----------------- packages/dashboard/app/styles.css | 11 ++ 11 files changed, 144 insertions(+), 272 deletions(-) Fusion-Task-Id: FN-8406 Fusion-Task-Lineage: 957a77b0-fb04-4024-9506-225fec562f5d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
bea51f7bdb |
FN-8348: relocate report actions to settings and command center
Relocate guided reporting from the header into durable project and overview surfaces. - Add Report entry points to Project General settings and Command Center Overview. - Preserve guided report modal context through a shared route helper. - Cover relocated controls and update dashboard guidance. Files changed: docs/dashboard-guide.md | 2 +- packages/dashboard/app/components/Header.tsx | 33 ++++------------------ .../dashboard/app/components/SettingsModal.tsx | 2 +- .../app/components/__tests__/Header.test.tsx | 7 +++++ .../components/command-center/CommandCenter.css | 32 +++++++++++++++++++++ .../components/command-center/CommandCenter.tsx | 30 +++++++++++++++++++- .../__tests__/CommandCenter.test.tsx | 11 ++++++++ .../settings/sections/GeneralSection.tsx | 21 ++++++++++++++ .../GeneralSection.aiUndoWorkflow.test.tsx | 20 +++++++++++-- packages/dashboard/app/utils/reportContextRefs.ts | 13 +++++++++ 10 files changed, 139 insertions(+), 32 deletions(-) Fusion-Task-Id: FN-8348 Fusion-Task-Lineage: add1b302-deab-4e17-be2f-832971c1c83d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
12aee016ee |
FN-8352: promote ideation to top-level navigation
Make ideation independently accessible from desktop and mobile navigation. - Add an Ideation view backed by the Command Center panel and view-state routing. - Surface Ideation in desktop/sidebar and mobile primary navigation, with coverage for navigation and rendering. - Document the experimental setting and add a minor changeset. Files changed: .changeset/fn-8352-ideation-top-level-view.md | 7 ++++ docs/dashboard-guide.md | 14 +++++++ docs/settings-reference.md | 3 +- .../src/__tests__/mobile-nav-primary-items.test.ts | 10 ++++- packages/core/src/mobile-nav-primary-items.ts | 17 +++++++- packages/dashboard/app/App.tsx | 16 ++++++- packages/dashboard/app/components/Header.tsx | 21 +++++++-- .../dashboard/app/components/LeftSidebarNav.tsx | 8 +++- packages/dashboard/app/components/MobileNavBar.tsx | 2 + .../dashboard/app/components/SettingsModal.tsx | 6 +++ .../app/components/__tests__/App.test.tsx | 20 +++++++++ .../app/components/__tests__/Header.test.tsx | 15 +++++++ .../components/__tests__/LeftSidebarNav.test.tsx | 5 +++ .../app/components/__tests__/MobileNavBar.test.tsx | 43 +++++++++++++++--- .../components/command-center/CommandCenter.tsx | 12 +++--- .../__tests__/CommandCenter.test.tsx | 7 ++-- .../__tests__/IdeationPanel.test.tsx | 49 ++++++++++++++++++++++ .../app/components/dashboard/MainContent.tsx | 13 ++++++ .../dashboard/app/components/dashboard/types.ts | 1 + .../settings/sections/GeneralSection.tsx | 10 ++--- packages/dashboard/app/hooks/useViewState.ts | 8 +++- 21 files changed, 256 insertions(+), 31 deletions(-) Fusion-Task-Id: FN-8352 Fusion-Task-Lineage: e7791119-2fe5-4e68-b669-0e5bd8df9b49 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
0cba6fa56a |
FN-8351: move org portability controls to Team
Move organization export and import from Overview to the Team section. - Render the existing portability controls in TeamArea with the established settings refresh flow - Remove the Overview mount and update focused placement coverage - Document the Team-tab location and add a patch changeset Files changed: .changeset/fn-8351-org-portability-team-tab.md | 7 +++ docs/dashboard-guide.md | 3 +- .../command-center/CommandCenterControls.tsx | 6 +- .../__tests__/CommandCenterControls.test.tsx | 15 ++--- .../components/command-center/areas/TeamArea.tsx | 8 +++ .../areas/__tests__/TeamArea.test.tsx | 66 ++++++++++++++++++++++ 6 files changed, 91 insertions(+), 14 deletions(-) Fusion-Task-Id: FN-8351 Fusion-Task-Lineage: 3877a8ec-f307-4da5-88bb-806e1428d14a Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
9f44f26a36 |
FN-8350: move configuration versions into Settings
Move project configuration revision history and rollback controls from Command Center to Settings. - Add a Project Settings configuration versions section with rollback handling. - Remove the Command Center revision card and retain organization portability controls. - Update translations, dashboard documentation, tests, and release metadata. Files changed: .changeset/fn-8350-config-versions-settings.md | 7 ++ docs/dashboard-guide.md | 3 +- .../dashboard/app/components/SettingsModal.tsx | 11 ++++ .../command-center/OrgPortabilityControls.css | 47 ++------------ .../command-center/OrgPortabilityControls.tsx | 55 +--------------- .../__tests__/CommandCenter.mobile-scroll.test.tsx | 2 +- .../__tests__/OrgPortabilityControls.test.tsx | 37 ++--------- .../sections/ConfigurationVersionsSection.css | 56 ++++++++++++++++ .../sections/ConfigurationVersionsSection.tsx | 75 ++++++++++++++++++++++ .../ConfigurationVersionsSection.test.tsx | 58 +++++++++++++++++ packages/i18n/locales/en/app.json | 29 +++++---- 11 files changed, 238 insertions(+), 142 deletions(-) Fusion-Task-Id: FN-8350 Fusion-Task-Lineage: a7f68720-038a-42a6-b064-38533c584492 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
38891bfd81 |
FN-8296: add chat-requested task verification
Enable chat agents to queue and monitor executor-owned verification runs. - Persist task verification requests through a new PostgreSQL migration. - Expose action-gated chat request and status tools with executor processing. - Show verification status in task and Command Center views. - Advance the schema baseline to migration 0024 and keep chat mocks complete. Files changed: .changeset/fn-8296-feature.md | 7 ++ docs/agent-tool-surface-full-loop.md | 10 +-- docs/dashboard-guide.md | 4 + packages/core/src/index.ts | 2 + .../core/src/postgres/migrations/0000_initial.sql | 20 +++++ .../migrations/0024_task_verification_request.sql | 20 +++++ packages/core/src/postgres/schema-applier.ts | 13 ++- packages/core/src/postgres/schema/project.ts | 25 ++++++ packages/core/src/store.ts | 16 +++- packages/core/src/task-store/reads.ts | 14 +++- packages/core/src/task-store/remaining-ops-6.ts | 49 ++++++++++- packages/core/src/types.ts | 30 +++++++ packages/dashboard/app/api/legacy.ts | 1 + packages/dashboard/app/api/task-content.ts | 10 +++ .../dashboard/app/components/TaskDetailModal.tsx | 17 +++- .../app/components/TaskVerificationStatus.css | 94 ++++++++++++++++++++++ .../app/components/TaskVerificationStatus.tsx | 39 +++++++++ .../__tests__/TaskVerificationStatus.test.tsx | 28 +++++++ .../components/command-center/CommandCenter.css | 33 ++++++++ .../components/command-center/CommandCenter.tsx | 37 ++++++++- packages/dashboard/src/__tests__/chat.test.ts | 1 + packages/dashboard/src/chat.ts | 55 +++++++++++++ .../src/routes/register-command-center-routes.ts | 20 +++++ .../src/routes/register-task-workflow-routes.ts | 17 ++++ packages/engine/src/executor.ts | 51 +++++++++++- packages/engine/src/gating-classifications.ts | 5 ++ packages/engine/src/index.ts | 2 +- 27 files changed, 605 insertions(+), 15 deletions(-) Fusion-Task-Id: FN-8296 Fusion-Task-Lineage: f94647cf-c89f-4f0e-b25f-cbf5b56683bc Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
ed2ffc4885 |
FN-8346: preserve manual scroll position in live logs
Preserve the sticky-bottom follow invariant across streamed Dev Server and System Controls output. - Track pinned-bottom state synchronously for rebuild and system-log streams. - Follow in-place Dev Server transcript mutations only while the reader is pinned. - Cover manual unsnapping, stream growth, and re-pinning behavior. - Add a patch changeset for live-log scrolling. Files changed: .changeset/fn-8346-live-tail-scroll-follow.md | 7 ++ .../app/components/DevServerLogViewer.tsx | 43 ++++++++++-- .../__tests__/DevServerLogViewer.test.tsx | 47 +++++++++++++ .../__tests__/SystemControlsArea.test.tsx | 81 +++++++++++++++++++++- .../command-center/areas/SystemControlsArea.tsx | 44 ++++++++++-- 5 files changed, 208 insertions(+), 14 deletions(-) Fusion-Task-Id: FN-8346 Fusion-Task-Lineage: c1eeb84d-c0af-473b-99f1-0d8564ac8a24 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
1a63b6dba6 |
fix(ci): index embedded Postgres cap and mock portability API in CC controls (#2317)
## Summary - Index `embeddedPostgresMaxConnections` in Settings search (backups-global). - Export `withProjectId` + `api` from `CommandCenterControls` legacy mock so FN-8284 portability card can mount under the controls suite. ## Test plan - [x] CommandCenterControls + settings-search-index tests green locally - [ ] Full Suite all 4 shards green on main after merge <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added the embedded PostgreSQL maximum connections setting to Settings search, with relevant labels, help text, and keywords. * **Tests** * Improved test coverage setup for controls that use project-specific API paths. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d51ce46db5 |
FN-8295: add persisted ideation mission handoffs
Persist bounded ideation sessions through agent tools, the Command Center, and atomic Mission convergence. - Store ideation sessions and divergent candidates in PostgreSQL with async APIs and migration support. - Expose gated ideation tools, chat routes, and agent lifecycle integration. - Add the Ideation panel, documentation, release metadata, and regression coverage. Files changed: .changeset/fn-8295-ideation-diverge-converge.md | 7 ++ docs/ideation/persisted-diverge-converge.md | 22 ++++ docs/missions.md | 4 + .../__tests__/postgres/ideation-store.pg.test.ts | 57 +++++++++ packages/core/src/async-ideation-store-queries.ts | 117 +++++++++++++++++ packages/core/src/async-ideation-store.ts | 138 +++++++++++++++++++++ packages/core/src/async-mission-store.ts | 27 ++-- packages/core/src/ideation-types.ts | 69 +++++++++++ packages/core/src/index.ts | 3 + .../core/src/postgres/migrations/0022_ideation.sql | 67 ++++++++++ packages/core/src/postgres/schema-applier.ts | 18 ++- packages/core/src/postgres/schema/project.ts | 49 +++++++- packages/core/src/store.ts | 8 +- packages/core/src/task-store/remaining-ops-8.ts | 14 +++ .../components/command-center/CommandCenter.tsx | 7 +- .../components/command-center/IdeationPanel.css | 18 +++ .../components/command-center/IdeationPanel.tsx | 58 +++++++++ .../__tests__/CommandCenter.test.tsx | 6 +- .../dashboard/src/__tests__/chat-manager.test.ts | 1 + packages/dashboard/src/__tests__/chat.test.ts | 1 + .../__tests__/ideation-tool-route-parity.test.ts | 29 +++++ packages/dashboard/src/chat.ts | 4 + packages/dashboard/src/ideation-routes.ts | 50 ++++++++ .../src/routes/register-integrated-routers.ts | 2 + .../src/__tests__/agent-ideation-tools.test.ts | 40 ++++++ .../src/__tests__/gating-classifications.test.ts | 16 +++ .../src/__tests__/permanent-agent-gating.test.ts | 2 + packages/engine/src/agent-heartbeat.ts | 4 +- packages/engine/src/agent-tools.ts | 67 ++++++++++ packages/engine/src/executor.ts | 2 + packages/engine/src/gating-classifications.ts | 8 ++ packages/engine/src/index.ts | 1 + packages/engine/src/triage.ts | 2 + 33 files changed, 897 insertions(+), 21 deletions(-) Fusion-Task-Id: FN-8295 Fusion-Task-Lineage: 1b8b0752-22bd-4b2f-aebd-4305c63abcf9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
13f936eb7b |
FN-8286: add review artifact controls and galleries
Add configurable review-deliverable policies and surface eligible artifacts in review workflows. - Add project and PROMPT.md review-artifact modes with task eligibility enforcement. - Display video and live-demo deliverables in Task Review and Command Center galleries. - Document, localize, and test the new review-artifact controls. Files changed: .changeset/fn-8286-review-artifacts.md | 7 ++ docs/settings-reference.md | 1 + .../core/src/__tests__/review-artifacts.test.ts | 53 +++++++++++++++ .../core/src/__tests__/settings-parity.test.ts | 5 ++ packages/core/src/index.ts | 4 +- packages/core/src/settings-schema.ts | 1 + packages/core/src/types.ts | 75 ++++++++++++++++++++++ packages/core/src/types/execution-and-ui.ts | 8 +++ .../dashboard/app/components/TaskReviewTab.tsx | 28 +++++++- .../__tests__/SettingsModal.general.test.tsx | 8 +++ .../components/__tests__/TaskReviewTab.test.tsx | 27 ++++++++ .../components/command-center/CommandCenter.tsx | 5 ++ .../command-center/areas/ReviewArtifactsArea.tsx | 59 +++++++++++++++++ .../areas/__tests__/ReviewArtifactsArea.test.tsx | 39 +++++++++++ .../app/components/settings/section-keys.ts | 1 + .../settings/sections/GeneralSection.tsx | 20 ++++++ .../settings-default-descriptions.test.tsx | 1 + .../src/__tests__/agent-artifact-tools.test.ts | 19 +++++- packages/engine/src/agent-tools.ts | 26 ++++++++ packages/i18n/locales/en/app.json | 7 ++ packages/i18n/src/resources.d.ts | 7 ++ 21 files changed, 397 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-8286 Fusion-Task-Lineage: 357ccbe3-510d-4ffd-ba7c-6bf79fe40a09 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
3568a86a66 |
FN-8284: add organization portability controls
Add Command Center tools for safe organization portability and configuration recovery. - Register project-scoped organization export/import and revision rollback routes. - Add localized, responsive Command Center controls for bundle preview, import, and rollback. - Invalidate stale dry-run responses and retain only the exact previewed bundle for import. - Cover portability routes and editing-during-preview behavior with tests. Files changed: docs/dashboard-guide.md | 2 + .../command-center/CommandCenterControls.tsx | 3 + .../command-center/OrgPortabilityControls.css | 81 +++++++++ .../command-center/OrgPortabilityControls.tsx | 184 +++++++++++++++++++++ .../__tests__/CommandCenter.mobile-scroll.test.tsx | 2 + .../__tests__/OrgPortabilityControls.test.tsx | 94 +++++++++++ packages/dashboard/src/routes.ts | 2 + .../register-org-portability-routes.test.ts | 109 ++++++++++++ .../src/routes/register-org-portability-routes.ts | 129 +++++++++++++++ packages/i18n/locales/en/app.json | 37 +++++ 10 files changed, 643 insertions(+) Fusion-Task-Id: FN-8284 Fusion-Task-Lineage: 1fa06550-8064-417f-a8d0-40f693206404 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
38c6fdc60d |
fix: green full-suite after mock and stacking drift (#2287)
## Summary Restacks onto latest main after #2285 and clears the remaining Full Suite red classes from run [29633869887](https://github.com/Runfusion/Fusion/actions/runs/29633869887) (post-#2285): - **Shard 1:** `agent-skills-flow` vitest TDZ — hoist `mockFiles` via `vi.hoisted` (same class as skill-resolver in #2285) - **Shard 2/3:** incomplete mocks after product drift - `isFullScreenSheetViewport` / `isShortViewport` on viewport mocks (without overriding dynamic mobile helpers) - `fetchCodebaseMetrics` on Command Center `api/legacy` mocks - `fetchSettings` on `agent-modals-mobile` api mock - **Shard 3:** PlanningMode `ui-interactions` race — sync-settle `fetchGlobalSettings` (FN-8245 pattern from planning-flow) - **Shard 3:** settings search drift guard — inventory `SettingsFieldRow` `htmlFor` keys (`mobileNavPrimaryItems`) - **Shard 2:** FloatingWindow shared-stack product bug — only reclaim z-index on hidden→visible (not every mount effect), so last-mounted utility stays on top - **Shard 4:** grok process-lifecycle timeout under shard load — prove bound with 5 reimports instead of 15 ## Test plan - [x] `agent-skills-flow.test.ts` green - [x] `process-lifecycle.test.ts` green - [x] FileBrowserModal, FloatingWindowStack.cross-type, agent-modals-mobile, settings-search-index, SystemControlsArea, PlanningModeModal.ui-interactions + planning-flow (210 tests) green - [ ] PR merge gate (Lint/Typecheck/Build/Gate) - [ ] Post-merge Full Suite on `main` green <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved floating-window stacking so reopened or interacted windows appear in the correct order. * Restored consistent layering between floating windows and expanded dock modals. * **Tests** * Updated automated coverage for viewport behavior, codebase metrics, settings search indexing, and process lifecycle scenarios. * Improved test reliability and consistency across responsive layouts and modal interactions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
6206af8ce9 |
FN-8146: restore persistent theme selection
Restore the full Settings theme picker while preserving Shadcn Mono selections across reloads. - Merge the Settings selector into the current-theme row with shared dropdown controls. - Restore Shadcn Mono across theme metadata, token styles, and dashboard/desktop bootstrap validation. - Scope Mono light swatches correctly and cover restored options and persistence with tests. Files changed: .changeset/FN-8146-theme-dropdown-current-row.md | 7 +++ docs/dashboard-guide.md | 5 ++- packages/core/src/types/execution-and-ui.ts | 1 + .../dashboard/app/components/ThemeDropdown.css | 52 ++++++++++++++++++++++ .../dashboard/app/components/ThemeDropdown.tsx | 42 ++++++++++++++--- .../dashboard/app/components/ThemeSelector.css | 42 +---------------- .../dashboard/app/components/ThemeSelector.tsx | 45 +++++-------------- .../components/__tests__/ThemeDropdown.test.tsx | 46 ++++++++++++++++--- .../components/__tests__/ThemeSelector.test.tsx | 29 ++++++++---- .../__tests__/CommandCenterControls.test.tsx | 15 ++++++- packages/dashboard/app/components/themeOptions.ts | 2 + .../dashboard/app/hooks/__tests__/useTheme.test.ts | 8 ++-- packages/dashboard/app/hooks/useTheme.ts | 8 ++-- packages/dashboard/app/index.html | 5 +-- packages/dashboard/app/public/theme-data.css | 16 ++++++- packages/desktop/src/renderer/index.html | 1 + 16 files changed, 213 insertions(+), 111 deletions(-) Fusion-Task-Id: FN-8146 Fusion-Task-Lineage: 32ec7f21-ee6b-4459-8e7b-f5a5435c4994 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
4df5c62854 |
FN-8133: add local codebase context metrics
Expose local codebase token estimates and apparent disk size in the project dashboard. - Add a bounded, cached, symlink-safe codebase metrics service and project API. - Display token and disk indicators across Command Center overview states. - Add formatting, route, UI, and metric calibration coverage with a minor changeset. Files changed: .changeset/fn-8133-codebase-metrics.md | 7 + docs/dashboard-guide.md | 2 +- .../dashboard/app/__tests__/api-projects.test.ts | 12 ++ packages/dashboard/app/api/legacy.ts | 14 ++ .../components/command-center/CommandCenter.css | 5 + .../components/command-center/CommandCenter.tsx | 65 +++++++-- .../CommandCenter.mobile-chart-layout.test.ts | 4 + .../__tests__/CommandCenter.test.tsx | 10 ++ .../__tests__/SystemStatsArea.test.tsx | 8 + .../command-center/areas/SystemStatsArea.tsx | 8 +- .../app/utils/__tests__/formatBytes.test.ts | 18 +++ packages/dashboard/app/utils/formatBytes.ts | 11 ++ .../src/lib/__tests__/codebase-metrics.test.ts | 62 ++++++++ .../lib/__tests__/fixtures/token-corpus/README.md | 17 +++ .../fixtures/token-corpus/calibration/component.ts | 1 + .../fixtures/token-corpus/calibration/config.json | 1 + .../lib/__tests__/fixtures/token-corpus/example.ts | 1 + .../lib/__tests__/fixtures/token-corpus/notes.md | 3 + .../fixtures/token-corpus/reference-counts.json | 9 ++ .../__tests__/fixtures/token-corpus/settings.json | 1 + .../lib/__tests__/fixtures/token-corpus/view.tsx | 1 + packages/dashboard/src/lib/codebase-metrics.ts | 161 +++++++++++++++++++++ .../__tests__/codebase-metrics-route.test.ts | 34 +++++ .../src/routes/register-project-routes.ts | 19 +++ 24 files changed, 456 insertions(+), 18 deletions(-) Fusion-Task-Id: FN-8133 Fusion-Task-Lineage: d591636b-d4b8-469e-8788-c4516eeb8405 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
47f9aa7144 |
FN-8124: reuse dashboard theme dropdown in Settings
Unify Settings appearance theme selection with the dashboard control. - Reuse ThemeDropdown and its custom-color picker in ThemeSelector - Remove the obsolete Settings color-theme grid styles - Cover shared dropdown interactions and document the unified control - Add a patch changeset for the Settings theme selector Files changed: .changeset/FN-8124-settings-theme-dropdown.md | 7 + docs/dashboard-guide.md | 2 +- .../dashboard/app/components/ThemeDropdown.tsx | 9 +- .../dashboard/app/components/ThemeSelector.css | 48 -- .../dashboard/app/components/ThemeSelector.tsx | 49 +- .../components/__tests__/ThemeSelector.test.tsx | 778 ++------------------- .../__tests__/CommandCenterControls.test.tsx | 18 +- 7 files changed, 109 insertions(+), 802 deletions(-) Fusion-Task-Id: FN-8124 Fusion-Task-Lineage: 6bd87f2a-d9e1-4374-8f54-1a2266c4004f Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
66ae82af5b |
FN-8007: align concurrency current-use markers
Align dashboard and footer concurrency markers with their native range thumbs. - Map running counts in min-relative slider coordinates and clamp them to the configured cap - Standardize native slider thumb dimensions and marker geometry across browsers - Add dashboard coverage and document the marker behavior Files changed: .changeset/fn-8007-concurrency-dot-alignment.md | 7 + docs/dashboard-guide.md | 8 +- .../dashboard/app/components/EngineControlMenu.css | 20 ++- .../dashboard/app/components/EngineControlMenu.tsx | 19 ++- .../__tests__/EngineControlMenu.test.tsx | 96 +++++------- .../command-center/CommandCenterControls.css | 22 ++- .../command-center/CommandCenterControls.tsx | 19 ++- .../__tests__/CommandCenterControls.test.tsx | 164 +++++++++++++++++++++ 8 files changed, 277 insertions(+), 78 deletions(-) Fusion-Task-Id: FN-8007 Fusion-Task-Lineage: 9ad8ee0b-09da-413e-96bc-530c897cb32e Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
2179a61db9 |
FN-7973: fix mobile concurrency sliders with touch-action none
Restore horizontal concurrency thumb drags on mobile by opting range inputs out of the pan-y ancestor lock. - Set touch-action:none on Engine Control menu and Command Center concurrency range inputs - Update geometry/touch contract test to assert none and reject pan-y - Add patch changeset for the mobile slider fix Files changed: .changeset/fn-7973-mobile-concurrency-sliders.md | 7 +++++++ packages/dashboard/app/components/EngineControlMenu.css | 5 ++++- .../app/components/__tests__/EngineControlMenu.test.tsx | 11 ++++++++--- .../app/components/command-center/CommandCenterControls.css | 5 ++++- 4 files changed, 23 insertions(+), 5 deletions(-) Fusion-Task-Id: FN-7973 Fusion-Task-Lineage: bf36e544-c24f-49ae-beae-b11707be9c79 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
4d78f9641b |
feat(dashboard): build/link local fn and npm restore from System panel
Add Command Center System controls for source/dev hosts to build the standalone fn binary and install it as the default PATH binary, switch back to the global npm install, and force-check for published updates. Build jobs stream into the shared job log and scroll that view into focus. |