You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Shell snapshot reads on main: app open 7 s, t3_thread_list 10 s, a worktree check on 2 threads 1.8 s #36139
On main at a044f0c0b3, the shell snapshot is slow on our database in every shape its callers use, not only the full read. Setup as in #36127: a block clone of our 49 GB statev2.sqlite, read through the real ProjectionStore, read-only, second of two passes. The clone has 7,524 threads, 3,454 active and 4,070 archived. Thread A has 7,352 runs.
Caller
Read
Time
App open: /api/orchestration/shell or the socket snapshot, with both client trims
The thread-row filters read payload JSON.selectShellThreadRows filters archivedAt, worktreePath, settledAt and lineage.rootThreadId with json_extract. Each of these reads therefore scans all 7,524 payloads (34 MB). The 2-thread worktree read spends all of its 1.75 s in this statement. For the 3,454 active threads the statement takes 5.0–5.4 s. perf(server): active thread reads filter on the archived_at column #28992 adds a column for archivedAt only.
The item counts read every run's table row.selectShellItemCounts joins orchestration_v2_projection_runs on run_id only to read status. For thread A in the sqlite3 CLI the statement took:
1.28 s as written;
0.03 s summing the counts without the join;
0.08 s with the same join through an index on (run_id, status).
This statement is 1.0 s of the 2-thread batch, 2.9 s of app open and 6.0 s of the full read.
The shell index reads every payload.listActiveShellIndex filters on archivedAt in the payload. It then extracts eight more JSON fields and runs two subqueries for each active thread. That takes 2.7 s before app open reads any shell.
Our build reads run status in the count through a (run_id, status) index, and filters archived threads on an archived_at column. We have no fix for the other JSON filters.
Measured and written by Claude (Opus 5.5) in T3 Code; posted with the owner's approval.
I checked #36146 on the database from this issue: a block clone of our 49 GB statev2.sqlite, opened read-only. Reads went through the real ProjectionStore. "Before" is 2d8a843e6b^ and "after" is 2d8a843e6b, with migration 089's indexes. Both were run back to back, and each time is from the second of two passes.
The item-count query dropped from 6.0 s to 0.1 s. Most of what remains is the shell row statement. For the 3,454 active threads it takes 5.2 s.
I timed each of its columns separately, over the same FROM and WHERE:
Column
Time
presented run join (any of its columns)
1.6–2.0 s
latest_user_authored_message_at
2.1 s
latest_user_message_at
0.9 s
payload_json
0.9 s
forked_from_run_source_thread_id
0.8 s
last_error
0.6 s
Every other column
under 0.1 s
No single thread explains this. The presented lookup takes at most 1 ms on any thread, so these costs grow with the number of threads in the read, not with history.
There is one outlier. latest_user_authored_message_at takes 244 ms on a thread with 7,120 user messages: it walks back through agent-authored messages until it reaches one written by the user.
Measured and written by Claude (Opus 5.5) in T3 Code; posted with the owner's approval.
Activity
Dropje97 commentedon Nov 13, 2026
I checked #36146 on the database from this issue: a block clone of our 49 GB
statev2.sqlite, opened read-only. Reads went through the realProjectionStore. "Before" is2d8a843e6b^and "after" is2d8a843e6b, with migration 089's indexes. Both were run back to back, and each time is from the second of two passes.{worktreePath}){threadIds})listActiveShellIndext3_thread_list(active)getShellSnapshot()The item-count query dropped from 6.0 s to 0.1 s. Most of what remains is the shell row statement. For the 3,454 active threads it takes 5.2 s.
I timed each of its columns separately, over the same FROM and WHERE:
presentedrun join (any of its columns)latest_user_authored_message_atlatest_user_message_atpayload_jsonforked_from_run_source_thread_idlast_errorNo single thread explains this. The
presentedlookup takes at most 1 ms on any thread, so these costs grow with the number of threads in the read, not with history.There is one outlier.
latest_user_authored_message_attakes 244 ms on a thread with 7,120 user messages: it walks back through agent-authored messages until it reaches one written by the user.Measured and written by Claude (Opus 5.5) in T3 Code; posted with the owner's approval.