diff --git a/packages/db/src/data/events.ts b/packages/db/src/data/events.ts index 85af19d14..35e8bbcce 100644 --- a/packages/db/src/data/events.ts +++ b/packages/db/src/data/events.ts @@ -1917,20 +1917,25 @@ export function listTodoSnapshotEventRowsForThread( "item/completed", ] satisfies ThreadEventType[]; - const rows = db - .select(storedEventRowFields) - .from(events) - .where( - and( - eq(events.threadId, args.threadId), - inArray(events.type, itemTypes), - eq(events.itemKind, "toolCall"), - sql`json_extract(${events.data}, '$.item.tool') IN ( - 'TodoWrite', 'TaskCreate', 'TaskUpdate', 'TaskList', 'TaskGet' - )`, - ), - ) - .all(); + // Issue #1131 experiment: pin the tiny partial expression index (created + // manually in the seeded db for the experiment) and spell the predicate as + // literals so SQLite can prove the partial-index WHERE clause. + const rows = db.all(sql` + SELECT ${events.createdAt} AS "createdAt", ${events.data} AS "data", ${events.id} AS "id", + ${events.itemId} AS "itemId", ${events.itemKind} AS "itemKind", + ${events.providerThreadId} AS "providerThreadId", ${events.scopeKind} AS "scopeKind", + ${events.sequence} AS "sequence", ${events.threadId} AS "threadId", + ${events.turnId} AS "turnId", ${events.type} AS "type" + FROM ${events} INDEXED BY events_todo_snapshot_idx + WHERE ${events.threadId} = ${args.threadId} + AND ${events.type} IN ('item/started', 'item/completed') + AND ${events.itemKind} = 'toolCall' + AND json_extract(${events.data}, '$.item.tool') IN ( + 'TodoWrite', 'TaskCreate', 'TaskUpdate', 'TaskList', 'TaskGet' + ) + ORDER BY ${events.sequence} + `); + void itemTypes; // Ordering in SQL makes SQLite prefer the thread/sequence index and read every // event in the thread to satisfy the sort; the type/item-kind index visits