Files
ai-app/app
irisandClaude Opus 5 cc41a03746 Keep eight screens of rows built, and stand the rest down
Iris's readings made the shape unarguable: smooth with one page loaded,
a step worse at the next, worse again at the one after, and 62.7ms at
the median by 390 rows -- with layout at 0.1ms and the GPU at 1.8ms the
whole time. The cost was following what was *loaded* rather than what
was on screen, and keeping every row built is the only thing in here
that does that.

So the window is bounded. Eight screens either side stay fully built,
which is about sixteen times what a lazy list keeps: everything somebody
has just read is still there, and only a deliberate journey back through
the conversation pays to rebuild anything. That was the point of
retaining rows and it survives; what does not survive is retaining all
of them.

A row outside the window is replaced by a spacer of the height it was
last measured at, so the transcript's total height is unchanged and
nothing under the reader moves. A row that has never been measured has
no height to stand in for it and is kept whatever its distance, which is
exactly the row that has just been paged in.

Each row decides for itself, in a composable of its own, from a derived
state -- so a row hears about the scroll only when its own answer
changes. Read from the list's body instead, every row would recompose
whenever any row crossed the edge.

On the emulator, same transcript and same gesture, the frame's draw
phase goes from 2.7ms at the median to 0.4ms. Iris's own timing reading
from before this says where the rest of her frame goes: the transcript's
whole draw is 3.0ms mean against a 4.2ms median draw phase, so the
median frame was already close to budget and what is left is the tail --
20ms of waiting and 2.3 seconds of parsing in bursts, both of which
arrive with a page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 02:51:35 -04:00
..