Repository navigation
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a bounded persistence performance fix that adds seven backward-compatible SQLite indexes and verifies migration idempotence, query plans, and unchanged results. Its production impact is limited to index build/storage and maintenance overhead rather than a behavior or API change. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 134b2e6e96
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| `; | ||
| yield* sql` | ||
| CREATE INDEX IF NOT EXISTS orchestration_v2_projection_runs_user_message_idx | ||
| ON orchestration_v2_projection_runs(json_extract(payload_json, '$.userMessageId')) |
There was a problem hiding this comment.
Guard malformed JSON before building expression indexes
When upgrading a database that contains a malformed run projection, this statement evaluates json_extract for every existing row and SQLite aborts the migration with malformed JSON; Sqlite.ts:39 runs migrations before services start, so the server cannot reach its unreadable-projection handling. This is an explicitly supported recovery case: ProjectionRecovery.test.ts:345-368 stores '{broken' in this table and expects the affected thread to be reported unreadable. Repair or guard invalid payloads before creating this and the analogous turn-item expression index, and cover that upgrade path.
Useful? React with 👍 / 👎.
| SELECT thread_id FROM orchestration_v2_projection_runs | ||
| WHERE json_extract(payload_json, '$.userMessageId') = 'message-1' |
There was a problem hiding this comment.
Drop the index exercised only by the synthetic query
This planner query does not occur in production: a repo-wide search finds the only two $.userMessageId SQL reads at ProjectionStore.ts:4234-4235 and 5140-5144, and both restrict the run by run_id before extracting the field, so the primary-key lookup wins. Consequently this test blesses an expression index that every run.created/run.updated upsert must maintain without accelerating a real read; exercise an actual lookup and drop or reshape the index.
AGENTS.md reference: AGENTS.md:L98-L101
Useful? React with 👍 / 👎.
| CREATE INDEX IF NOT EXISTS orchestration_v2_projection_provider_turns_thread_completed_idx | ||
| ON orchestration_v2_projection_provider_turns(thread_id, completed_at DESC) |
There was a problem hiding this comment.
Remove the unmatched provider-turn completion index
For normal provider-turn updates, this adds a second B-tree with the same useful prefix as the existing orchestration_v2_projection_provider_turns_thread_idx, but a repo-wide search of production SQL finds no provider-turn read that filters or orders on completed_at; those reads use identifiers, thread/status, or provider-thread/ordinal instead. It therefore adds maintenance to every provider-turn.updated upsert at ProjectionStore.ts:2379-2413 without improving a current lookup, so remove it or introduce it only alongside a query whose ordering matches it.
AGENTS.md reference: AGENTS.md:L15-L17
Useful? React with 👍 / 👎.
Problem
Projection reads can scan a long thread's historical turn items and build a temporary B-tree to recover message order, even though the query only needs message items grouped by their JSON message ID. Related: #21578, the accepted report of long-thread SQLite stalls.
Change
Migration 067 adds seven missing access paths for projection and application-event reads: thread/type and thread/message-ID turn items, run/status turn items, running runs, runs by user-message ID, provider turns by thread/completion time, and aggregate/version event sequence. The migration and upgrade expectations use the next free number on main at
67c0fc0cda.I checked the running-only index against the existing
runs_recovery_idxbefore keeping it. On the upstream schema,WHERE status = 'running'scans the runs table; SQLite does not infer the partial recovery index'sstatus IN (...)predicate from that equality. After migration it scans the small covering running-only index. The matchingstatus IN (...) AND thread_id = ?query continues to useruns_recovery_idx.The port excludes the original update-time and message-prefix indexes: their callers were fork-specific maintenance code.
Scope and approval
This is a focused persistence performance fix for missing query access paths, with unchanged query results and a migration regression test. #21578 establishes the accepted long-thread SQLite performance problem. This does not claim to resolve its unfinished-item lookup: open #21585 addresses that predicate. I also checked #21193 (live snapshot cohort indexes), #21777 (thread sweep expressions), #21491 (wire filtering), and #21315 (checkpoint process batching); these seven index definitions do not duplicate those changes.
Verification
macOS arm64, Node v26.7.0,
sqlite_version()3.54.1. Used a private logical DB copy containing one real thread: 11,911 turn items, 8,143 nodes, 203 runs, 1,915 message groups, about 90 MB before the new indexes. Only that thread's projections were copied; application events were omitted. No private records are included here.Compared the same copy with upstream's existing indexes, then with migration 067's seven indexes. No planner statistics. Each query ran once to warm up, followed by 20 measured executions; the table gives medians. This measures SQL lookups, not browser paint or the complete snapshot request.
Building the seven indexes took 60.30 ms on this copy. Full multi-GB migration cost and write-throughput impact were not measured.
The new test checks the migration, a second no-op migration run, message-result equivalence, and the message, user-message run, running-only, and existing recovery query plans.
Model: GPT-6. Harness: Codex.