Skip to content

perf(flow-chat): reduce session opening latency - #3183

Merged
wsp1911 merged 6 commits into
GCWing:mainfrom
wsp1911:flowchat-perf-pr
Sep 21, 2026
Merged

wsp1911 merged 6 commits into
GCWing:mainfrom
wsp1911:flowchat-perf-pr

Conversation

@wsp1911

@wsp1911 wsp1911 commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Improve FlowChat session opening performance by reducing initial transcript work and
synchronizing viewport state earlier during opening.

Type and Areas

Type: regression fix, UI/UX, test

Areas: web UI, FlowChat, Markdown rendering

Motivation / Impact

Opening a session previously rendered and measured the transcript from the head
before settling near the tail, causing unnecessary layout and virtualization work.

This PR:

  • Starts live-tail sessions near the end of the transcript.
  • Isolates the opening transcript from user interaction until the viewport settles.
  • Reconciles measured scroll offsets through the existing virtualizer observer channel.
  • Publishes opening follow readbacks immediately so range selection can catch up
    without a synchronous React flush.
  • Limits streaming Markdown reveal highlighting to the active streaming content.
  • Adds focused tests and documents the scroll-stability invariants.

The changes reduce unnecessary opening work and improve the time before the first
visible transcript content stabilizes. In a desktop measurement, virtual range
expansion moved approximately 65 ms earlier and reveal completion approximately
15 ms earlier. These figures are sample measurements rather than runtime guarantees.

Verification

  • pnpm --dir src/web-ui exec vitest run src/flow_chat/components/modern/useFlowChatFollowOutput.test.tsx src/flow_chat/components/modern/useFlowChatVirtualizer.initial-window.test.tsx src/flow_chat/components/modern/useFlowChatVirtualizer.measurement.test.tsx src/flow_chat/components/modern/VirtualMessageList.session-boundary.test.tsx src/flow_chat/components/modern/FlowChatOpeningBoundary.test.tsx
    • 5 test files passed
    • 136 tests passed
  • pnpm run check:web
    • Passed
  • git diff --check
    • Passed
  • Session-opening diagnostic probes are not included in this branch history or diff.

Reviewer Notes

The viewport offset handoff uses the existing TanStack virtualizer observer
channel and intentionally avoids flushSync. Opening interaction remains
suppressed until the transcript reaches its settled state, then focus and pointer
behavior return to the normal path.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

Keep the changing edge-mask stop local to the scroller so scroll-edge updates do not invalidate every message row. Runtime opening traces reduced the follow-up style stall from 562.3ms to 3.6ms.
Keep the opening transcript measurable while preventing hidden message controls from receiving pointer, scroll, keyboard, or programmatic focus events. Replace whole-tree inert and visibility transitions with a local shield, focus guards, aria-hidden, and opacity; retain guard nodes through reveal to avoid repeated style invalidation. Add focused boundary contracts and document the measured reveal behavior.
Seed the initial virtual window from estimated row heights to avoid mounting head rows before following the tail. Preserve history restoration and defer the seed until initial hydration has items.

A same-session desktop trace reduced rowRef time from 377.3ms to 4.2ms and advanced the post-reveal probe from 1540.3ms to 806.7ms. These are single-trace timings, not paint guarantees.

Validation: 130 focused tests, check:web, focused ESLint, and diff checks passed. Remote scenarios were not exercised.
Reconcile the existing follow target after measured row sizes enter
the virtualizer cache, then publish the actual offset before the next
window is selected. Prevent delayed scroll-end samples from restoring
an older offset and causing overscan rows to unmount and remount.

Limit reconciliation to active, unsuspended opening transcripts owned
by follow-output. Preserve user takeover and historical reading rules.

A same-session desktop retest reduced row cleanup calls from five to
zero and advanced post-reveal sampling from 786.8ms to 596.4ms. These
are single-trace observations, not paint timing or remote validation.

Validation: 57 focused tests rerun successfully; staged diff checked.
The implementation previously passed 187 related tests, check:web,
and focused ESLint. Temporary diagnostics remain outside this commit.
Limit the 32 reveal highlight rules to text parents with active arrivals.
Keep markers stable across animation frames and release empty shared
highlight buckets without interrupting other renderer owners. Preserve
the 160 ms fade and settle history, replacements, and reduced motion.

A complete local desktop trace reduced pre-reveal style work from
451.5 ms to 172.4 ms. The two row-batch style updates fell from
128.3/223.3 ms to 45.4/61.4 ms; overall opening latency remains variable.

Validation: 10 reveal lifecycle tests and check:web passed. Motion audit
completed. Remote scenarios were not exercised.
Publish the actual scrollTop readback after an opening follow correction so the virtualizer can expand its range before the delayed native scroll event. Keep the update on the existing observer channel without flushSync, preserve viewport ownership and suspension guards, and cover clamping, stale events, and takeover behavior with focused tests.\n\nA desktop trace showed range expansion about 65 ms earlier and reveal about 15 ms earlier; these are diagnostic single-trace results rather than fixed runtime guarantees.
@wsp1911
wsp1911 merged commit 76236b2 into GCWing:main Sep 21, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant