Repository navigation
Agent chat: growing the composer never moves the transcript or its scrollbar - #23097
Conversation
The room kept under the transcript's last row for the floating bottom stack was the stack's live height, so every composer line (Shift-Return or a wrap) changed the scroller's content height. Scrolled up, that moved and resized the scrollbar's thumb (and redrew the full-height minimap) on each newline even though the reader's rows stayed put. The room now follows the stack only while the view follows the latest row; scrolled up, it stays as it was, so the scroller's offset, height and scrollbar are unchanged. Back at the latest row the room is the stack's again and the last row sits above the grown card. A followed view still stays at its end as the composer grows. Test: agent-pane-scrollbar-full-height gains "a composer that grows leaves a reader scrolled up where they were, scrollbar and all, on every frame" (red on base: scrollHeight grew on every line). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=cosmic-gray
|
Owned by projects-9d on cosmic-gray · session |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Unclear: CI failed on
Failures:
Matched log linesNot re-run automatically: Written by red: web / Web status; NEW: green on the base 3d944c5; do not merge until green; see lane-rules
Agents: Tour of |
|
Bead |
|
Found 20 test failures on Blacksmith runners: Failures
...and 10 more test failures. View all on Blacksmith
|
…er-grow-keeps-scroll
|
Review (subagent, correctness first): SHIP at 5a5ab52 An independent review subagent read this PR's change at ef6af37 (code only, no local run) and passed it with nothing blocking. 5a5ab52 is a clean merge of origin/feat-cmux-next into that commit: the PR's diff against base is unchanged, still the same two files.
Risk tier:
This receipt should have been posted before the merge; posting it now so merge-audit can close #23244. |
Scrolled up, the room under the last row stays as it was (#23097), so the scroller ended short of a composer that grew meanwhile, and Jump to latest snapped to the end: following again gave the room back, and a followed view's room moves its offset at once. Jump to latest now takes the room first, out of view, and glides to the end above the card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray
|
Shipped in:
|
…23257) * test(next): back at the end after the composer grew, the last row is never under the card Review of #23097: scrolled up, the room under the last row stays as it was, so the scroller ends short of a composer that grew meanwhile. Scrolling back to the end must never show the last row under the card, and Jump to latest must glide there instead of snapping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray * test(next): the composer guards sample until the card has shrunk back The reader guard from #23186 read its frames a fixed 300 ms after clearing the draft; on a slow runner the last shrink painted later and the card was still a line taller (CI on 5566a2a). Both grow-and-shrink guards now wait for the card to reach its first frame's height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray * fix(next): Jump to latest glides to the end after the composer grew Scrolled up, the room under the last row stays as it was (#23097), so the scroller ended short of a composer that grew meanwhile, and Jump to latest snapped to the end: following again gave the room back, and a followed view's room moves its offset at once. Jump to latest now takes the room first, out of view, and glides to the end above the card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray * fix(next): Jump to latest aims at the committed layout's end Review of #23257: scrollHeight is 0 under jsdom, so the jump aimed at the top in transcript-jump-latest.test.tsx. The layout the taken room just committed gives the same end in the browser. The composer guards wait for the card's height from before typing, not their first sample. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray * test(next): the composer guards take their first frame before the first key On a slow runner the sampler's first frame landed after the first Shift-Return, so the card's first height was a line taller than at rest (CI on 7f70721). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray * fix(next): Jump to latest's glide is not snapped to the end on its way The jump follows again at once, so its first small step read as layout work and settled at the end, and a layout pass while following did the same: the glide snapped (CI on 7f70721, one moving frame). While the glide is in flight its steps are the view following, a layout pass aims it at the new end, and the reader's input or the landing ends it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray * fix(next): a Jump to latest glide reports the latest place and yields to Find Review of #23257: the glide's steps returned before the kept place was reported, so a chat reopened after Jump to latest opened where the reader had been. Its steps now commit before paint and report the latest place, a Find match or a row reveal ends the glide, and the keyboard jump test wheels back up as a reader does before its second jump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray * webviews: the Jump to latest tests wait for the view to come to rest, not a fixed time Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc7-79b0-b869-8ac78b0edd90&host=cosmic-gray --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Typing a newline in the agent chat's composer (Shift-Return, or a soft wrap) made the transcript's scrollbar jump (Leo, 2026-10-20).
Root cause: the bottom stack floats over the transcript's foot, and
VirtualTranscriptkeeps room under the last row equal to the stack's live height (rowsHeight = rows + THREAD_TOP + dockSpace). Every composer line therefore changed the scroller's content height. Scrolled up, the reader's offset and rows stayed put, butscrollHeightgrew by a line each time, so the scrollbar's thumb moved and shrank on each newline (and WebKit flashes the overlay scroller on a content resize). The full-height minimap, sized fromheight - dockSpace, rescaled every mark on each line too.Fix (
App.tsx): the room under the last row follows the stack only while the view follows the latest row. Scrolled up, it stays as it was, so the scroller's offset, height and scrollbar don't change, and neither does the minimap. Back at the latest row, the room is the stack's again and the last row sits above the grown card. A followed view still stays at its end on every frame as the composer grows, as before. Jump to latest, the mask under the stack, and scroll-into-view still use the stack's live height.Follow-up to #22819 (bottom stack is a no-scroll zone), built on #22272 and #22858.
Changelog
Fixed: In agent chat, typing a newline in the composer while scrolled up no longer moves the transcript's scrollbar.
Testing
webviews/test/agent-pane-scrollbar-full-height.test.tshas a new case, "a composer that grows leaves a reader scrolled up where they were, scrollbar and all, on every frame". It scrolls up, grows the composer by four Shift-Return lines and a wrapped line, and samples every painted frame:scrollTop,scrollHeightandclientHeightstay unchanged. It then scrolls back to the end and checks that the latest row sits above the grown card. The existing case "a composer that grows keeps the followed end above it on every frame" covers the pinned view (distance from end stays 0 on every frame).CMUX_BROWSER_TESTS=1). The new case fails on base (scrollHeightgrew on every line) and passes with the fix, twice. Related suites pass with the fix: agent-pane-bottom-stack, chat-column, follow-live, pr-dock, queue-steer, thread-minimap-, thread-scroll-map, transcript-scroll-restore.tsc --noEmit,vp fmt --checkandvp lintpass on the changed files.Observed / Not run
Agent session: cosmic-gray
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Fixes agent chat so growing the composer (newlines or soft wraps) no longer moves the transcript's scrollbar when the reader is scrolled up.
Written for commit 5a5ab52. Summary will update on new commits.