Commit Graph

19 Commits

Author SHA1 Message Date
gsxdsm
ccf562f178 gate: compare mirrored INTERFACES too, and delete the dead prop that found (#3034)
> **Re-landing the second half of #3031.** That PR merged into #3029's
branch and only its first commit reached `main` — the arity rule
shipped, the interface rule and its finding did not. Verified on `main`:
the gate reports *"7 mirrored function(s)"* with no interface count, and
the dead prop below is still there.

## What

The arity rule covers exported functions. The same files also mirror
**interfaces**, which is the larger surface — six copies of
`PluginDashboardViewContext` alone.

**One direction only.** A mirror may declare *fewer* properties, and all
six do (6, 8, 7, 7, 3, 6 against the real nine) because a plugin mirrors
the fields it uses. Demanding equality would fail every plugin for not
using everything — which is how a check gets ignored and then deleted. A
property the real type **doesn't have** is the drift that matters: a
rename nobody propagated, where the plugin keeps compiling and reads a
field the host never sends.

## Its first interface run found a live one

```
dashboard-interop.d.ts:67  TaskCardProps.workflowStepNameLookup is not a property of the real TaskCardProps
```

Git history says it **was** one when FN-2466 and FN-7039 added this
threading. The dashboard removed it later; nothing propagated that to
the plugin's hand-written declaration. So the plugin built a lookup map
from `context.workflowSteps` on every render, threaded it through two
components, and handed it to a `TaskCard` with no such prop.

Deleted rather than exempted — a new gate shouldn't ship with a waiver
for its own first finding. Behaviour-preserving: the value never reached
anything.

## Measured on `main`

| check | result |
|---|---|
| population | **7 functions + 10 interfaces across 6 plugins**, all
matching after the deletion |
| control probe | phantom property **caught**; clean tree exits 0 |
| anti-vacuity | now also requires a non-zero *interface* comparison |
| gate's own suite | **5 → 8** |
| dependency-graph suite | 179 green; `tsc` clean |
| other five gates · census | green |

## Running total for this check

Three real drifts, none of which any other instrument reported:

1. `isTaskStuck` stuck at three parameters through the whole lane
conversion (#3003)
2. `taskStuckTimeoutMs?: number` vs the required `number | undefined` —
in **two independent authors'** declarations
3. `workflowStepNameLookup` outliving its removal from `TaskCard`

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 01:43:58 -07:00
gsxdsm
a460a9bbc0 fix(plugins,dashboard): the dependency graph drew every card with the LEGACY lane vocabulary (#3029)
## The third producer of unflagged cards — the one a host-side fix could
not reach

#3025 fixed the two producers that go through `renderTaskCard`.
`GraphTaskNode` is a third: it imports `TaskCard` **directly** through
the plugin's interop shim, so that fix bypassed it and every role helper
inside a graph card kept reading the legacy ids.

The same component also called the stuck predicate without its flags:

```ts
const isStuck = isTaskStuck(task, taskStuckTimeoutMs, lastFetchTimeMs);   // no columnFlags
```

so `isWipColumnRole` fell back to the literal and **no card in the graph
could ever be stuck on a renamed board**. Because `isStuck` gates
`isActive`, a wedged card rendered with the **active** styling — the
graph reported *"running"* about a task that had not moved in hours,
while the main board showed the same card as stuck.

That asymmetry between two views of one task is the defect, and it is
what the new test pins.

## One cause, so one fix

Both symptoms came from the same gap: `PluginDashboardViewContext`
exposed `tasks` and nothing about the board's vocabulary. It now carries
`columnFlagsByTaskId` — the same per-task map `renderTaskCard` already
uses, **two lines away in the same object literal**.

## I filed this twice as blocked on a public-API change. It was not.

```
packages/dashboard                        @fusion/dashboard                        private: true
packages/plugin-sdk                       @fusion/plugin-sdk                       private: true
plugins/fusion-plugin-dependency-graph    @fusion-plugin-examples/dependency-graph private: true
```

No published surface anywhere in the path — three in-repo private
packages and a hand-written `.d.ts`. **#3026 landed the general form of
that mistake while I was still making it**: a deferral's stated blocker
is a claim, and mine decayed unchecked until I finally measured it.

## Two type decisions worth reviewing

- **`Partial<TraitFlags>`** in the plugin-facing type, not the
dashboard's `ExecutorColumnFlags` — that module's own header restricts
it to `@fusion/core` and `react` imports so external plugin builds can
consume it. Same runtime object either way.
- **`MainContentProps.columnFlagsByTaskId` widened** from `{complete,
archived, intake, hold}` to the flags the map really carries. It is
built from `workflow.columns.find(...).flags`, so the four-flag
declaration was a narrower view than the value — and `countsTowardWip`,
which every wip predicate needs, was invisible through it. That narrow
type is why threading this looked impossible at first.

Absent still means legacy, matching how the host treats remote rows and
off-board columns: the degraded answer is the documented literal, never
*"this board has no wip lane"*.

## Revert proof

Dropping the 4th argument:

```
AssertionError: expected 'graph-task-node graph-task-node--acti…' not to contain 'graph-task-node--active'
      Tests  1 failed | 26 passed (27)
```

The paired case (a fresh legacy `in-progress` card still reads active)
passes both ways by design — it guards against over-detection, so I am
not counting it as coverage.

The gate agrees independently:
`plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx: 1 -> 0`,
baseline re-recorded 16 → 15 in the same commit.

## Verification (measured)

- plugin suite — **185 passed / 20 files**
- dashboard `dashboard/` + `plugins/` suites — **48 passed / 6 files**
- `tsc --noEmit` clean in both packages; `pnpm lint` clean
- `lifecycle-column-census --strict`, `check-lane-wiring` (15, none
added), `check-sql-column-literals`, `check-inert-flag-seams`,
`check-fnxc-future-dates` — green

No changeset: all three packages are `private: true`.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 01:30:47 -07:00
gsxdsm
a1cac3a6a3 fix(dashboard): replace quick chat with modal chat 2026-06-22 15:23:43 -07:00
gsxdsm
44257dd8ea fix(dependency-graph): graph centers on first paint without a manual drag
Root cause: fitToGraph's clampPan clamped against graphBoundsRef, which a separate effect populated from NORMALIZED bounds — on first paint the ref was still {0,0,0,0}, so pan clamped to +/-viewport (off-center) and only a manual drag re-ran clampPan against the committed bounds. Fit now runs on normalizedPositions (fit-space == render-space == clamp-space), after the setGraphBounds effect, deferred a double-rAF so the committed bounds are live before clampPan; ResizeObserver still drives the hidden->visible 0->N fit. Manual-layout opt-out preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:01:23 -07:00
gsxdsm
4626f8e7fe feat(dashboard): list-view count/border cleanup, overview buttons match Stop AI Engine, center graph on load
- List view: remove the 'X of Y tasks' count from the desktop sidebar toolbar and the border between the controls row and the quick-add box (mobile count kept). Count-display tests now verify the filter via rendered rows.
- Command Center Overview: View Board / View Agents are btn btn-secondary (taller, centered) matching the Stop AI Engine button.
- Dependency graph: fit/center on load — the initial fit ran before the viewport was measured + before nodes were positioned (async), and never re-fit. Now fits only when fittable (nodes + measured viewport) and re-fits when the node set changes (covers async load + re-entering the view).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:59:26 -07:00
Fusion
7b35a5b426 feat(FN-4549): complete Step 4 — align edges and bounds to measured heights
Fusion-Task-Id: FN-4549
Fusion-Task-Lineage: 7c6b974d-cad9-418c-bf02-9d8490725c6e
2026-05-14 22:16:43 -07:00
Fusion
d3dd9bd38c feat(FN-4549): complete Step 3 — measure task node heights for auto layout
Fusion-Task-Id: FN-4549
Fusion-Task-Lineage: 7c6b974d-cad9-418c-bf02-9d8490725c6e
2026-05-14 22:16:43 -07:00
Fusion
e3e208d87a feat(FN-4539): complete Step 3 — add responsive orientation wiring
Fusion-Task-Id: FN-4539
Fusion-Task-Lineage: 90c37e7c-0691-4f15-80d6-e95bc6502e76
2026-05-14 16:12:18 -07:00
Fusion
db60a65884 feat(FN-4129): add wheel pan and modifier-key zoom to dependency graph
Adds wheel-based panning to the dependency graph plugin, separating pan behavior from zoom when the wheel event is horizontal or un修饰, with new tests covering both interactions and updated graph interaction documentation in the plugin README.

Fusion-Task-Id: FN-4129
2026-05-12 17:04:32 -07:00
Fusion
59597ee426 feat(FN-4036): fix zoom-aware graph pan bounds
Fixed zoom-aware graph pan bounds in the dependency graph plugin, correcting edge-case behavior when the graph is zoomed or panned. Added regression tests for graph interactions and updated documentation to cover the corrected behavior.

Fusion-Task-Id: FN-4036
2026-05-11 15:38:34 -07:00
Fusion
2d167f1025 feat(FN-3912): fix dependency graph focus and apply tokenized styling feedb
Bug fix addressing dependency graph focus behavior and CSS tokenization feedback, alongside test coverage for CLI bundle output and bundled plugin installation paths. The styling changes affect `DependencyGraph` and `GraphTaskNode` components, while tests validate the published CLI artifact.

Fusion-Task-Id: FN-3912
2026-05-10 15:33:25 -07:00
Fusion
83fb0e722f feat(FN-3941): separate graph pan from selection-gated drag
Separates graph panning from selection-gated drag by updating `useNodeDrag` and `useGraphInteraction` hooks to handle the two interaction modes independently, with `GraphTaskNode` now gating drag on selection state. Tests were added across the graph interaction, node drag, persistence, and integrati

Fusion-Task-Id: FN-3941
2026-05-10 15:33:25 -07:00
gsxdsm
958af16ded fix(FN-3888): resolve dependency-graph plugin from src in dashboard build
The dashboard dynamically imports `@fusion-plugin-examples/dependency-graph/dashboard-view`, which resolved through the plugin's package.json exports to `dist/`. When plugin source was edited without rebuilding, stale `dist/` (extensionless ESM imports) made the import throw and the UI surfaced "Bundled plugin view unavailable". Add vite/vitest aliases mapping the plugin (and its `/dashboard-view` subpath) to `src/` so the dashboard never depends on `dist/`. Mirrors the existing pattern for hermes/openclaw/paperclip runtimes. Also extends the runtime-plugin alias regression test, and emits `.js` extensions from the plugin source for the CLI-bundled path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 16:44:44 -07:00
Fusion
70007a1d24 feat(FN-3090): add graph position persistence to dependency graph plugin
Merges graph position persistence into the dependency graph plugin (FN-3090) via a scoped storage layer, a dedicated position storage utility, and a React hook that preserves pan/zoom state across sessions. Also includes a responsive CSS fix for ScriptsModal and supporting test coverage in both the

Fusion-Task-Id: FN-3090
2026-05-07 06:03:58 -07:00
Fusion
70105b2481 feat(FN-3089): add draggable dependency graph nodes
Adds draggable interaction to dependency graph nodes (FN-3089), introducing a `useNodeDrag` hook to manage drag state and positioning, with corresponding tests and a new drag stylesheet; the `GraphTaskNode` and `DependencyGraph` components are updated to wire up the drag behavior.

Fusion-Task-Id: FN-3089
2026-05-07 05:28:27 -07:00
Fusion
6f63ee3fcd feat(FN-3088): add dependency graph highlighting with hover and selection s
The merge adds visual highlighting to the dependency graph plugin. A new `useDependencyChain` hook tracks dependency relationships, while `GraphTaskNode` and `DependencyGraph` gained hover, selection, and highlight visual states backed by new CSS. Tests cover the hook logic, highlighting behavior, a

Fusion-Task-Id: FN-3088
2026-05-07 04:48:19 -07:00
Fusion
f859108779 feat(FN-3086): enhance graph navigation with toolbar and keyboard controls
The merge introduces a new Cursor CLI plugin provider with dashboard authentication (FN-3396), enabling Fusion to bundle Cursor's CLI as a native AI model source alongside native shell guide and bridge contract documentation (FN-3577). It also completes the dependency graph plugin's navigation contr

Fusion-Task-Id: FN-3086
2026-05-07 04:28:37 -07:00
Fusion
caf4062b76 feat(FN-3083): add GraphTaskNode wrapper and integrate into dependency grap
The merge introduces a new `GraphTaskNode` wrapper component for the dependency graph plugin (FN-3083) with visual parity tests, adds an AI security scan gate to the plugin install/unpack flows (FN-3077), updates the dashboard PluginManager UI and adds plugin API routes, and cleans up remaining main

Fusion-Task-Id: FN-3083
2026-05-07 02:37:14 -07:00
Fusion
12326eeb00 feat(FN-3082): restructure dependency graph plugin with modular architectur
Implements a modular dependency graph feature for the Fusion dashboard plugin, replacing the monolithic `DependencyGraphView` component with a factored architecture: graph types and filtering (Step 1), a data hook (Step 2), auto-layout engine (Step 3), SVG edge rendering (Step 4), an interaction hoo

Fusion-Task-Id: FN-3082
2026-05-07 01:42:01 -07:00