fix(agent-chat): preserve fractional scroll anchors across transcript and rail
The transcript keeps a fractional row-height correction in a bounded CSS origin on its scroller, so its logical offset (where rows are laid out) differs from scrollTop by under a pixel. The transcript half of this branch landed with #26718 and #27365. Base's rails still read and write raw scrollTop, so their band, thumb and jump targets sit up to a pixel off the rows they point at. This PR fixes that.
Leo: "no jitter, there's no flicker, there's no flash" and "if I'm scrolling upwards, it's, like, there's some sort of weird recalculation."
What changes (after the carry onto current base)
This branch has been merged with feat-cmux-next. That merge takes base's App.tsx, scrollCoordinates.ts, anchor trace and upward-anchor test exactly as #27365 left them. What is left here is the part base lacks:
ChatMinimap.tsx: the minimap's view box andaria-valuenowreadlayoutScrollTop, and a drag writes throughphysicalScrollTop. Absolute Home/End navigation clears the fractional origin, and relative keys keep it.ScrollMap.tsx: the thumb readslayoutScrollTop, and mark jumps and track clicks write throughphysicalScrollTop.ThreadMinimap.tsx: the band, the restored offset and the reading position readlayoutScrollTop, and a turn jump's target goes throughphysicalScrollTop.- Test:
chat-minimap.test.tsxchecks that absolute keys clear the origin and relative keys keep it.
The branch's earlier row-render cases (1/2/4px late scroll events, no-op upward gestures) are dropped. They read a row's place from style.top alone, but base now splits that into an integer top and a fractional marginTop. #27365 covers those transcript behaviors with its own tests.
No new timer, observer or animation is added. The ScrollMap track click stays instant, as base has it.
The fractional-anchor hosted scripts and the Chromium and video additions to the upward-anchor trace are dropped. Base's trace grew its own version in #27365.
No capture: the rails read and write the same offsets in the transcript's logical coordinates; the difference on screen is under a pixel of band placement, which the tests above pin.
Earlier measurements (pre-carry head 688a6927, for history)
Run 40658799574, on the same painted-frame harness with 9,000 rows: blank frames went from 168 to 0 on WebKit and from 187 to 0 on Chromium. Those numbers measure the transcript half, which now ships from #27365.
Changelog
Fixed the thread rail and minimap reading the transcript a fraction of a pixel off after a fractional scroll anchor.
Agent session: agent session