Files
fusion/packages
gsxdsm f0875a79c6 fix(dashboard): finished cards on a renamed board never showed a completion date (#3007)
The **fifth** instance of the async-memo shape #2998 documents, and the
one that survived #3001's sweep.

`lifecycleDates` gates its `completed` value on `isCompleteColumn ||
isArchivedColumn` — both derived from the async `taskColumnFlags` prop —
while listing neither:

```js
}, [task.createdAt, task.executionCompletedAt, task.archivedAt, task.column, locale, lifecycleNowMs]);
```

First paint runs with the flags undefined, the role helpers fall back to
the legacy ids, and on a board whose complete lane is named anything but
`done` that answers false. The flags arrive, `task.column` has not
changed, nothing recomputes, and the card renders **no "Completed
<date>" line at all**.

## Why #3001's sweep called this covered

That PR recorded `mergeSignature` as *"the last live site … nine
persistent candidates, seven covered transitively or by a dependency
that already carries the flags."* This memo was presumably in the
covered pile, and the reasoning is nearly right: it **does** list a
dependency that changes — `lifecycleNowMs`.

But that value is driven by a timer scheduled with
`millisecondsUntilNextLocalMidnight` (FN-8561, so compact date labels
turn over at the viewer's midnight). **A dependency that changes once a
day is not coverage for a value that must be correct on first paint.**
The card shows no completion date for the rest of the session.

That distinction is worth adding to the doc's property 2: *does a listed
dependency change* is the wrong question — *does it change when the
resolved value arrives* is the right one.

## Verification

| state | result |
|---|---|
| clean | 2/2 pass |
| revert the dep fix | **1 failed / 1 passed** |

The control case (a `done` board) passes either way by design, so a
failure in the renamed case means "renamed board", not "nothing
renders".

**One trap worth recording**, since it nearly cost me the finding: my
first `completedLine()` used `time[datetime]:last-of-type`. When only
the *Created* line renders, that selector returns **that** element — so
the pre-resolution absence assertion silently passed against the wrong
node. The test now matches on the element's own `Completed` label. A
positional selector cannot express "this specific line is missing".

`tsc -p tsconfig.app.json` 0 errors, lint clean, 8/8 across all three
renamed-lane TaskCard suites.

## Note

`main` is currently red on the FNXC gate for an unrelated reason
(#2994's impossible-hour stamps landing after #2995); fixed in #3006.

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