Files
fusion/packages
gsxdsm cf6062c524 fix(dashboard): finished cards on a renamed board never refreshed their diff stats (#3001)
Last live site from the stale-lane-dependency sweep recorded in #2998.
**Nine persistent candidates; this and #2996 were real.** The other
seven are covered transitively or by a dependency that already carries
the flags — each checked by hand rather than filed, which is the whole
point of that doc.

## The defect

`mergeSignature` is the key `useTaskDiffStats` uses to notice that a
merge changed what a finished card should display. It early-returns
`undefined` unless `isCompleteColumn`, which derives from the
`taskColumnFlags` **prop** — and its dependency list was three `task.*`
fields, none of which is that prop or carries it.

The flags arrive after first paint, so:

1. first computation runs with flags `undefined`;
2. the role helper falls back to the legacy id —
`isCompleteColumnRole(undefined, "shipped")` is **false**;
3. the key is `undefined`;
4. for a card **already merged when the board loaded** — the common case
for anything sitting in a completion lane — neither `mergeDetails` field
changes afterwards either;
5. nothing recomputes, and the hook never learns a merge landed.

A legacy board hides it: `column === "done"` answers true on the very
first paint.

## Measured

| check | result |
|---|---|
| test written first | red for the right reason — control and negative
passed, only the arrival case failed (`expected undefined to be
defined`) |
| after the fix | 3 passed |
| dropping the dependency again | that same case fails |
| `TaskCard.test` + new suite | **391 tests green** |
| gates | census + FNXC green; lint and `tsc` clean |

The observable is the options object handed to `useTaskDiffStats`, so
the assertion is on the value this component is responsible for
producing rather than on what the hook does with it.

## The negative case

Recomputing must not hand a signature to cards that aren't finished. An
in-flight card has no merge to key on, and inventing one would have the
diff-stats hook treat unfinished work as landed.

## The sweep is now closed

For anyone picking this up later: the four "bounded" sites from #2998's
triage remain unexamined **by design** — their dependency lists all
contain a fast-refreshing value (`allTasks`, a live clock), so any wrong
answer there survives only until the next update. That's a judgement
about priority, not a claim that they're correct.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 00:02:50 -07:00
..
2026-07-26 18:11:47 -07:00