fix(app): keep the unread session indicator stable during polling - #1403
fix(app): keep the unread session indicator stable during polling#1403chphch wants to merge 1 commit into
Conversation
`buildSessionListViewData` bakes each row's `hasUnread` flag into a snapshot, reading it from an *optional* `unreadSessionIds` set. `applySessions` passes the set, but several other reducers rebuild the snapshot without it — most importantly `applyMachines`, which fires on every machine heartbeat / `fetchMachines` poll. On each such rebuild `hasUnread` falls back to `undefined?.has(id) ?? false`, so every row loses its unread state until the next `applySessions` restores it. The result is a distracting flicker of the unread indicator (bold title on the bold-title builds, the status dot/text on main) on the polling cadence, with no user action involved. Make `unreadSessionIds` a required parameter on `buildSessionRowData` / `buildSessionListViewData` so any reducer that forgets it is a compile error, and thread `state.unreadSessionIds` through the call sites that dropped it (`updateSessionDraft`, `applyMachines`, `deleteMachine`, `deleteSession`). Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Rebased onto current The conflict was stale code on this branch's side: it cleaned up per-session model/effort picks from MMKV in Worth noting what
Heads-up on overlap: #1580 (read-position unread sync) also makes this parameter required as part of changing where |
0a2e8ed to
29c612d
Compare
The unread session indicator flickers off and back on during normal polling, with no user interaction.
buildSessionListViewData()bakes each row'shasUnreadinto the list snapshot, reading it from an optionalunreadSessionIdsset.applySessions()passes the set, but several other reducers rebuild the snapshot without it — most importantlyapplyMachines(), which runs on every machine heartbeat (update-machine,machine-activity) and the periodicfetchMachinespoll. On each of those rebuildshasUnreadfalls back toundefined?.has(id) ?? false, so every row loses its unread state until the nextapplySessions()restores it. Because machine heartbeats arrive on a timer, the unread indicator (the status dot/text onmain) blinks off→on repeatedly while the user just watches the list.The fix makes
unreadSessionIdsa required parameter onbuildSessionRowData()/buildSessionListViewData()so any reducer that forgets it becomes a compile error, and threadsstate.unreadSessionIdsthrough the four reducers that dropped it:updateSessionDraft,applyMachines,deleteMachine,deleteSession. (applySessions,markSessionRead,markSessionUnread, andsetCurrentViewingSessionalready passed it.)Repro: open the sessions list with at least one unread session and an online machine; the unread indicator blinks each time a machine heartbeat arrives (a few times a minute). After the fix it stays stable.
Verification:
pnpm typecheckis clean. Making the parameter required is what guarantees completeness here — every call site is now compiler-checked. A running-app capture is awkward for a sub-second timer transient; happy to add one if you'd prefer it over the mechanism walkthrough above.