Repository navigation
fix(native-chat): remove superseded chat history rows and return their space - #36053
AmoabaKelvin merged 133 commits into
Conversation
Publish versioned reducer checkpoints atomically, checkpoint through the chat write queue, and backfill closed chats without retiring journal rows. Co-Authored-By: Codex <noreply@openai.com>
Delete fully superseded item and lifecycle rows inside the paced checkpoint job, retain first/latest cursor touches and current witnesses, and reclaim incremental-vacuum pages. Allow catch-up to cross retired prefix rows. Co-Authored-By: Codex <noreply@openai.com>
[Medium impact] The PR appears safe to merge; no actionable new issues were found. SummaryThis PR removes old chat revisions covered by saved state and returns freed space on databases that support it.
No actionable new issues were found. No previous review threads were supplied. Tests were inspected but not run.
|
…' into brennanb2025/bug-native-chat-journal-grows-to-20-gib-request # Conflicts: # src/main/native-chat/agent-session-journal/journal-state-backfill.ts
…er it is frozen The fold comment claimed an unheld prefix-ordinal value only moves that key; a prefix read differently can also show a key twice or bring back one the tail deleted. The marker version now states the rule: a build that reads old rows into different keys or values keys that reading off a new marker version, and duplication or resurrection is never intended.
…elds this build adds The open check compared whole snapshots, so a field main starts setting would fail the required cross-version job until a release ships it. It now compares the release's items, sends and cards, in order and by value, allowing added fields; the byte-identity and restore-equals-live checks are unchanged.
…edundant union member
…thout parsing or walking it again or keeping its text
…batch's encode stays linear in its mutations
…hrough the draft's tracking
…ements and work linear in what they restate
There was a problem hiding this comment.
Actionable comments posted: 1

