perf(claude): look up retained prompts' turns in one journal pass during catch-up (#36127)

Catch-up scanned the whole chat journal once per retained prompt. Index prompt-to-turn matches once per reader, the same way the reader already indexes local prompts, keeping every match as a commit dependency in journal order.

Tracked in STA-12049.
This commit is contained in:
Brennan Benson
2026-10-29 17:05:06 -07:00
committed by GitHub
parent fdfe1e5a09
commit a88581d8d5
2 changed files with 23 additions and 14 deletions
@@ -477,7 +477,7 @@ describe('Claude chat catch-up', () => {
expect(c.warn).not.toHaveBeenCalled()
})
// P saved aliases plus P unacknowledged queued prompts: P×J scope work and one J-item index.
// P saved aliases plus P unacknowledged queued prompts: two J-item indexes, not P×J scans.
it.each([10, 100].flatMap((prompts) => [1_000, 10_000].map((items) => ({ prompts, items }))))(
'bounds retained-leaf work for $prompts aliases and local misses over $items journal items',
async ({ prompts, items }) => {
@@ -569,8 +569,7 @@ describe('Claude chat catch-up', () => {
expect(c.journal.canonicalItemId(alias)).toBe(canonical)
expect(committed).not.toHaveBeenCalled()
expect(c.warn).not.toHaveBeenCalled()
expect(associationVisits).toBeGreaterThan(prompts * itemCount)
expect(associationVisits).toBeLessThanOrEqual((prompts + 1) * itemCount)
expect(associationVisits).toBeLessThanOrEqual(2 * itemCount)
expect(viewVisits).toBeLessThanOrEqual(2 * itemCount)
console.info('retained-leaf operation counts', {
prompts,
@@ -15,6 +15,7 @@ export function createClaudeTranscriptItemReader(
) {
const dependencies = new Map<string, AgentJournalRenderItem>()
let localPrompts: Map<string, string> | undefined
let promptTurns: Map<string, string[]> | undefined
const saved = (key: string) => {
const held = dependencies.get(key)
if (held) {
@@ -63,19 +64,28 @@ export function createClaudeTranscriptItemReader(
const scope = scopeOf(item)
return scope.kind === 'turn' ? scope : undefined
}
let scope: AgentJournalTurnScope | undefined
journal.visitItems((itemId, _sequence, body) => {
if (
body.kind === 'turn' &&
body.userItemId &&
journal.canonicalItemId(body.userItemId) === item.itemId
) {
const turn = saved(itemId)
if (turn) {
scope = scopeOf({ ...item, turnScope: { kind: 'turn', turnItemId: itemId } })
// One pass, like localPrompts: a stale entry cannot commit past the catch-up guard.
if (!promptTurns) {
const turns = new Map<string, string[]>()
journal.visitItems((itemId, _sequence, body) => {
if (body.kind === 'turn' && body.userItemId) {
const user = journal.canonicalItemId(body.userItemId)
const held = turns.get(user)
if (held) {
held.push(itemId)
} else {
turns.set(user, [itemId])
}
}
})
promptTurns = turns
}
let scope: AgentJournalTurnScope | undefined
for (const turnItemId of promptTurns.get(item.itemId) ?? []) {
if (saved(turnItemId)) {
scope = scopeOf({ ...item, turnScope: { kind: 'turn', turnItemId } })
}
})
}
return scope
}
return { saved, localPrompt, scopeOf, promptScope, dependencies }