Challenge 5: Compose Interruption

The user is typing a long message. A poll returns a new message. If we auto-scroll or redraw, the OSK cursor position and text might flicker or shift. The OSK must remain the top-most rendered layer, and its state must be completely independent of message updates.

Need: The draw loop must render OSK after messages, and message updates must not mutate self.compose_text, self.compose_cursor, or OSK selection state.

Challenge 6: Rate of Arrival

What if 10 messages arrive in a single poll? Or messages arrive faster than the poll interval? The UI should handle batch arrivals gracefully — show all new messages, update the count indicator, and auto-scroll once to the bottom (not 10 separate scrolls).