Surfaced by #3002, which widened check-inert-flag-seams to scan plugins/.
What
plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx:72 calls:
const isStuck = isTaskStuck(task, taskStuckTimeoutMs, lastFetchTimeMs);
Six of the seven other isTaskStuck call sites in the tree pass resolved column flags as the fourth argument. This one can't: the plugin has no lane-trait source anywhere.
DependencyGraph receives tasks: Task[] and nothing else;
- the view is mounted through
PluginDashboardViewContext, which carries no per-task traits;
TaskCardBridgeProps doesn't include them either.
So on a board with renamed lanes, stuck detection in the dependency-graph view falls back to the legacy ids and answers for a vocabulary the operator isn't using. Same class as the fan-out and ticker defects (#2993, #2996, #2997, #3001), one boundary out.
Why it wasn't just fixed in #3002
Passing the argument from what's currently in scope would pass undefined — an unsupplied optional parameter. That's the first failure shape in docs/solutions/workflow-learnings/lifecycle-conversions-that-score-as-wins.md: strictly worse than the literal it replaces, because it reads as converted, satisfies every instrument, and answers legacy forever. It's recorded as a bounded exemption in the gate with that reasoning rather than bodged.
What the fix needs
A decision from whoever owns the plugin view contract, because it changes a published surface:
- extend
PluginDashboardViewContext (or TaskCardBridgeProps) with a per-task flags accessor — the host already builds one for the footer, footerColumnFlagsByTaskId in App.tsx:552;
- thread it through
registerBundledPluginViews → DependencyGraph → GraphTaskNode;
- drop the exemption in
scripts/check-inert-flag-seams.mjs — it's count-bounded, so it fails the moment the site is fixed and left behind.
Per-task, not a board-wide union. blocker-fanout.ts documents why: a column id means something only relative to its own workflow, and a union serves one workflow's traits to another's card.
Scope check
The dependency-graph plugin is the only current instance — the glasses plugin references lane flags in src/cards.ts and src/routes/board-routes.ts but resolves them server-side, so it isn't affected. This is one site today and a contract gap that any future card-rendering plugin inherits.
Surfaced by #3002, which widened
check-inert-flag-seamsto scanplugins/.What
plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx:72calls:Six of the seven other
isTaskStuckcall sites in the tree pass resolved column flags as the fourth argument. This one can't: the plugin has no lane-trait source anywhere.DependencyGraphreceivestasks: Task[]and nothing else;PluginDashboardViewContext, which carries no per-task traits;TaskCardBridgePropsdoesn't include them either.So on a board with renamed lanes, stuck detection in the dependency-graph view falls back to the legacy ids and answers for a vocabulary the operator isn't using. Same class as the fan-out and ticker defects (#2993, #2996, #2997, #3001), one boundary out.
Why it wasn't just fixed in #3002
Passing the argument from what's currently in scope would pass
undefined— an unsupplied optional parameter. That's the first failure shape indocs/solutions/workflow-learnings/lifecycle-conversions-that-score-as-wins.md: strictly worse than the literal it replaces, because it reads as converted, satisfies every instrument, and answers legacy forever. It's recorded as a bounded exemption in the gate with that reasoning rather than bodged.What the fix needs
A decision from whoever owns the plugin view contract, because it changes a published surface:
PluginDashboardViewContext(orTaskCardBridgeProps) with a per-task flags accessor — the host already builds one for the footer,footerColumnFlagsByTaskIdinApp.tsx:552;registerBundledPluginViews→DependencyGraph→GraphTaskNode;scripts/check-inert-flag-seams.mjs— it's count-bounded, so it fails the moment the site is fixed and left behind.Per-task, not a board-wide union.
blocker-fanout.tsdocuments why: a column id means something only relative to its own workflow, and a union serves one workflow's traits to another's card.Scope check
The dependency-graph plugin is the only current instance — the glasses plugin references lane flags in
src/cards.tsandsrc/routes/board-routes.tsbut resolves them server-side, so it isn't affected. This is one site today and a contract gap that any future card-rendering plugin inherits.