fix(platform): stabilize chat scroll and layout during streaming drain#611
Conversation
Replace boolean programmatic-scroll guard with a timestamp-based window to handle browsers firing multiple scroll events per scrollTo call. Freeze the stream buffer anchor position once drain begins to prevent StableMarkdown re-parse layout shifts. Unify StructuredMessage to always render via the mapped-sections path so TypewriterText survives when new sections (e.g. [[NEXT_STEPS]]) appear mid-stream.
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
📝 WalkthroughWalkthroughThis PR refactors chat streaming to prevent component remounts and layout instability. It introduces a Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes The changes span six files with heterogeneous modifications: public API surface expansion for Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@services/platform/app/features/chat/hooks/__tests__/use-stream-buffer.test.ts`:
- Around line 430-451: The test "anchor still advances normally during active
streaming" currently uses a non-strict assertion that allows a stalled anchor;
update the assertion to require a strict increase by replacing
expect(anchor2).toBeGreaterThanOrEqual(anchor1) with
expect(anchor2).toBeGreaterThan(anchor1). If flakiness arises, increase the
simulated time window used with advanceFrames (e.g., the second advanceFrames
call) so the streaming has enough frames to progress; locate this logic around
the useStreamBuffer hook test referencing result.current.anchorPosition and
advanceFrames.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (7)
services/platform/app/features/chat/components/chat-interface.tsxservices/platform/app/features/chat/components/structured-message/__tests__/structured-message.test.tsxservices/platform/app/features/chat/components/structured-message/structured-message.tsxservices/platform/app/features/chat/hooks/__tests__/use-stream-buffer.test.tsservices/platform/app/features/chat/hooks/use-stream-buffer.tsservices/platform/app/hooks/__tests__/use-auto-scroll.test.tsservices/platform/app/hooks/use-auto-scroll.ts
…ng streaming The ResizeObserver was resetting programmaticScrollAtRef on every height change, making the 50ms guard window perpetually active during streaming. This prevented users from scrolling away while content was growing. Remove the timestamp reset from the ResizeObserver callback — the guard now only activates for explicit scrollToBottom/scrollTo/useLayoutEffect calls. Also fix the guard test which passed at the threshold boundary regardless of whether the guard was active, mock performance.now() globally for deterministic test timing, and correct a stale comment referencing the removed enabledRef behavior.
Summary
scrollTocall, preventing auto-scroll from permanently breaking mid-streamStructuredMessageto always render via the mapped-sections path so theTypewriterTextatkey="section-0"survives when new sections (e.g.[[NEXT_STEPS]]) appear mid-stream — eliminates content flash from unmount/remountTest plan
use-stream-buffer.test.ts)scrollTohelper and programmatic scroll guard window (use-auto-scroll.test.ts)[[NEXT_STEPS]]appears during streaming (structured-message.test.tsx)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests