Skip to content

fix(desktop): bound initial timeline retention - #5603

Merged
wesbillman merged 2 commits into
mainfrom
carl/fix-initial-timeline-retention
Aug 11, 2026
Merged

fix(desktop): bound initial timeline retention#5603
wesbillman merged 2 commits into
mainfrom
carl/fix-initial-timeline-retention

Conversation

@wesbillman

Copy link
Copy Markdown
Collaborator

Summary

  • let Virtua own the initial visible timeline range instead of passing every loaded row to keepMounted
  • populate the existing bounded retention window after the virtualizer reports its first settled viewport
  • cover a 10,000-row timeline to prevent an all-history initial mount regression

Why

useTimelineRetention initialized its retained-key set with every loaded timeline key. Those indices were passed to Virtua's keepMounted, effectively defeating virtualization during initial channel positioning until onScrollEnd pruned the set.

On a large real channel this grew WebContent into multiple gigabytes and blocked the renderer main thread for 20+ seconds while WebKit laid out and painted the retained rows. Starting with no retained rows restores Virtua's visible-range mount; the existing reader-neighborhood and visual-tail retention is populated once the viewport is measured.

Validation

  • node --import ./test-loader.mjs --experimental-strip-types --test src/features/messages/ui/useTimelineRetention.test.mjs
  • pre-push hook at 8e86a189de7e9a8f2cb119396c8f912ed9dacd6e: branch-skew, desktop-check, desktop-typecheck, and all 4,671 desktop tests passed
  • manual ablation against PR fix(desktop): remove 0.5.9+ perf regressions, speed up get_channels #5599 on the affected profile: catastrophic channel-switch stalls disappeared

Authorship disclosure

Carl implemented and is posting this change on Wes's behalf.

Let Virtua own the initial visible range instead of passing every loaded
message through keepMounted. Populate the stable retention window after
the virtualizer reports its first settled viewport.

Add a hook regression test covering a 10,000-row timeline: no indices are
retained initially, then the bounded reader neighborhood and visual tail
are retained after scroll end.

Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman
wesbillman requested a review from a team as a code owner August 11, 2026 21:32
// seeding every key here turns `keepMounted` into an all-history mount.
const [retainedKeys, setRetainedKeys] = React.useState<ReadonlySet<string>>(
() => new Set(keys),
() => new Set(),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this it!?!?! Crazy

Keep a bounded 100-row visual tail mounted during initial positioning, then
refresh retention from the measured viewport after the first painted frame.
This preserves bottom and reading-state initialization without returning to
the pathological all-history mount.

Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 3f7d6ebe3b8062ffd3fcf91cdfc61098eb05539d. The bounded initial tail fixes the all-history keepMounted regression while preserving initial bottom positioning, and the post-paint refresh correctly reuses the existing viewport/tail retention policy and prepend guard. The 10,000-row regression covers both the initial bounded state and the measured steady state. I found no blocking or non-blocking issues.

@wesbillman
wesbillman merged commit d9dc76c into main Aug 11, 2026
27 checks passed
@wesbillman
wesbillman deleted the carl/fix-initial-timeline-retention branch August 11, 2026 22:59
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.

2 participants