Skip to content

Coalesce completed turns across timeline byte windows - #2361

Open
ymichael wants to merge 11 commits into
mainfrom
bb/understand-timeline-grouping-thr_e625skpecw
Open

Coalesce completed turns across timeline byte windows#2361
ymichael wants to merge 11 commits into
mainfrom
bb/understand-timeline-grouping-thr_e625skpecw

Conversation

@ymichael

@ymichael ymichael commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

What was wrong

A completed turn can exceed the timeline response byte budget and be projected from several transport windows. Completed-turn row identity was coupled to presentation segmentation: a window containing the accepted user seed or a visible intermediate response could emit :turn:0, while a partial window for the same turn emitted the canonical :turn ID. Clients therefore could not coalesce the fragments and rendered multiple Worked for rows. The first attempted fix also exposed byte-window ranges as the client's detail fetch plan, turning one expansion into a burst of range requests and leaking a storage boundary into the public contract.

What changed

  • A sole work summary within one user exchange now uses the turn's canonical row identity on every byte page. Identity is separate from source bounds, so fragments retain their message-local chronology while clients merge them into one Worked for row.
  • Real exchange boundaries remain segmented: later human messages and external new-turn boundaries still produce distinct summary segments, and intentionally visible assistant responses remain visible.
  • Byte-window detail segments were removed from the public timeline row contract. Main-timeline transport windows are no longer the client's fetch plan.
  • Completed-turn details are now a server-owned, forward-paginated resource. The client supplies a turn ID and follows opaque cursors sequentially; each page is bounded by both the configured event-count budget and the 4 MB stored-event byte budget.
  • Desktop and mobile progressively merge detail pages, including delegated child rows. Exact-range mode remains for full-output hydration, and legacy range URLs are normalized at the server boundary.
  • The plugin SDK patch version is 0.4.17 because the public timeline declaration changed.

The main timeline still deliberately keeps a finished turn whole under the event-count budget; only the byte limit can split its summary transport. Turn-detail pagination applies both limits. No host-daemon wire contract changed, so HOST_DAEMON_PROTOCOL_VERSION is unchanged.

How you verified

The new regression reproduces the old :turn:0 plus :turn split across byte pages and fails before the fix. It now proves that the fragments share one canonical ID while visible responses remain visible. Unit coverage separately proves that the accepted seed is not an internal boundary, later human messages still are, and canonical identity does not widen source bounds.

  • pnpm exec turbo run test --filter=@bb/thread-view --force: 375 tests passed.
  • pnpm exec turbo run test --filter=@bb/server --force: 2,008 tests passed.
  • Turbo typechecks passed for thread-view and server after the final identity change. Earlier branch-wide runs also passed app, mobile, CLI, SDK, server-contract, client-core, and DB test/typecheck suites.
  • A consistent SQLite online backup of the production DB reproduced the original affected turn without running plugins or mutating production. Seven bounded main-timeline pages (148 KiB total JSON) now contain two fragments with the same canonical ID; client coalescing produces exactly one row spanning sequences 7773–14136 with summary count 586. Five warm local runs had a 249 ms median.
  • On that production copy, expansion follows three forward pages with 326, 237, and 23 top-level detail rows. The pages total 5.47 MiB JSON, merge one cross-page duplicate into 585 unique rows, and had a 122 ms median over five warm local runs. The underlying page selection included 1,500, 1,500, and 165 non-noise events, confirming that both the event-count and byte bounds apply.
  • A seeded 508-event, 12.5 MB completed turn still uses four bounded main-timeline byte windows but renders exactly one Worked for 1h 24m 20s row. Expansion follows four opaque-cursor pages and the final UI shows one Ran 250 commands group, nested progress updates, and one terminal response.
  • Live synthetic repro and proof: https://ymichael--17705.getbb.app/projects/proj_jg5wvf42hz/threads/thr_fyxnfvdzaa

Fixes: no filed issue; reproduced from a production thread timeline.

AGENT GENERATED

@ymichael ymichael changed the title Fix timeline grouping across byte windows Coalesce completed turns across timeline byte windows Aug 24, 2026
@ymichael
ymichael marked this pull request as draft August 25, 2026 04:04
@ymichael
ymichael marked this pull request as ready for review August 25, 2026 04:39
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