4.8 KiB
Prose start/end jump diagnosis
Historical first-pass diagnosis. A later two-turn/manual-reading replay also identified a transient native error at completion, which these initial replays missed. See completion correction.
Four offline phone replays: Nelly and Polaire, each with normal and reduced motion. The neutral recorded library text was repeated eight times and paced in synthetic 350-character deltas to expose overflowing text. A requestAnimationFrame probe measured every rendered frame. Changed-frame evidence. These measurements identify reproducible causes; chunk sizes and absolute distances can differ in a real conversation.
| Moment | Measured movement | Owning behavior |
|---|---|---|
| First prose chunk | Header 108 → 80px; transcript top moves up 28px in both personas | The streamed short title replaces a two-line title with one line. conversation-status.tsx:98 renders it immediately; conversation-status.stylex.ts:59 gives each line 28px. Header height is natural, so the entire viewport moves. No scroll-direction toggle occurs. |
| Growing prose first exceeds the viewport | Nelly: text height grows 115.5 → 250.25px; scroll stays 0 for a frame, then jumps to 113px about 33ms later. The same paragraph moves from y=533.5 to y=420.5. | Native MessageScroller content ResizeObserver schedules a requestAnimationFrame, then performs scrollToEnd({ behavior: 'auto' }). This produces a visible layout update followed by a discrete bottom correction. Subsequent chunks repeat the pattern. |
| Suggestions arrive after prose | Polaire composer 51 → 85px; viewport 597 → 563px; about 33ms later scrollTop 587 → 621px and unchanged prose y=-130 → -164px | narrative-composer.tsx:59 mounts the suggestion rail. Polaire's composer participates in normal flow. The native viewport ResizeObserver then follows the new bottom. |
| Native run completes | No measured geometry change in any of the four replays | aria-busy changes true → false after the preceding movements. The final structured-output transition is not itself the cause in these fixtures. |
Nelly's overlay composer also grows, 80 → 152px, when suggestions arrive. In this replay it does not move the prose: its existing 160px transcript padding already covers that height. Thus the end-adjacent jump depends on persona layout.
The native observer/scroll implementation is in node_modules/@shadcn/react/dist/message-scroller/index.js:2: Content's observer (pt), Viewport's observer (Rt), resize handler (Ce), and scroll call (V). Our current local patch changes user-intent marker clearing only; it does not introduce those observers, their animation-frame delay, or their automatic scroll behavior.
The earlier settled-sample checks missed the two-frame correction. Their normalized transcript coordinates intentionally subtract scrolling; a stable content coordinate does not prove a stable on-screen reading position. The compact receipt tests correctly establish that closed rationales do not grow, but do not establish that the surrounding viewport is stable.
Not reproduced here: a standalone completion jump with unchanged title, composer, content and viewport. Image insertion, persona handoff, title wrapping in other locales, and a real conversation's existing scroll position remain separate possible contributors. No new UX fix or fixed-height reservation is proposed or applied in this diagnosis.