Page giant turns' work and collapse the active-turn frontier#738
Open
SawyerHood wants to merge 3 commits into
Open
Page giant turns' work and collapse the active-turn frontier#738SawyerHood wants to merge 3 commits into
SawyerHood wants to merge 3 commits into
Conversation
Collaborator
Author
|
Ran one multi-angle review round over the diff (8 finder angles + verification) and pushed the fixes in ff042a3. Highlights of what it caught:
Full suites green after the fixes (the one failing app test is the pre-existing flaky promptbox slash-token test; it passes in isolation). |
SawyerHood
force-pushed
the
bb/fresh-problem-solution-thr_7rrht6txvp
branch
from
July 16, 2026 13:49
732405c to
2be3bf5
Compare
Very long single turns (observed: 335 min / 7,025 events / 27 MB) froze the browser: active turns rendered every event as a flat row, and expanding a completed turn's "Worked for…" section fetched the entire un-truncated turn in one response. Top-level segment pagination stays untouched — every visible response keeps its initiating user message — and all new bounding happens inside a turn's work section, the lesson from the #711 revert. Server: - turn-summary-details gains work-item paging: `workItemLimit` serves the newest N work items with an `earlierCursor` for progressively revealing older windows; `afterSeq` serves an exact catch-up range. Windows resolve from the indexed item/completed sequence, items straddling a window edge project fully from their completion payload, and paged rows get the same 32 KB output truncation as the timeline (full detail stays un-truncated). - Active turns past ~48 finished work items collapse their settled prefix into a partial "Worked so far" turn row (`partial: true`); recent work, running commands, approvals, and questions stay flat below it. The collapse frontier is derived from indexed completion counts and moves in 24-item chunks, so row identity churns at most once per chunk and the row converges to the normal completed "Worked for…" row at the same id. - Conversation outline selects only message-producing and turn-lifecycle events instead of reading every event (re-land of the #711 outline query, plus lifecycle events so completed-turn grouping matches the timeline). App: - LazyTurnRowBody pages large turns (partial rows and >60-item completed turns) through immutable per-window segment queries with a nested "Show earlier work" control; revealed work is keyed by summary-row id so it survives collapse/expand, live growth, and the completion transition, and prepending anchors scroll like "Load older messages". Verified against a copy of the 39 MB sample thread: the active giant turn's latest page drops from ~7,000 rows / 27 MB to 69 rows / ~420 KB; paged expansion serves ~210 KB windows in ~15 ms with full coverage and no duplicates; the outline builds in ~50 ms. UI exercised end-to-end in the dev app (expand, page, scroll stability). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Correctness: - Bound the collapse-frontier queries (active turn lookup, completion count, nth completion) by the build's maxSeq so a response cached per (thread, maxSeq) never bakes in turn state from events appended after that revision, and pass the same frontiers into the conversation outline so its items always correspond to top-level timeline rows (the minimap's jump-to-message contract). - Guard the partial collapse against an empty settled prefix: previously the single-group fast path fell back to turn.summaryCount and whole-turn bounds, emitting a bogus "Worked so far" row above the same rows rendered flat. - Keep agent/system-initiated steer messages in paged work windows: they fold into summary children for completed turns, so dropping every user row made them unreachable in paged expansions. - Treat NULL-item_kind legacy completions like the outline query does (fall back to the payload's item type) so reasoning completions on old threads don't inflate page windows or the collapse frontier. - Keep the "Show earlier work" control mounted in a loading state while the next-older window fetches instead of flickering out mid-load. - Re-key segment windows (generation bump) when a turn finishes so work that never completed reappears finalized as interrupted instead of silently vanishing from an already-open expansion. - Include `partial` in the turn-row render signature; forward workItemLimit/afterSeq through the SDK so the paging contract isn't accepted-but-ignored there. Efficiency: - Add a partial covering index (thread_id, turn_id, sequence, item_kind) WHERE type='item/completed' — EXPLAIN QUERY PLAN showed the frontier and paging queries doing per-row table seeks (or whole-thread scans for the OFFSET variant) against the existing indexes. Generated via drizzle-kit. - Gate the outline's json_extract fallback to NULL-item_kind rows so typed tool/command events never parse their payloads; include plan items, which also project to assistant text. Cleanup: - Extract the duplicated turn-window event selection pipeline into a shared helper used by both the full-detail and paged paths; fold the pending-row predicates into one type guard; drop a redundant client-side re-sort and simplify the segment row merge to Map semantics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SawyerHood
force-pushed
the
bb/fresh-problem-solution-thr_7rrht6txvp
branch
from
July 16, 2026 22:31
2be3bf5 to
ee850f1
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.
Problem
Very long threads — especially a single agent turn running for hours — became progressively expensive to load and update. The worst sample turn (
thr_n8ptu7bf8f) is 335 minutes / 7,025 events / 27 MB:#711 tried to bound responses by raw row/byte budgets and was reverted in #722 because the cut could fall mid-turn behind a generic "Load older" control. This change keeps that constraint front and center: top-level segment pagination is untouched — a visible response always starts with its initiating user message — and all new bounding happens inside a turn's "Worked for…" section.
What changed
Paged turn work ("Show earlier work")
GET /threads/:id/timeline/turn-summary-detailsgainsworkItemLimit(newest-N page +earlierCursor) andafterSeq(exact catch-up range). Windows resolve from the indexeditem/completedsequence; items straddling a window edge still project fully from their completion payload; paged rows get the timeline's 32 KB output truncation. Omitting both params keeps today's full, un-truncated detail (small turns, CLI).LazyTurnRowBodypages large turns (partial rows, or completed turns above 60 work items) through immutable per-window segment queries with a nested "Show earlier work" control. Expansion shows newest work first; revealed windows are keyed by summary-row id so they survive collapse/expand, live-turn growth, and the completion transition; prepends anchor scroll exactly like "Load older messages".Active-turn frontier collapse ("Worked so far")
partial: true, title "Worked so far (2h 5m)"). Running commands, waiting approvals, unanswered questions, and the most recent ~24–47 finished items stay flat below it.Targeted conversation outline
Measured (copy of the 39 MB sample thread)
Validation
pnpm exec turbo run typecheckacross the repo; full test suites for@bb/server,@bb/thread-view,@bb/db,@bb/app,@bb/server-contract,@bb/cli,@bb/sdk.Follow-up (documented in plans/long-thread-timeline-pagination.md)
🤖 Generated with Claude Code