Add experiment-gated timeline row windowing - #2011
Merged
Merged
Conversation
ymichael
force-pushed
the
bb/check-for-dom-virtualization-thr_s7s2cc7j8a
branch
3 times, most recently
from
August 20, 2026 18:53
418d223 to
3f75697
Compare
ymichael
force-pushed
the
bb/check-for-dom-virtualization-thr_s7s2cc7j8a
branch
from
August 20, 2026 19:08
3f75697 to
300015e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
Long timelines kept every rich top-level row mounted after older history loaded, and expanded delegation/turn details likewise kept every nested row mounted. A long-lived client that streams across multiple threads therefore accumulated DOM, rich markdown trees, observers, and row-local interaction state even though almost all content was outside the viewport.
The first prototype fixed the resting DOM size with a bespoke 826-line virtualizer, but it added too much custom geometry and gesture policy to land comfortably. Its cold full-history traversal also mounted each rich row once, producing 4.96 s round trips and 66.3 ms p95 frames.
What changed
Add the default-off
timelineWindowingexperiment using the existing@tanstack/react-virtualdependency for range calculation, variable-height measurement, scroll correction, and momentum-safe updates. A thin timeline adapter retains only product policy:The experiment-off path renders the existing full list. A small
React.lazyboundary keeps the 346-line TanStack adapter out of the route closure until windowing is enabled and a list crosses its threshold; the disabled app does not request that module.The experiment is exposed in Settings,
bb settings experiment timelineWindowing <true|false>, system defaults, docs, templates, and the built-in CLI skill. This does not alter the server/host-daemon wire contract, soHOST_DAEMON_PROTOCOL_VERSIONis unchanged.This PR supersedes #1991 with one experiment that covers top-level and recursive nested rows.
Complexity reduction
The implementation is about 26% smaller in gross additions and the custom windowing layer is about 48% smaller. TanStack owns the difficult virtualizer mechanics; repository code owns the timeline-specific behavior and experiment integration.
How you verified
Final focused validation after rebasing onto current
origin/main:A full app run before the lazy-boundary-only follow-up passed 3,102 tests with three skipped. The replacement GitHub Actions run validates the exact final revision.
Dev Browser QA used a production-derived SQLite copy containing 620,222 events across 504 threads. The benchmark thread contained 38,946 underlying events, 577 projected top-level rows, and about 134.8k px of history.
Matched full-history benchmark:
Real-data nested QA expanded a 103-row turn. It mounted 39 rows at the header and 46 while scrolled through the middle (visible range plus the pinned final row), rather than retaining all 103. Expanding and collapsing it preserved the shared scroll position exactly at
scrollTop=41900. Compact-viewport QA also crossed the 40-row threshold and windowed correctly.The CLI toggled the experiment off and on against the same development server. With 188 loaded rows, the disabled path mounted all 188 with no virtual spacer and did not request the adapter module; the enabled path mounted 15 with a virtual spacer preserving the full scroll geometry. No timeline runtime errors were observed.
No enrolled
mbp-intelhost was available for a hardware-specific rerun; the connected machines were M4 and M5. The benchmark above was run on the production-derived dataset on the M4 host.Fixes: no linked issue.