Files
fusion/packages/engine
gsxdsm 8c79da364c fix(engine): FN-8356's duplicate-marker cleanup was inert on a renamed board (5 call sites) (#2827)
Fourth unowned finding picked up after both batch PRs (#2783 core, #2785
engine) merged without addressing their reports. Completes the
`isNearDuplicateCanonicalInactive` seam alongside #2823, which fixed the
sixth (core) site.

## The defect

All five engine call sites — `self-healing.ts` ×2, `triage.ts` ×3 —
called the predicate without the canonical's resolved column flags, so
it fell back to the legacy `done`/`archived` ids. A canonical resting in
a renamed complete column (`shipped`) read as **still active**, so every
*"the canonical is inactive, so clear the marker"* branch failed to
fire.

The user-visible result is precisely the stranding FN-8356 was written
to remove: a card keeps its **"Needs your decision"** duplicate badge
pointing at work that shipped days ago, and no decision can resolve it —
the detail banner deliberately offers none for an inactive canonical.

## Measured

With the fix reverted, exactly one case flips:

```
✓ clears the FN-8353-shaped hidden decision for every inactive canonical state
× renamed vocabulary: clears the decision for a canonical resting in a RENAMED complete column
✓ renamed vocabulary: leaves the decision alone while the canonical is still in the WIP lane
✓ leaves active canonical decisions, user pauses, unrelated reasons, non-marker sources untouched
  Tests  1 failed | 3 passed (4)
```

With it: `Tests 4 passed (4)`.

## Wiring is proven separately from behaviour

A behaviour test on one call site says nothing about the other four —
that is the failure this whole lane keeps re-finding, so I did not rely
on it.

With #2822's barrel-import fix applied locally, the seam gate's
staleness check **fails both engine allow-list entries as "now
supplied"** — it can no longer find an omitting call site in either
file. That is the proof for all five.

Consequence worth flagging: **when the second of #2822 / this PR lands,
the two engine entries in #2822 must be deleted.** CI fails until they
are, by design — the exemption cannot outlive its fix.

## Both negatives included

A canonical still in the WIP lane must **not** have its decision
cleared, under each vocabulary. Resolving real flags must not degrade
into "every column is terminal", which would dismiss a duplicate
decision the operator has not made yet.

## Design note

The helper is module-private in each file rather than shared.
`findColumn` is already duplicated exactly this way in
`hold-release.ts`, `merge-trait.ts`, and `workflow-capacity.ts` —
following the established shape beat adding a cross-module abstraction
for a bug fix.

## Verification

`pnpm test:gate` green · 27 triage suites / 387 tests green · engine
`tsc` 0 · lint 0 · changeset included.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 13:04:58 -07:00
..
2026-07-26 18:11:47 -07:00