b3070f16ff6aba8e9df3923c6d7c71903a5da28a
Three things, all of them the same complaint: scrolling back through a long session stalls. **The fold was on the main thread.** Only `fetchTranscript` was inside `withContext(Dispatchers.IO)`; the fold loop that turns a page into rows ran on the caller's dispatcher, which is Main. `foldEvent` returns a new list per event, so a page is that many copies of a list growing to that length -- about three hundred thousand element copies -- run in the middle of the scroll that asked for it. Affordable at 80 events per page and not at 800. **`warm` scanned the whole transcript on the calling thread.** Only `replies.warm` was off it; the `markdownIn` split that decides *what* to parse ran before the hop, over every assistant message loaded, on every page. The scan grew with the conversation while the work it found stayed one page's worth. **The cushion was eight rows, which is not a distance.** A row is anything from one line to a page: on a tool-heavy transcript eight rows is less than one screen, so the reader reached the end of what was loaded on every swipe and waited a round trip standing there. It is three screenfuls now, measured from what is actually on screen. On the emulator against a 24,000-event transcript that is 3 page fetches for 10 swipes rather than 10. Also a spinner while a chat loads. Nothing is drawn while the newest page is in flight or a saved position is being put back, and a blank page is what this screen otherwise means by "there is nothing here" -- so the state that does not know needed its own appearance. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Languages
Rust
54%
Kotlin
43.6%
Shell
2.4%