diff --git a/.changeset/taskcard-lifecycle-dates-renamed-lanes.md b/.changeset/taskcard-lifecycle-dates-renamed-lanes.md new file mode 100644 index 0000000000..373d1347fd --- /dev/null +++ b/.changeset/taskcard-lifecycle-dates-renamed-lanes.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Finished cards on a renamed board now show their completion date. +category: fix +dev: `lifecycleDates` in TaskCard omitted `isCompleteColumn`/`isArchivedColumn` from its dependency list; both derive from the async `taskColumnFlags` prop. diff --git a/packages/dashboard/app/components/TaskCard.tsx b/packages/dashboard/app/components/TaskCard.tsx index 9e1c638023..f0f47b2162 100644 --- a/packages/dashboard/app/components/TaskCard.tsx +++ b/packages/dashboard/app/components/TaskCard.tsx @@ -1863,7 +1863,25 @@ function TaskCardComponent({ ? formatCompactLifecycleDate(completionSource, locale, new Date(lifecycleNowMs)) : null; return { created, completed }; - }, [task.createdAt, task.executionCompletedAt, task.archivedAt, task.column, locale, lifecycleNowMs]); + /* + FNXC:WorkflowResolvedColumns 2026-07-31-08:20: + `isCompleteColumn` AND `isArchivedColumn` BELONG IN THIS LIST — both derive from the async + `taskColumnFlags` prop, and the completion date is gated on them. + + The board resolves workflow traits after first paint, so the first computation runs with the flags + undefined and the role helpers fall back to the legacy ids. On a renamed board that answers false, + `completed` is null, and the "Completed " line never renders. When the flags arrive nothing in + the old list had changed — every entry was a `task.*` field, `locale`, or `lifecycleNowMs`. + + WHY THE SWEEP IN #3001 CALLED THIS COVERED: `lifecycleNowMs` does change, so the memo does + eventually recompute — but its timer fires at the viewer's LOCAL MIDNIGHT (see the + `millisecondsUntilNextLocalMidnight` effect). A dependency that turns over once a day is not + coverage for a value that must be right on first paint; the card shows no completion date for the + rest of the session. + + A default board hides it: `column === "done"` is already true before the flags land. + */ + }, [task.createdAt, task.executionCompletedAt, task.archivedAt, task.column, locale, lifecycleNowMs, isCompleteColumn, isArchivedColumn]); const liveBadgeData = badgeUpdates.get(`${projectId ?? "default"}:${task.id}`); diff --git a/packages/dashboard/app/components/__tests__/TaskCard.lifecycle-dates-renamed-lanes.test.tsx b/packages/dashboard/app/components/__tests__/TaskCard.lifecycle-dates-renamed-lanes.test.tsx new file mode 100644 index 0000000000..0fa344f1ed --- /dev/null +++ b/packages/dashboard/app/components/__tests__/TaskCard.lifecycle-dates-renamed-lanes.test.tsx @@ -0,0 +1,105 @@ +/* +FNXC:WorkflowResolvedColumns 2026-07-31-08:25: +THE "Completed " LINE NEVER APPEARED ON A RENAMED BOARD. + +`lifecycleDates` gates its `completed` value on `isCompleteColumn || isArchivedColumn`, both derived +from the `taskColumnFlags` PROP. The board resolves workflow traits asynchronously, so the first +computation 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` the answer is false. + +The dependency list held only `task.*` fields, `locale` and `lifecycleNowMs`, so when the flags +arrived nothing invalidated and the card kept rendering no completion date. + +WHY THIS SURVIVED THE #3001 SWEEP, which recorded `mergeSignature` as the last live site: this memo +DOES list a dependency that changes — `lifecycleNowMs`. But its timer fires at the viewer's local +midnight, so "eventually recomputes" means once a day. A value that must be correct on first paint is +not covered by a dependency that turns over daily. + +Asserted through the rendered `