Review info
-
Run configuration-
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
a6a2f4d5-bed5-4e89-af96-c7fdb4748fca
Files selected for processing: 197-
config/flaky-test-pattern-baseline.txtsrc/main/acp/acp-structured-host-restore-failed.test.tssrc/main/acp/acp-structured-launch-resolution.test.tssrc/main/acp/acp-structured-unknown-window-usage.test.tssrc/main/codex/codex-structured-journal-settlement-rollback.test.tssrc/main/codex/codex-structured-journal-translation-turn-lifecycle.test.tssrc/main/codex/codex-structured-thread-catch-up-echo.spec.tssrc/main/codex/codex-structured-thread-catch-up.test.tssrc/main/codex/codex-thread-catch-up-contract-test-fixture.tssrc/main/codex/codex-thread-catch-up-rewind.test.tssrc/main/codex/codex-turn-lifecycle-completion.test.tssrc/main/codex/codex-turn-lifecycle-contract-test-fixture.tssrc/main/codex/codex-turn-lifecycle-history.test.tssrc/main/jsonl-rpc/timeline-lane.test.tssrc/main/native-chat/agent-session-journal/__fixtures__/journal-input-prefix.jsonsrc/main/native-chat/agent-session-journal/__fixtures__/journal-outcome-format-1-values.jsonsrc/main/native-chat/agent-session-journal/__fixtures__/journal-outcome-format-1.jsonsrc/main/native-chat/agent-session-journal/journal-approval-revision-validation.spec.tssrc/main/native-chat/agent-session-journal/journal-atomic-settlement-contract-test-fixture.tssrc/main/native-chat/agent-session-journal/journal-atomic-settlement-oversized.spec.tssrc/main/native-chat/agent-session-journal/journal-atomic-settlement-rollback.spec.tssrc/main/native-chat/agent-session-journal/journal-atomic-terminal-settlement.spec.tssrc/main/native-chat/agent-session-journal/journal-compaction-scaling.test.tssrc/main/native-chat/agent-session-journal/journal-cursor.tssrc/main/native-chat/agent-session-journal/journal-damage.test.tssrc/main/native-chat/agent-session-journal/journal-database.tssrc/main/native-chat/agent-session-journal/journal-epoch-controller.tssrc/main/native-chat/agent-session-journal/journal-epoch-replacement-contract-test-fixture.tssrc/main/native-chat/agent-session-journal/journal-epoch-replacement-receipts.spec.tssrc/main/native-chat/agent-session-journal/journal-epoch-replacement.spec.tssrc/main/native-chat/agent-session-journal/journal-epoch-replacement.tssrc/main/native-chat/agent-session-journal/journal-epoch-rollover.tssrc/main/native-chat/agent-session-journal/journal-host-database-test-support.tssrc/main/native-chat/agent-session-journal/journal-host-database.spec.tssrc/main/native-chat/agent-session-journal/journal-host-database.tssrc/main/native-chat/agent-session-journal/journal-incremental-vacuum.tssrc/main/native-chat/agent-session-journal/journal-item-provenance.spec.tssrc/main/native-chat/agent-session-journal/journal-lifecycle-batch-appender.spec.tssrc/main/native-chat/agent-session-journal/journal-lifecycle-boundaries.spec.tssrc/main/native-chat/agent-session-journal/journal-mixed-epoch-replacement.test.tssrc/main/native-chat/agent-session-journal/journal-open.tssrc/main/native-chat/agent-session-journal/journal-outcome-cleanup.tssrc/main/native-chat/agent-session-journal/journal-outcome-codec.tssrc/main/native-chat/agent-session-journal/journal-outcome-compaction.test.tssrc/main/native-chat/agent-session-journal/journal-outcome-compaction.tssrc/main/native-chat/agent-session-journal/journal-outcome-format-1-decode.tssrc/main/native-chat/agent-session-journal/journal-outcome-format-1.test.tssrc/main/native-chat/agent-session-journal/journal-outcome-format-1.tssrc/main/native-chat/agent-session-journal/journal-outcome-format.tssrc/main/native-chat/agent-session-journal/journal-outcome-scaling.test.tssrc/main/native-chat/agent-session-journal/journal-outcome-sweeper.test.tssrc/main/native-chat/agent-session-journal/journal-outcome-table.tssrc/main/native-chat/agent-session-journal/journal-outcome-wire.test.tssrc/main/native-chat/agent-session-journal/journal-outcome-write.tssrc/main/native-chat/agent-session-journal/journal-projection-bootstrap.test.tssrc/main/native-chat/agent-session-journal/journal-projection-failure.test.tssrc/main/native-chat/agent-session-journal/journal-projection-streams.test.tssrc/main/native-chat/agent-session-journal/journal-projection-test-support.tssrc/main/native-chat/agent-session-journal/journal-read-row.tssrc/main/native-chat/agent-session-journal/journal-received-content.test.tssrc/main/native-chat/agent-session-journal/journal-reducer-transition.tssrc/main/native-chat/agent-session-journal/journal-row-context-usage.spec.tssrc/main/native-chat/agent-session-journal/journal-row-schema-version.spec.tssrc/main/native-chat/agent-session-journal/journal-row-schema.test.tssrc/main/native-chat/agent-session-journal/journal-row-schema.tssrc/main/native-chat/agent-session-journal/journal-row-table.tssrc/main/native-chat/agent-session-journal/journal-row-writer.tssrc/main/native-chat/agent-session-journal/journal-saved-state.test.tssrc/main/native-chat/agent-session-journal/journal-sequence-replay.spec.tssrc/main/native-chat/agent-session-journal/journal-state-codec.tssrc/main/native-chat/agent-session-journal/journal-state-layout.tssrc/main/native-chat/agent-session-journal/journal-state-schema.tssrc/main/native-chat/agent-session-journal/journal-storage-admission.test.tssrc/main/native-chat/agent-session-journal/journal-storage-row-schema.tssrc/main/native-chat/agent-session-journal/journal-storage-schema.tssrc/main/native-chat/agent-session-journal/journal-storage-strict.tssrc/main/native-chat/agent-session-journal/journal-store-collaborators.tssrc/main/native-chat/agent-session-journal/journal-store-contract-test-fixture.tssrc/main/native-chat/agent-session-journal/journal-store-contracts.tssrc/main/native-chat/agent-session-journal/journal-store-restore.tssrc/main/native-chat/agent-session-journal/journal-store-schema.spec.tssrc/main/native-chat/agent-session-journal/journal-store.spec.tssrc/main/native-chat/agent-session-journal/journal-store.tssrc/main/native-chat/agent-session-journal/journal-streamed-revision-contract-test-fixture.tssrc/main/native-chat/agent-session-journal/journal-streamed-revision-resolved-lifecycle.test.tssrc/main/native-chat/agent-session-journal/journal-streamed-text-revision.test.tssrc/main/native-chat/agent-session-journal/journal-terminal-settlement-validation.spec.tssrc/main/native-chat/agent-session-journal/journal-terminal-time-validation.spec.tssrc/main/native-chat/agent-session-journal/journal-terminal-validation-test-fixture.tssrc/main/native-chat/agent-session-journal/journal-transition-collections.tssrc/main/native-chat/agent-session-journal/journal-unknown-content.spec.tssrc/main/native-chat/agent-session-journal/journal-unknown-row-kind.spec.tssrc/main/native-chat/agent-session-journal/journal-unsent-send-hold-contract-test-fixture.tssrc/main/native-chat/agent-session-journal/journal-unsent-send-hold-queue.spec.tssrc/main/native-chat/agent-session-journal/journal-unsent-send-hold-recovery.spec.tssrc/main/native-chat/agent-session-journal/journal-unsent-send-hold.spec.tssrc/main/native-chat/agent-session-journal/journal-write-projection.tssrc/main/native-chat/agent-session-journal/queued-message-pause-contract-test-fixture.tssrc/main/native-chat/agent-session-journal/queued-message-pause-held-cards.spec.tssrc/main/native-chat/agent-session-journal/queued-message-pause.spec.tssrc/main/native-chat/agent-session-journal/queued-message-reopen-pause.spec.tssrc/main/native-chat/agent-session-journal/queued-message-stop-pause.spec.tssrc/main/native-chat/agent-session-journal/queued-message-stored-row.tssrc/main/native-chat/agent-session-wire/agent-session-history-batches.test.tssrc/main/native-chat/agent-session-wire/agent-session-history-byte-limits.test.tssrc/main/native-chat/agent-session-wire/agent-session-history-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/agent-session-history-large-identities.test.tssrc/main/native-chat/agent-session-wire/agent-session-history-page.test.tssrc/main/native-chat/agent-session-wire/agent-session-journal-batch.tssrc/main/native-chat/agent-session-wire/agent-session-stop-note-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/agent-session-stop-note-paging.test.tssrc/main/native-chat/agent-session-wire/agent-session-stop-note-projection.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-actionable-prompts.tssrc/main/native-chat/agent-session-wire/structured-agent-session-append-delivery.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-contract-test-actions.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-ends-session.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-plan-card.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-queue-cards.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-clear-rewind.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversations.tssrc/main/native-chat/agent-session-wire/structured-agent-session-create-adoption-budget.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-create-adoption-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-create-adoption-restart.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-create-adoption.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-current-work.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.tssrc/main/native-chat/agent-session-wire/structured-agent-session-late-settlement-cancelled.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-late-settlement-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-late-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-leftover-settlement.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-context.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-newer-content-host.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-prompt-cancel.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queue-import-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queue-import-retained-history.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queue-import-reuse.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queue-import-scaling.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-legacy-import.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-legacy-journal.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-refused-card.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-failure-filing.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-interruption-test-harness.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-offer-newer-orca.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-ownership.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-resume-progress.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-options.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stale-turn-verdict.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stale-verdict-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stale-verdict-persistence.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stale-verdict-prompts.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-event.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-receipts.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subscriber-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subscriber-oversized-removal.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subscriber-publication.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subscribers.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-transition-contract-test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-transition-rollback.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-transition.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-unopened-tab.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-wire-admission.test.tssrc/main/runtime/orchestration/structured-worker-journal-page.test.tssrc/main/runtime/rpc/methods/orchestration/worker-start-card-contract-test-fixture.tssrc/main/runtime/rpc/methods/orchestration/worker-start-card-operations.test.tssrc/main/runtime/rpc/methods/orchestration/worker-start-card-population.test-fixture.tssrc/main/runtime/rpc/methods/orchestration/worker-start-card-scenario.test-fixture.tssrc/main/runtime/rpc/methods/orchestration/worker-start-card.test.tssrc/main/runtime/rpc/methods/structured-agent-session-at-rest-context.test.tssrc/main/runtime/rpc/methods/structured-agent-session-at-rest-lease.test.tssrc/main/runtime/rpc/methods/structured-agent-session-at-rest-options.test.tssrc/main/runtime/rpc/methods/structured-agent-session-at-rest.test.tssrc/main/runtime/rpc/methods/structured-agent-session-rest-contract-test-fixture.tssrc/main/runtime/structured-agent-runtime-registrations.tssrc/main/runtime/structured-agent-session-attachment-wiring.test.tssrc/main/runtime/structured-agent-session-attachment-wiring.tssrc/main/runtime/structured-agent-session-codex-interrupt-order.test.tssrc/main/runtime/structured-agent-session-codex-settlement-order.test.tssrc/main/runtime/structured-chat-dispatch-worker-lifecycle.test.tssrc/main/sqlite/sqlite-read-failure.tssrc/shared/agent-session-journal-open-union.tssrc/shared/agent-session-journal-schemas.tssrc/shared/wsl-move/wsl-move-storage-dispositions.tstests/e2e/cross-version-wire/agent-session-interrupted-tool-downgrade.unit.test.tstests/e2e/cross-version-wire/agent-session-newer-chat-refusal.unit.test.tstests/e2e/cross-version-wire/agent-session-outcome-chat-downgrade.unit.test.tstests/e2e/cross-version-wire/agent-session-stop-event-downgrade.unit.test.tstests/e2e/cross-version-wire/cross-version-stop-note-scenarios.tstests/e2e/cross-version-wire/kept-card-downgrade.unit.test.tstests/e2e/cross-version-wire/release-checkout.tstests/e2e/cross-version-wire/released-chat-continuation.tstests/e2e/cross-version-wire/released-chat-queue.tstests/e2e/cross-version-wire/released-chat-upgrade.unit.test.tstests/e2e/cross-version-wire/released-chat-writers.tstests/e2e/journal-restored-consumers.unit.test.ts
Files with no reviewable changes: 2-
- src/main/native-chat/agent-session-wire/structured-agent-session-prompt-cancel.test.ts
- src/main/native-chat/agent-session-wire/structured-agent-session-newer-content-host.test.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.
-
| const close = releaseModuleExport<(stateDirectory: string) => void>( | ||
| support, | ||
| 'closeTestJournalHostDatabase' | ||
| ) |
There was a problem hiding this comment.
Await the release's closeTestJournalHostDatabase before you read the database.
The current closeTestJournalHostDatabase is async. It awaits the checkpoint close and then closes the connection. These lines type the release export as (stateDirectory: string) => void and do not await it. If the release's closeAll() leaves that handle open, the close runs concurrently with the next steps. In the first test, databaseBytes() hashes the .db and -wal files while the connection can still checkpoint or truncate the WAL. The byte-equality assertion can then fail intermittently. In the second test, this build's openTestJournalHostDatabase can open the file while the release's connection is still open.
If a release returns void, awaiting it is still harmless. Type the export as returning void | Promise<void> and await each call.
Proposed fix
-
- const close = releaseModuleExport<(stateDirectory: string) => void>( + const close = releaseModuleExport<(stateDirectory: string) => void | Promise<void>>( support, 'closeTestJournalHostDatabase' ) ... await older.closeAll() - close(directory) + await close(directory) ... - releaseModuleExport<(stateDirectory: string) => void>( + await releaseModuleExport<(stateDirectory: string) => void | Promise<void>>( support, 'closeTestJournalHostDatabase' )(directory)
Also applies to: 199-199, 284-287
…ve-chat-journal-grows-to-20-gib-request # Conflicts: # src/main/native-chat/agent-session-journal/journal-storage-admission.test.ts
… prefix lacks Cleanup never deletes a key's newest record or touches the input prefix, so it needs no new reader check. Refusing the whole chat over one such key reversed main's deliberate append fallback and is out of this change's scope.
… checks that cannot fail
Resolve import conflicts from main's module moves. #37216 stopped the journal sink refusing writes under backpressure, so drop the tests that forced a sink refusal and keep one that proves a time-gated tail is saved before an incoming stream evicts it. Move the scheduled plan owner check out of codex-structured-session-acquire.ts to stay under its line cap.
|
This merged before its review finished. The review loop's last verdict was not ready. These things are still open: 1. Cleanup freezes the app on large journals (must fix before this ships in a release). Tracked in STA-13374. 2. Not yet tested on the merged code.
3. Related, tracked separately.
The prefix-position check removed in 3415066 is fine to leave out. Cleanup never deletes the newest copy of anything, so this PR doesn't need it. |
…urn their space (stablyai#36053)" This reverts commit 2a5ec2b.
ELI5
Every time an agent revised a message or a plan, Native Chat saved another full copy of it and never threw the old copies away. One user's chat database reached about 20 GiB. Orca now deletes the copies nothing reads any more, a little at a time in the background, and gives the space back to the disk.
What Changed
Before: since #36024, each chat change is saved as keyed records. A key's newest record is what a chat opens from, and every older revision stays on disk forever. A busy chat streams dozens of revisions per message, so the file keeps growing.
After: the existing background sweeper (a minute after launch, then every six hours, at a 10% duty cycle) runs three bounded steps:
journal-outcome-compaction.ts). For each key it keeps the first record, the newest record, and every removal record (tombstones, removed turns, deleted values), and deletes the revisions in between. Each page is one transaction over at most 32 records and reads no saved content;incremental_vacuum(32)pages (journal-incremental-vacuum.ts), so the file shrinks on databases created with incremental auto-vacuum, which every journal database has been since feat(native-chat): one structured-chat journal database per host, owned by one process #23613. A database without it keeps its size and reuses the freed pages for later saves.Cleanup reads each record's own format declaration and understands both formats Orca writes today, including the native input and queue records added since #36024. An unknown format or field stops cleanup for that chat at that record, so nothing at or after it is deleted. Later healthy chats are still cleaned.
Design decisions kept from the original PR:
Changed in the takeover:
1bf4ca375fb. Cleanup never touches the prefix or a key's newest record, so it doesn't need the stricter reader, and reverting keeps the reader identical to main's.Phone and paired-client messages are unchanged.
Why
The saved format already stores whole values per key, so the middle revisions are redundant for every reader. Deleting them in small paced pages fixes the growth without blocking a send or a chat open and without migrating anything. Keeping the first record per key preserves what a #36024-only reader needs. Stopping at the first unknown record keeps a newer build's data safe from an older build's cleanup.
Linked Issue
Part of #34916. This stops the growth for everything saved since #36024. History saved before #36024 stays as it is (the 10-30 decision), so a file that is already large, like the reporter's, shrinks only by what was saved after upgrading.
Visual Proof
N/A: nothing visible changes. Chats open, page history and render exactly as before; only the database file gets smaller.
Testing
Reporter-scale run (macOS, this head, shared machine at load 5–18). I generated 310 chats with 2,565,165 changes (#34916 has 310 sessions and 2,578,668 rows) through the real writer: streamed assistant messages and tool calls, cloned by SQL into a skewed mix of small and very large chats.
#36024's own reader and writer on cleaned data. I ran these on a checkout of the #36024 merge commit (
2cc33b8d898):restoreJournalread identical state and rendered items for every chat, before and after cleanup.Focused tests. Compaction, compaction scaling, storage admission, projection bootstrap and streams, outcome scaling and wire, sweeper, mixed-epoch replacement, checkpoint integration and attachment wiring all pass, plus changed-file oxlint and oxfmt. Test audit changes:
Risk
The riskiest part is deleting saved data. A wrong keep rule would lose part of a chat's history.
Level: Medium
AI Disclosure
Review
Two review rounds (Codex plus a Claude reviewer), each with no P0 or P1.
Agent skill upstream boundary
Notes
Ensure no issues in: Security, Cross-platform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)