diff --git a/apps/server/src/services/threads/timeline.ts b/apps/server/src/services/threads/timeline.ts index 430d64660..ccd2379d9 100644 --- a/apps/server/src/services/threads/timeline.ts +++ b/apps/server/src/services/threads/timeline.ts @@ -1538,13 +1538,13 @@ function buildSequencePageTimelineRows( selection.responsePageKind === "latest" ? "" : `:sequence-page:${selection.byteWindowSequenceStart}`; - return rowsWithPlaceholder.map((row): TimelineRow => { + return rowsWithPlaceholder.flatMap((row): TimelineRow[] => { if ( row.kind !== "turn" || selection.byteWindowSequenceEnd === null || selection.byteWindowSequenceStart === null ) { - return { ...row, id: `${row.id}${suffix}` }; + return [{ ...row, id: `${row.id}${suffix}` }]; } const sourceSeqStart = Math.max( row.sourceSeqStart, @@ -1555,13 +1555,18 @@ function buildSequencePageTimelineRows( selection.byteWindowSequenceEnd, ); return sourceSeqStart <= sourceSeqEnd - ? { - ...row, - id: `${row.id}${suffix}`, - sourceSeqEnd, - sourceSeqStart, - } - : { ...row, id: `${row.id}${suffix}` }; + ? [ + { + ...row, + id: `${row.id}${suffix}`, + sourceSeqEnd, + sourceSeqStart, + }, + ] + : // PROTOTYPE (#1868): a finished-turn row whose events lie entirely + // outside this byte window came in through parent/lifecycle closure + // and belongs to the page that actually holds those events. + []; }); } diff --git a/packages/db/src/data/events.ts b/packages/db/src/data/events.ts index e7de63b63..061d9de86 100644 --- a/packages/db/src/data/events.ts +++ b/packages/db/src/data/events.ts @@ -2838,6 +2838,19 @@ function storedTimelineWindowConditions( if (args.excludedTypes && args.excludedTypes.length > 0) { conditions.push(notInArray(events.type, [...args.excludedTypes])); } + // PROTOTYPE (#1868): superseded background-task progress snapshots are + // never load-bearing (see pruneBackgroundTaskProgressEvents), so neither + // the byte budget nor the materialized window should include them. + const progressType = + "item/backgroundTask/progress" satisfies ThreadEventType; + conditions.push( + sql`(${events.type} <> ${progressType} OR ${events.id} IN ( + SELECT latest.id FROM events latest + WHERE latest.thread_id = ${events.threadId} + AND latest.type = ${progressType} + AND latest.item_id = ${events.itemId} + ORDER BY latest.sequence DESC LIMIT 1))`, + ); return conditions; }