## Summary
Gives dashboard integrators (plugin views, embedded panels, theming
tools) a supported way to match the dashboard's look and to layer
overlay UI correctly — instead of scraping computed styles and guessing
z-index values. This implements the CSS-token bridge slice of
`docs/proposals/2026-07-01-dashboard-theme-plugin-system.md`.
Two additions, both inert unless used:
1. **Documented theme-token contract.** A "Theme tokens" section in
`docs/dashboard-guide.md` (referenced from `docs/PLUGIN_AUTHORING.md`)
declares the stable set of CSS custom properties — colors, surfaces,
status colors — that integrators may read. Tokens resolve to raw color
strings (e.g. `#161b22`) in every theme, including the newer ones. A
sync test (`theme-token-contract-docs.test.ts`) parses the doc's token
table and asserts each documented token has a real definition in the
dashboard CSS, so the contract cannot silently drift from the code.
2. **Overlay layering surface.** Overlay-style UI (palettes, pickers,
floating panels) currently has no supported way to sit above the
floating-window stack — the effective max z-index is runtime state
inside `floatingWindowStack.ts`. This PR exposes it:
- `--fusion-max-z` on `:root` — kept in sync by `floatingWindowStack`
(written at module load and after every `nextFloatingZ()` claim), so it
always reflects the true top of the dashboard-managed stack. Boot/floor
value is `11001`, chosen to clear the highest statically-declared layer
(the body-portaled model-combobox dropdown at `z-index: 11000`).
- `#plugin-overlay-root` — an empty, `pointer-events: none` sibling of
`#root` stacked at `calc(var(--fusion-max-z) + 1)`. React never renders
into it, so it is hydration-safe; integrators portal into it and
re-enable pointer events on their own elements.
- The layer bands (base UI / floating windows / toasts / dropdown /
overlay root) are documented in `styles.css` and the guide, and a guard
test (`dashboard-max-z-guard.test.ts`) scans the structural + component
CSS and fails if any static `z-index` is ever introduced above the floor
— keeping the contract honest as the codebase evolves.
## Behavior
No visual or behavioral change for existing users: `floatingWindowStack`
still returns the same values from `nextFloatingZ()`; the overlay root
is empty and click-through; tokens were already defined — this only
documents and guards them.
## Tests
- `theme-token-contract-docs.test.ts` — docs ↔ CSS sync
(non-tautological: anchored matching against real definitions).
- `floatingWindowStack.max-z.test.ts` — `--fusion-max-z` boot value and
live tracking as the stack claims z-indexes.
- `dashboard-max-z-guard.test.ts` — no static dashboard z-index above
the floor (decorative `public/theme-data.css` INT_MAX scanline overlay
deliberately excluded; it's non-interactive grain, documented in the
test).
- Changeset included (`minor`, `category: feature`). Typecheck clean.
## Open question for maintainers
The token is named `--fusion-max-z`. The existing scale uses `--z-*`
names (`--z-dropdown`, `--z-modal`) on a lower band — happy to rename to
`--z-max` / `--z-plugin-overlay` or anything that fits your convention;
the name is the only bikeshed here, the sync mechanism is independent of
it.
## AI assistance disclosure
Parts of this change were authored with AI assistance (Anthropic's
Claude); the commit carries a `Co-authored-by` trailer accordingly.
Everything was human-reviewed before submission, and the test suite and
typecheck were run locally against the current `main`.
If squash-merging with a rewritten message, please keep the attribution:
```
Co-authored-by: Claude <noreply@anthropic.com>
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added stable dashboard theme tokens for consistent plugin/integration
styling.
- Introduced a dedicated plugin overlay mount point with click-through
defaults and an overlay stacking ceiling.
- Overlay z-index now stays in sync with floating window layering
automatically.
- **Documentation**
- Added an explicit stable “theme token contract” and “overlay layering
contract,” including interaction and z-index usage rules and deprecation
expectations.
- **Bug Fixes**
- Improved reliability of plugin overlay stacking so overlay content
renders above intended dashboard layers.
- **Tests**
- Added guards validating CSS z-index ceilings and enforcing the
documented theme token contract.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude <noreply@anthropic.com>
The jump-to-latest button is centered via transform: translateX(-50%), and
the global .btn:active scale transform replaced it wholesale on mousedown,
shifting the button out from under the cursor mid-click. Compose both
transforms on :active (same fix as the DevServer new-logs button).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plugin-defined HTTP routes were a boot-time snapshot of the launch
project's PluginLoader, while dashboard views/UI slots resolve a
project-scoped loader live per request. Two failure modes survived the
961edf214 no-engine mount fix: a plugin enabled after boot rendered its
view while every API route 404'd until restart, and a plugin enabled
only in a non-launch project never got routes mounted at all (Compound
Engineering "Failed to load sessions: Not found" on v0.73.0-beta.3).
Routes are now dispatched per request through the same
getProjectPluginLoader cache (moved from the plugins registrar into
routes/context.ts) that serves dashboard-views and enable/disable, with
the host loader + PluginRunner tables unioned in (project entries win,
loader beats runner). The compiled dispatch sub-router is cached per
resolved loader and rebuilt only when the route signature changes, so
views and routes agree by construction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Code-review findings on 085f7b99c: a bare date like 2026-07-22 qualified
as a distinctive slug, so unrelated failure reports quoting the same date
silently converged (and the date outranked a real file-path anchor in the
sorted-first pick); reject slugs whose segments are all hex/numeric.
Also render non-http(s) sourceMetadata.issueUrl values as plain text to
block javascript:-scheme links from API-supplied metadata.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Widen computeCrossParentDiagnosticClaim so repair tasks phrased as
'exceeds limit / oversized / blocking X / so X passes' converge on a
file-path or distinctive-slug anchor at creation time (FN-8510/8511/
8513/8514 incident: four executors on unrelated parents filed the same
oversized-changeset follow-up and none deduped before triage).
Add a Provenance section to the Task Detail Stats tab showing source
type, parent task, creating agent, imported-issue link, and the triage
near-duplicate marker.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The KTD-8 adoption sweep runs on every store open, and a DB with active tasks
never records the drained marker, so it re-runs constantly. Its resume-graph
mapping for 'planning' cleared FN-8504's freshly written live planner status
~100ms after triage claimed it (audit: task:reconcile-legacy-adoption,
priorStatus 'planning'), leaving a live replan planner rendered as an idle
READY card and invisible to every Running count.
Generalize the FN-8498 needs-replan fix: any status with a live post-cutover
writer is preserved — planning (triage's stale-planning sweep owns crash
recovery), queued (scheduler re-evaluates each poll), merging/merging-pr/
merging-fix (self-healing stale-merge recovery), stuck-killed (restart-
recovery coordinator). Only writer-less statuses (plan-review-unavailable,
triaged) keep resume-graph.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Todo card parked in the durable needs-replan stage keeps its REVISING badge
and activity chrome (FN-8494), but the header only counted live agents, so it
read 0/2 under a glowing card. Union the shared Running predicate with the
card's own activity predicate (same globalPaused/stuck gates) so the header
equals the number of visibly active cards. Footer Running and admission keep
live-agent-only truth: a parked replan must not consume concurrency capacity.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Align the mobile task-detail Move action with the footer edge.
- Let the footer spacer absorb surplus mobile width instead of the Move dropdown.
- Cover canonical footer order and triage actions-absent behavior.
- Add a patch changeset for the mobile footer fix.
Files changed:
.changeset/fn-8501-mobile-footer-alignment.md | 7 ++++
.../dashboard/app/components/TaskDetailModal.css | 8 ++++-
...etailModal.responsive-and-dependencies.test.tsx | 40 ++++++++++++++++++++++
3 files changed, 54 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-8501
Fusion-Task-Lineage: a87bb5af-d16e-4ca8-9111-3168c8440f14
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Two mobile board gesture fixes: (1) finger travel only counts as horizontal
pan intent when it dominates the vertical axis, so scrolling a column's card
list with incidental diagonal drift no longer swipes to another column; (2)
the commit-one-column paging clamp applies only to gestures begun at rest
centered on a column — a tap-to-stop mid-momentum followed by a drag settles
on the nearest column at the drag's landing point instead of being forced a
column past it by the interrupted scroll's origin.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An In Review column with one MERGING task and one live CODE REVIEW task showed
1/2 processing: gate sessions run with task.status left null, so the shared
isRunningAgentTask predicate only saw the merge-pipeline statuses. Count a
pending workflow-step-result lease (the durable live-gate signal; FN-8492
fails orphaned ones) as Running on any unpaused, non-terminal row. Covers
plan review, code review, browser verification, post-merge verification, and
custom optional steps across column headers, footer stats, admission, and CLI.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The directional settle always paged one past the nearest column once the
viewport center crossed its center, so a fling that decelerated with a column
mostly on screen was pushed a full extra column. Settle now lands on the
nearest column, clamped to at least one column of progress from the gesture's
origin column — short swipes still commit forward and the settle never moves
against travel.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
iOS/Android fire pointercancel when the native pan claims a touch while the
touch stream keeps flowing. Treating it as gesture end either orphaned the
gesture (drag released mid-screen rested between columns until the next tap)
or armed the idle settle with the finger still down (slow scrolls at the edge
columns glitched and snapped back). Track the live touch sequence and ignore
pointercancel while it is active; touchend stays the real finger lift.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Code-review follow-up on 4413699de. Deleting an orphaned pending review
entry was a severity inversion: the merge gate blocks on pending/failed
results, not on an enabled step with NO result, so deletion silently
satisfied the gate and the task merged with its review skipped (verified
live: FN-8492 landed on main without Code Review re-running). Orphans are
now rewritten to status:"failed" — the gate stays closed and the
failed-pre-merge-steps recovery / FN-7720 operator-bypass paths own the
re-run decision.
Also from review: the sweep now runs in periodic maintenance too (a step
session can die without a restart), skips executor-owned in-progress rows
(resume is deferred ~30s at startup, so their liveness is unprovable when
startup recovery runs), re-reads the row immediately before the write so
the whole-array update cannot clobber a fresh lease, counts recovery on
the successful mutation rather than after the audit emit, and the new
audit event literal is registered in DatabaseMutationType (cast dropped).
Tests now cover all three liveness-triple legs, >500-row pagination,
in-progress skip, per-task write-failure isolation, and the never-delete
invariant; the needs-replan adoption row moved under a preserve-group
header.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An engine restart that kills an in-flight pre-merge step session (FN-8492's
Code Review) left its pending workflowStepResult behind with no live session.
The merge gate read it as incomplete pre-merge steps, surfaced an identical
stall every 30 minutes, and the deadlock disposer parked the task failed two
hours later. resolveOrphanedPendingStepResults existed for exactly this but
shipped with no caller (same U9 gap as the adoption table).
Wire it: a startup sweep right after legacy adoption clears pending results
whose task has no live session (activeSessionRegistry / executingTaskLock /
isTaskActive), emitting task:reconcile-orphaned-pending-step-results with
ids/counts-only metadata. User pauses and live resumed sessions are never
disturbed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The KTD-8 startup adoption sweep mapped needs-replan to resume-graph, clearing
it on every engine restart. But needs-replan is not un-migrated legacy: post-U3
it is written live by the graph's plan-replan seam and is the exact status
triage's todo-rediscovery keys on to re-admit a planned todo task. Clearing it
stranded replan-loop tasks in todo forever (FN-8498 sat "ready" for 80 minutes
after a restart). Map it to preserve — the status is self-resuming as-is.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
After tap-to-stop or zero-pan lifts, hard-jump to the nearest column so the board never rests between lanes, while directional paging still applies only when the settle gesture itself panned.
Re-touch while the board is coasting now cancels the pending directional settle and re-baselines the gesture at the current scrollLeft, so a stop-tap no longer hard-jumps using the original swipe.
Refresh the weekly test velocity publication with the latest measurements.
- Record updated gate, boot smoke, and changed-only test timings.
- Append the W29 velocity history entry and update the published summary.
- Point testing guidance to the canonical weekly velocity workflow.
Files changed:
docs/test-velocity-baseline.md | 16 +++---
docs/testing.md | 10 +---
scripts/test-velocity-history.json | 115 +++++++++++++++++++++++++++++++++++++
3 files changed, 124 insertions(+), 17 deletions(-)
Fusion-Task-Id: FN-8495
Fusion-Task-Lineage: db432471-13a2-41b1-a951-f735c96456e9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Instead of dropping a fallback-only grok-cli pair when no GROK_API_KEY is
Fusion-visible, defer it: the session runs the configured primary, and on
the first retryable model-selection failure it creates a session on the
Grok CLI runtime with the fallback model and re-issues the failed prompt
there; later prompts stay on the swapped session. Engagement reports
through onFallbackModelUsed and an ids-only
session:grok-cli-fallback-engaged run-audit event. The pair is dropped
(with audit flag) only when the Grok runtime plugin is unavailable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A configured grok-cli fallback with no Fusion-visible GROK_API_KEY was
promoted to primary at session start (FN-7758 seam), so every planning
session silently ran grok-4.5 instead of the configured planning model.
The no-visible-key Grok CLI auto-route now fires only for a grok-cli
primary; a fallback-only grok-cli pair is dropped with a warning and an
audited grokCliFallbackDropped flag, and session:runtime-resolved now
records the post-transform model pair the session actually runs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Summary
- add an atomic PostgreSQL operation that reconciles a mission feature
with a terminal delivery task
- support retained archived-task evidence without unarchiving or waking
mission automation
- reject missing, active, deleted-without-archive, and duplicate-linked
task evidence without partial mutation
- route the reconciliation endpoint through the transactional store
operation
## Root cause
Mission reconciliation previously relied on ordinary task-link and
lifecycle paths that cannot safely use retained archived task evidence.
That made historical delivery repair either impossible or vulnerable to
partial linkage and unintended mission-loop side effects.
## Scope
This PR contains the reusable product capability recovered from FX-001.
It intentionally does not perform the project-specific 69-row live data
mutation; that operational reconciliation was blocked by ambiguous
evidence and belongs outside the source change.
## Validation
- PostgreSQL mission-store tests: 23 passed
- dashboard reconciliation route tests: 3 passed
- `@fusion/core` typecheck
- `@fusion/dashboard` typecheck
- targeted ESLint
- strict changeset validation
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added safer reconciliation for completed mission features using
validated terminal task evidence.
* Supports eligible archived tasks without restoring or relinking them.
* Reconciliation is idempotent and updates related mission progress
consistently.
* **Bug Fixes**
* Prevented conflicting or invalid task evidence from changing mission
state.
* Added atomic rollback when reconciliation encounters an error.
* Improved API responses for missing resources and reconciliation
conflicts.
* **Documentation**
* Expanded reconciliation safety, error, idempotency, and
duplicate-cleanup guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: fusion-merge-train <merge-train@topkoli.local>
Co-authored-by: Fusion <noreply@runfusion.ai>