aedee4b8231bf050c3240a00ab6645ede5d87ee9
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
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> |