Edge Cases & Failure Modes

Scenario Expected Behavior
Poll returns exact same messages as cached Silent no-op, no redraw
Poll returns 1 new message while user is at bottom Append, auto-scroll, update selection
Poll returns 1 new message while user is scrolled up Append, show “New messages” indicator, preserve scroll
Poll returns N new messages in a batch Append all, auto-scroll once if at bottom, show count if scrolled up
Poll returns a message that was already sent optimistically Replace optimistic entry with confirmed one, preserving scroll position
Poll fails (timeout) Log, retry next interval, no UI change
Poll fails 3 times in a row Show subtle offline indicator (gray dot in nav bar)
User sends message while poll is in-flight Optimistic append immediately, poll response merges without conflict
User opens OSK while “New messages” indicator is visible Indicator stays visible, OSK opens on top
User navigates back to chat list while “New messages” is visible Indicator is dismissed, scroll position is NOT preserved for next chat entry
App receives a reaction message (associatedMessageGuid set) Treated as a new message, appended, indicator shown
Message list grows beyond 200 messages Truncate oldest messages from self.messages, but NOT from BlueBubbles history (user can scroll up to load more later)