Files
wadamesh/src
Ruben LabanandClaude Sonnet 4.6 28879f55c4 touch: fix phantom unread badge when ring evicts channel messages
The 96-slot message ring can overflow when there is sustained traffic
across many threads. When ring wraparound silently overwrites a channel's
messages, thread.unread stays non-zero but getThreadMessageIndexes
returns 0 — producing a badge with a count but an empty chat on open.
The same phantom persists across reboots because unread is saved to
disk independently of the ring contents.

Fix has three parts:

1. counted_as_unread per UIMessage (RAM-only): set true when a message
   is the reason a thread's unread counter was incremented. Cleared when
   the thread is marked read, so future evictions of those slots don't
   double-decrement.

2. Eviction hook in appendMessage: before overwriting a ring slot,
   decrement its thread's unread if the slot was counted_as_unread.
   Keeps the counter in sync as the ring wraps.

3. Post-load reconciliation in loadHistoryFromStorage: after restoring
   thread+message state from disk, any thread whose persisted unread
   count exceeds its actual incoming messages in the ring gets clamped
   (or reset to 0 if the ring has nothing for it). Also reconstructs
   the counted_as_unread flags so evictions after boot are tracked.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 08:34:37 +02:00
..