Skip to content

ADR-0058: Stable transcript reflow and scroll ownership ​

Status: Accepted · 2026-09-07 · Refines ADRs 0053, 0056 and 0057.

Context ​

The user reported chat content disappearing during font resizing and scrolling. A native regression exposed a stack-overflow crash in observable font setters that assigned to themselves unconditionally. The transcript also fed estimated lazy-stack heights into immediate scroll commands and animated row placement.

Decision ​

Use a fully measured VStack containing at most 40 messages, with the existing bounded Markdown cache. Native lazy-stack height estimates remained unstable under large font/width changes, and the native list alternative failed the selection/reflow regressions. A bounded measured window trades implicit whole-history scrolling for predictable geometry and bounded rich-view work.

Earlier and Later controls move by 20 messages with an overlapping window, preserving the current edge as a message-ID scroll target. Latest and a new send return to the newest window. All messages remain in the model and database; model context and generation ownership do not use this display range. Loading/evicting model history remains separate work.

Each message contributes one stable, vertically self-sizing child. Row insertion fades and offsets are removed. Native scroll-position binding preserves reading identity; native size-change anchors handle font, width and prepared-content reflow. Estimated content heights no longer drive explicit scrolling.

A bottom sentinel tracks whether the reader has reached the end. Reader gestures suspend following through deceleration; ending at the bottom resumes it. New sends resume following. Stream-driven commands retain their 15 Hz upper bound and are always deferred out of the current layout frame. Disappearance and reader gestures cancel pending commands.

Font setters assign a normalized value only when it differs, then persist the canonical value. This bounds observable setter reentry while preserving existing preference keys and valid ranges.

Consequences and validation ​

No storage, network authority, dependency or cache policy changes. Visibility observations stay outside observable view state; resuming following is deferred to avoid layout feedback. Long-history paging and large-code rendering remain PERF-01 and PERF-04.

Native regressions cover long/short chat selection, 80 messages across five width/font combinations and five native wheel movements, and scroll-wheel events followed by streaming and reflow. Font tests cover repeated, fractional, out-of-range and non-finite assignments and persistence. Visual inspection uses the complete hosting view, not its transparent clipping layer.

References ​