Transcript: a followed reply moves only by what is drawn
Fixes the base flake in webviews/test/agent-pane-chat-column.test.ts: "scrolls smoothly: its last line holds still" (24 > 23) and "a streaming reply keeps the view at its end, through a growing command and a queue". Both failed under CI load (seen on #20644 and #20633) and passed locally.
The load exposed two real scroll jitters:
- A streaming reply scrolled ahead and back on every chunk. A reply's text draws one frame after the version that holds it. The row was first placed by an estimate of the new version, a line or more ahead of the text, then by its drawn height. Now a row keeps its last drawn height until its new version is drawn, so the view grows only by what has been drawn (
App.tsx,heightAt). - The queue let the followed reply slip back a row. Superseded: base #20521 (one bottom stack) removed
--acpmux-queue-space, so that part of the fix was dropped in the base merge.
The test now loads the page itself with Emulation.setCPUThrottlingRate at 6×, so a local run reproduces what CI sees. The smoothness test no longer counts pixels per painted frame. That bound depends on frame timing: one loaded frame can hold two lines of growth. Instead it checks, for each frame, that the followed row moved exactly as far as the glides the thread started since the frame before. A step drawn at once fails at any frame rate. With glide() disabled, the test fails on that check. It still checks that the text never moves down or back.
The live-resize test (#20467) flaked too, but in the test, not the app. The watcher samples each frame in a task after its animation frame. On a loaded page a viewport resize could land between that frame and the sample. The sample's forced layout then read the new width (the reply rewrapped 341 px taller, the spacer and offset still placed for the old width), which the page never painted; the next frame was settled. A frame paints at the viewport its animation-frame callback saw, so a sample whose viewport changed since is skipped. The assertions are unchanged.
Testing
All runs were on the Linux builder, with the throttled page.
| Command | Result | |
|---|---|---|
| Red (test commit) | bun test test/agent-pane-chat-column.test.ts | "keeps the view at its end" fails in 2 of 2 runs |
| Green (fix commit) | same command | 7 pass, 0 fail, in 3 of 3 runs |
| Green after merging base and adding the glide check | same command | 8 pass, 0 fail, in 3 of 3 runs |
| Red (resize test, loaded at 6×) | bun test test/agent-pane-chat-column.test.ts -t 'pane resized' | 16 of 16 fail |
| Green (painted-frame sampling) | same command | 0 of 16 fail; whole file 8/8 at 6× |
Also run on the fix commit:
- the related transcript, queue, step-row and steer browser tests: 31 of 31 pass;
bun run check: clean.
Changelog
- Fixed: a streaming reply no longer slides ahead and back as it grows, and editing the queue no longer nudges the view.
🤖 Generated with Claude Code