Retain large completed event outputs in sidecars - #2918
Closed
ymichael wants to merge 2 commits into
Closed
Conversation
Collaborator
Author
|
Superseded by #2920 at the user’s request. PR #2920 now targets |
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.
Human comments
What was wrong
Completed command and tool outputs were stored inline in
events.data, so every ordinary timeline/event-row scan had to read and transform large values even though the normal product surface only renders a bounded preview. The existing delayed truncation sweep eventually reduced old rows, but new large completions still imposed their full materialization and main-event-loop cost throughout the retention window, while there was no separate short-lived source from which explicit raw/detail reads or event copies could recover the complete value.What changed
item/completedoutputs forcommandExecution.aggregatedOutput,toolCall.result, andwebFetch/webSearch.resultTextnow store a 2 KiB head + 2 KiB tail preview in the ordinary event row and the full string in a one-row-per-event sidecar for seven days. The existing 32 KiB eligibility threshold and retention constants are shared with the current storage policy.(expires_at, event_id)and deletes one sidecar per periodic retention tick. It never rewrites or deletes the ordinary event preview. Hydration uses bounded batches of 100 IDs and the event-ID primary key.RetainedEventOutputTargetand the authoritative four-entryRETAINED_EVENT_OUTPUT_TARGETSare exported from the local data module for the separately scoped legacy-migration work, without expanding the root@bb/dbAPI.0113_graceful_mojo.sqland its snapshot from currentorigin/main; the migration only creates the sidecar and expiry index and does not migrate legacy inline values.No host-daemon wire contract changed. This deliberately excludes legacy inline-output migration, destroyed-environment cleanup, watchers, outlines, timeline projection redesign, and background workers; all measured and production code remains synchronous on the Node main event loop.
How you verified
The focused regressions were run red before their implementation and green afterward: the storage integration initially found the full value in
events.data; uncapped timeline, raw-event, and detail reads initially returned the retained preview; copying initially lost the full value; and the periodic sweep initially left the expired sidecar in place.pnpm exec turbo run test --filter=@bb/db --force— 32 files, 450 tests passed, including in-memory SQLite storage/copy/expiry integration, the direct migration preservation/FK/index test, historical migration rewinds, and query-plan assertions for hydration selection, expiry selection, and primary-key deletion.pnpm exec turbo run test --filter=@bb/server -- --run test/services/threads/timeline-in-turn-window.test.ts test/public/public-thread-timeline-output-preview.test.ts test/services/periodic-sweeps.test.ts— 3 files, 42 tests passed.pnpm exec turbo run typecheck --filter=@bb/db --filter=@bb/server— passed.pnpm exec turbo run build --filter=@bb/db --filter=@bb/server— passed (@bb/serverbuilt;@bb/dbhas no build task).git diff --checkandorigin/main...HEADscope inspection — clean, 17 files, only this PR.Controlled same-machine benchmark
The deterministic production-shaped fixture has 95 event rows over 12 turns (11 completed, one running), including 72 completed 65,536-character outputs (4,718,592 output characters). Reads used 12 warmups + 60 measured iterations; writes used eight warmups + 40 measured immediate transactions of four large completions. Both revisions ran the byte-identical harness (SHA-256
16f0062baf584b30dde86e3777289b763bacec01ddd8b105c819c2175414dc07) on the same arm64 macOS host under Node v22.23.1, with separate disposable SQLite databases and the repository's production WAL/cache/mmap settings. Percentiles use nearest rank.Bounded event/timeline selection held row/work counts at 95/6 while selected/materialized event data fell from 2,327,734 to 331,678 bytes (85.8% less); the timeline response fell from 198,652 to 31,480 bytes. Raw reads materialized 95 rows / 4,755,746 bytes / 4,718,592 output chars on both revisions. Detail reads materialized six work rows / 396,190 bytes / 393,216 output chars on both. Fixture event-row data fell from 4,739,518 to 331,678 bytes; the branch sidecar held 72 rows / 4,718,592 bytes, and the checkpointed DB grew from 5,414,912 to 5,771,264 bytes (6.6%) while both full and preview values coexist.
Raw, detail, and written full-output hashes exactly matched their deterministic expected hashes on both revisions (
dc1df...40a0,4b640e...68cb,e88059...35cf). Bounded timeline identity hashes also matched (7e5f41...fb5a); preview hashes intentionally differ because the branch returns the storage contract's head-and-tail preview instead of the old prefix-only SQL cap.Raw BB thread-storage artifacts: comparison, origin/main JSON, branch JSON, byte-identical harness, and SHA-256 manifest. They are also browsable from the BB benchmark thread.
Fixes: no linked issue.