Repository navigation
fix(server): compact superseded history in the background - #19435
Conversation
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR not approvable — The PR adds default-on background compaction and SQLite page reclamation, including deletion of durable superseded history and changed replay retention behavior. Its persistence and runtime lifecycle impact is broader than a small isolated fix, even with targeted tests covering replay and reclamation. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
2385754 to
cd8a1ef
Compare
Superseded orchestration events (whole-thread state, message and node updates) accumulated for the lifetime of a database; one install reached 114 GB. compactEventStore existed but nothing in the running server called it, and SQLite never returned the freed pages to the filesystem. The new DatabaseStorage service runs compactEventStore six-hourly after startup and hands freed pages back every minute with incremental_vacuum, one page per step so client requests interleave. New databases are created with auto_vacuum = INCREMENTAL; existing files keep their mode until an offline VACUUM converts them. thread.pull-request-link-updated joins the compaction rules, keyed by the link's host/repository/number. No replay boundary is published. Whole-thread events keep only the newest per thread. Keyed entities (messages, nodes, PR links) keep both their oldest and newest event: client reducers append an entity where they first see it, so a replay from any cursor either carries that first event or finds the entity already present, and ordering survives. thread.deleted is never compacted because clients switch on the event type. The scan uses 50-row pages so discovery on the shared connection stays short. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cd8a1ef to
e5cbab0
Compare
|
A Windows data point from a large database, for anyone wondering what this does on an existing install. The fork I run has carried this change since 16 Oct. The numbers below are read-only queries on its The compactor has caught up. By its own rule (keep the oldest and newest event per entity, delete the ones in between), almost nothing is left to delete:
The file did not shrink, as #19436 says it won't. 3,274,887,168 bytes before, 3,299,213,312 now. What is left is mostly turn items. Event payload is 1,077 MB, and No stall visible, with one gap. The pass one minute after the 16:20 UTC restart (about 16:21:20) left no SQL span over 300 ms between 16:21:05 and 16:24:40, and no Not checked: other installs, and what doctor would actually reclaim here. Would a span around each compaction pass (deleted rows and duration as attributes) be welcome, so people with large databases can report the first pass from their trace file? Posted by Claude (Opus 5.5, Claude Code via T3 Code) on behalf of @AdEx-Partners-DE. |
Merges `pingdotgg/t3code` `main` at `3962ae8586` (96 commits since `e536bfd33b`) into the fork. One merge commit; the tracker entry in `docs/fork/upstream-merge-log.md` has the full decision list. ## Conflicts (8) - **`ChatView.tsx`** (`converged`): upstream pingdotgg#19869 replaced `useCallback` with plain functions plus `useStableCallback`. I took upstream's file and re-applied each fork delta in that style: the sandbox start for scripts, the draft-thread create and host-run path in `runProjectScript`, Workspace script saves, the sandbox surface, file retargeting, the announced preview and terminal effects, the sandbox-commands banner, the PR-surface gate and the thread-fork dialog. **This file is the one to review closely.** - **`rightPanelStore.ts`** / **`FilePreviewPanel.tsx`**: the fork's `retargetFile` sits beside upstream's new `navigateFolder` and `folderTrail` (pingdotgg#15045). - **`ci.yml`**: upstream folded the `typecheck` job into `build` (pingdotgg#19633). The Moatless spec check now follows `build`'s final `Typecheck` step. - **`Sidebar.tsx`, `ProjectSettingsPanel.tsx`**: upstream's code plus the fork's additions. - **`index.html`**: kept the Moatless title. Added a `branding-shell` path-policy entry for it and `branding.ts`. - **`source-control-github/package.json`**: took upstream's new `generate` script and kept `tsc --noEmit` (the `tsc-rs` tripwire). - **`pnpm-lock.yaml`**: took upstream's copy, stripped `tsc-rs`, and re-derived it with a real install. Merge stats: 738 files landed against 736 in the upstream range. The one upstream file that didn't land is `index.html`, whose only upstream change was the title. The three extra landed files are fork docs. The fork delta is 815 files. ## Contract - Added `UnsupportedMethodError` to `orchestration.subscribeCommandOutput` and `server.getDatabaseStorage`. Both are new upstream methods Moatless doesn't dispatch. - Moatless now serves 11 more `pullRequests.*` reads (moatless pingdotgg#1161, pingdotgg#1164, pingdotgg#1169). They share `PullRequestRpcError` with methods it still refuses, so the union keeps `UnsupportedMethodError`. The 11 are declared as `pull-requests-*-shared-union` exceptions in `inventory.json`, which retire together once the rest of the family is served. ## Also in this PR `sandboxSurfaces.test.ts` had been red on `main` since `95dcaca54f` made the `pull-request` surface sandbox-independent without updating the test. The test and module doc now match the code. ## Verification Duplicate-adds, tripwires, resolution-check, unsupported-methods, lockfile, format, lint, typecheck and the production build are all green. The full test pass hit its one-hour deadline, so I ran the remaining packages one at a time. These still fail when run alone, in the same files the 2026-10-15 merge logged as sandbox failures: - `shared`: `AgentScope` - `t3`: `ServerBrowserPage`, `AcpAdapterV2` - `provider-opencode`: `OpenCodeServerLedger` - `ssh`: `tunnel.test.ts` `t3`'s `OrchestratorReplayFixtures` `claude_result_is_error` fails only because this sandbox sets `CLAUDE_CONFIG_DIR`; it passes with that unset. Every other package passes. ## Upstream features ### Usable as-is - Folder breadcrumbs navigate to parent folders (pingdotgg#15045). - Chat view, composer and sidebar no longer keep old renders alive (pingdotgg#19869, pingdotgg#19852). - Thread list cache saves without re-encoding every thread (pingdotgg#19915). - React Compiler runs natively (pingdotgg#20114). - Linked pull requests are virtualized (pingdotgg#20107). - A linked PR can be dragged into the composer as a context chip (pingdotgg#20102). - HTML renders show a skeleton and open images in the image viewer (pingdotgg#19654, pingdotgg#20036). - Model picker search lists the newest models first (pingdotgg#18494). - Wrapped split diffs stop jumping while scrolling (pingdotgg#20022). - Text selection continues under the turn minimap (pingdotgg#16748). - Sent queued messages say "from queue" (pingdotgg#19849). - Settings stay compact with many connected machines (pingdotgg#19744). - Middle-click and a setting to open PR links on GitHub (pingdotgg#19854, pingdotgg#19719). - Text generation no longer falls back to the flagship model (pingdotgg#19722). - Pending context handoff is hidden on threads with no sent message (pingdotgg#20033). - Mobile and desktop changes don't affect the fork's web client. - Not taken: the Beta branding (pingdotgg#20032). ### Unsupported in Moatless / needs implementation - **Live command output** (pingdotgg#15094): `orchestration.subscribeCommandOutput`, shown in `CommandOutputPanel.tsx` behind `capabilities.commandOutputStreaming`. Covered by the new union entry. - **Database storage notice and `t3 doctor` reclaim** (pingdotgg#19436, pingdotgg#19437): `server.getDatabaseStorage`, shown in `DatabaseStorageNotice.tsx` behind `capabilities.databaseStorage`. Covered by the new union entry. - **Delete a branch after its PR merges or closes** (pingdotgg#19257): a `pullRequests.runAction` option. The action is refused here. - **Device setup through a remote device host only** (pingdotgg#20077): behind `FEATURES.deviceHub`. ### Backend behavior to consider reproducing in Moatless - Resumed Claude subagents keep updating their own thread and pick up the parent's renamed worktree branch (pingdotgg#20061, pingdotgg#20079). - Steering no longer ends running subagents (pingdotgg#19210). - Worktrees shared by subagents are cleaned up, and orphaned ones are reported (pingdotgg#19748, pingdotgg#19749). - Superseded history is compacted in the background (pingdotgg#19435). - A run whose provider stream ends without a terminal event fails instead of hanging (pingdotgg#19131). - One malformed ACP session update no longer ends the session (pingdotgg#20015). - A dropped HTTP/2 connection no longer crashes the server (pingdotgg#18378). - PR refreshes are bounded by tracker reads (pingdotgg#19403). - Cursor threads in Auto use Cursor's Auto-review (pingdotgg#19712). - Grok health checks no longer start its updater (pingdotgg#18075). - Expanding a wide ignored folder no longer classifies every child (pingdotgg#20062). - OTLP exports name the machine and build they came from (pingdotgg#19370). Recorded in `docs/fork/gaps.md` under "Runtime fixes upstream made to its own server". 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- Moatless task: https://moatless.soaplabstest.com/tasks/d6f425f2-8234-412e-8189-1c71b309c04a
…king (#175) T3 Code's history compaction (pingdotgg/t3code#19435, nightly and preview builds since Oct 15) deletes events that a newer event of the same thread supersedes. When the event the lifecycle reader saved as its anchor was one of them, every later reconcile threw "source history changed" and lifecycle state stayed frozen until repaired by hand. A missing anchor now counts as a deletion when its event id appears nowhere in the table; the id at another sequence, a different event at the saved sequence or a lower watermark still fail as a rewrite. event_id is unique in T3's event tables, so the lookup is indexed and runs only when the anchor is missing. Docs: orchestration_events is the event table for T3 0.1.0 and later; one non-GitHub link makes pr-sessions exit 1 for the project; Muse and Pi are listed with what Swarmail does for them today.
The server never deleted superseded orchestration history, so databases grow without bound. One maintainer database reached 114 GB, most of it repeated whole-payload updates of the same thread, message, node or PR link.
The server now runs
compactEventStoreone minute after startup and every six hours after that. Each pass deletes events whose state a newer retained event already carries:thread.created,thread.deleted, runs and turn items are never compacted.No replay boundary or snapshot fallback is needed: every deleted row has a newer row for the same key, so any replay from an older cursor still ends in the same state and order.
New databases are created with
auto_vacuum = INCREMENTAL, and the server returns freed pages to disk online in small yielding batches. Existing databases get that witht3 doctor(#19436). Compaction pages are 50 rows, because a 500-row page with large payloads blocked the shared connection for ~90 ms.A retried MCP metadata update whose events were compacted now answers from the current thread instead of failing.
Takes over #19249.
🤖 Generated with Claude Code
Fixes #18559