Skip to content

fix(flow-chat): eliminate excess footer whitespace after tool-card collapses (#1176)#1181

Merged
limityan merged 2 commits into
mainfrom
fix/issue-1176-chat-whitespace
Jun 13, 2026
Merged

fix(flow-chat): eliminate excess footer whitespace after tool-card collapses (#1176)#1181
limityan merged 2 commits into
mainfrom
fix/issue-1176-chat-whitespace

Conversation

@limityan

Copy link
Copy Markdown
Collaborator

Problem

GitHub issue #1176: After multi-turn conversations with tool-card collapses, an excessive whitespace gap accumulates at the bottom of the message list. The gap grows with each streaming cycle and never shrinks.

Root Cause

The collapse protection system relied on \layoutTransitionCountRef\ (CSS \ ransitionrun/\ ransitionend\ event counting) as the sole signal for blocking compensation consumption. When Virtuoso virtualization removed DOM nodes mid-transition, \ ransitionend/\ ransitioncancel\ events were lost, leaving the counter permanently stuck above zero. This blocked ALL consumption paths for \collapse.px, causing the synthetic footer reservation to grow without bound.

Solution

Replaced the transition-event system entirely with \pendingCollapseIntentRef\ (state-based, with \expiresAtMs\ timestamp) as the sole collapse protection signal. No timers, no event counting — all state changes are observable and deterministic.

Three accumulation paths for \collapse.px\ are now sealed:

1. Collapse intent expiry drain


eplayDeferredFollowIfSettled()\ (called on every scroll event) detects when \pendingCollapseIntentRef.expiresAtMs\ passes and immediately drains residual \collapse.px\ to zero. Previously, expired intents left stale compensation that could only be consumed by future content growth or user scroll — which may never happen.

2. Unsignaled shrink ratchet fix

\measureHeightChange's unsignaled shrink path used \Math.max(currentCollapseCompensation, fallbackRequiredCollapseCompensation), creating a ratchet where \collapse.px\ could only grow, never shrink. Replaced with just \ allbackRequiredCollapseCompensation\ so the compensation tracks the actual need.

3. Input shrink drain without streaming

The \useLayoutEffect\ that protects against input-footer shrink added to \collapse.px\ but relied on streaming content growth to consume it. If no streaming followed (e.g., quick turn completion), the residual persisted. Now schedules a
equestAnimationFrame\ drain when !isStreamingOutputRef, guarded by \pendingCollapseIntentRef.active\ to avoid racing with an ongoing tool-card collapse transition.

Audit

An adversarial third-party review identified and addressed a medium-risk race condition in the initial Issue 3 fix: the rAF drain lacked a guard for active collapse intents. This was fixed before commit — the rAF now checks \pendingCollapseIntentRef\ and skips drain if a transition is still being protected.

Residual edge cases acknowledged (low risk):

  • Unsignaled shrinks during non-streaming, non-input-shrink idle scenarios lack a guaranteed drain path. They rely on user scroll-down or content growth to consume.
  • The 1000ms intent timeout is empirically safe for current tool-card transitions but is not contractually coupled to CSS transition duration.

Verification

\
pnpm run type-check:web ✓ (0 errors)
E2E tests (4 specs) ✓ (4 passing, 17.9s)
\\

E2E coverage:

  • Test 1: Session/dialog/VirtualMessageList structural verification
  • Test 2: Streaming true→false drains injected collapse.px (footer returns to baseline)
  • Test 3: 3 streaming cycles with 300px injection each — footer stays at baseline (no accumulation)
  • Test 4: Session switch resets all compensation

Files Changed

  • \src/web-ui/src/flow_chat/components/modern/VirtualMessageList.tsx\ — core fix
  • \ ests/e2e/specs/l1-chat-scroll-whitespace.spec.ts\ — new E2E test file
  • \ ests/e2e/config/wdio.conf_l1.ts\ — register new test in L1 suite

limityan added 2 commits June 13, 2026 14:36
…afety

When multiple subagents are dispatched and one must wait for another
to finish (e.g., a read-only FileFinder followed by a read-write
GeneralPurpose), the second tool previously appeared to be
@limityan limityan merged commit 22d9763 into main Jun 13, 2026
4 checks passed
@limityan limityan deleted the fix/issue-1176-chat-whitespace branch June 13, 2026 10:00
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