Parent: #991
Summary
The transcript claims to autoscroll only while the user is at the bottom, but pinnedToBottom is initialized to true and never changes. Every appended item and every streamed assistant-text delta therefore calls scrollTo(bottomAnchor), pulling the viewport away from older content the user is reading.
Evidence
macapp/Sources/GoCodeUI/ChatView.swift:88-114 — pin state is declared and every stream mutation calls scrollIfPinned.
macapp/Sources/GoCodeUI/ChatView.swift:127-131 — the only pin-state consumer; no writer exists.
- Repository search finds no assignment that can make
pinnedToBottom false.
Impact
A long-running response makes earlier transcript content effectively unreadable until streaming ends. This violates the view's own documented behavior and removes user control during the app's primary workflow.
Scope
- Track whether the bottom anchor is actually visible (or within a small semantic threshold).
- Pause autoscroll as soon as the user scrolls upward.
- Resume when the user returns to the bottom.
- Show a keyboard-accessible “Jump to Latest” affordance while new content arrives off-screen.
- Respect Reduce Motion for programmatic scrolling.
Out of scope
- Changing transcript row styling or storage.
- Replacing the whole transcript renderer.
Tests first
- Extract/test a small scroll-pin state reducer covering: initially pinned, user leaves bottom, streamed delta while unpinned, user returns to bottom.
- Production-reachability test proving the scroll-position signal writes the pin state.
- Manual smoke with a real streaming run: scroll upward mid-response and verify the viewport stays put; activate Jump to Latest and verify following resumes.
Acceptance criteria
Parent: #991
Summary
The transcript claims to autoscroll only while the user is at the bottom, but
pinnedToBottomis initialized totrueand never changes. Every appended item and every streamed assistant-text delta therefore callsscrollTo(bottomAnchor), pulling the viewport away from older content the user is reading.Evidence
macapp/Sources/GoCodeUI/ChatView.swift:88-114— pin state is declared and every stream mutation callsscrollIfPinned.macapp/Sources/GoCodeUI/ChatView.swift:127-131— the only pin-state consumer; no writer exists.pinnedToBottomfalse.Impact
A long-running response makes earlier transcript content effectively unreadable until streaming ends. This violates the view's own documented behavior and removes user control during the app's primary workflow.
Scope
Out of scope
Tests first
Acceptance criteria
swift test, Swift build, formatting, and strict format lint pass.