Reported from a live board: a task that is done, and demonstrably has journal entries,
shows "(no activity)".
Two mechanisms, each harmless alone.
`stripTaskListHeavyFields` empties `log` and KEEPS every other field, `prompt` included. So
an SSE task:updated payload for a task with a spec arrives with `prompt` present and
`log: []`.
The detail mount effect treats `"prompt" in task` as proof the prop is a complete TaskDetail
and returns WITHOUT requesting the detail. `prompt` and `log` are stripped by different
paths, so that proxy is false for exactly the payload above — the card adopts a log-less
snapshot as if it were complete.
The only rescue, refreshEmptyActivityFeed, was bound to a segment CHANGE. A card that OPENS
on Feed — `initialTab: "logs"`, which is how a deep link and the board's activity affordance
land — never changes segment, so "(no activity)" was permanent for that visit.
The rescue now runs whenever an empty Feed is visible. Its existing emptiness guard is what
keeps this cheap: a populated feed still costs no request, and a genuinely empty task asks
once, because the callback identity is stable while it stays empty.
Three regression tests: the stripped-snapshot open (fails without the fix), an honestly empty
journal that must report empty without spinning, and a prop-carried journal that must render
without re-requesting. One existing FN-8779 fixture gained a default mock implementation
because it resets the mock and queues only one — its subject is Feed layout, not request
counts, and no assertion was relaxed.
pnpm lint 0 errors, dashboard typecheck clean, TaskDetail suites 758/758, test:gate green.