diff --git a/src/utils/pipeline-factory.ts b/src/utils/pipeline-factory.ts index b0b3f1c..ce87801 100644 --- a/src/utils/pipeline-factory.ts +++ b/src/utils/pipeline-factory.ts @@ -463,7 +463,7 @@ export function createL2Runner(opts: { logger.debug?.( `${TAG} [L2] No new L1 records since cursor (session=${sessionKey}, updatedAfter=${cursor ?? "(full)"}), skipping scene extraction`, ); - return { skipped: true }; + return { skipped: true, latestCursor: cursor || undefined }; } logger.debug?.( @@ -494,7 +494,7 @@ export function createL2Runner(opts: { if (sessionRecords.length === 0) { logger.debug?.(`${TAG} [L2] No new L1 records found (JSONL fallback, session=${sessionKey}), skipping scene extraction`); - return; + return { latestCursor: cursor || undefined }; } records = sessionRecords.map((r) => ({ diff --git a/src/utils/pipeline-manager.ts b/src/utils/pipeline-manager.ts index 92ce95b..bccf293 100644 --- a/src/utils/pipeline-manager.ts +++ b/src/utils/pipeline-manager.ts @@ -923,6 +923,11 @@ export class MemoryPipelineManager { // Advance cursor using the record timestamp returned by the runner if (result?.latestCursor) { state.last_extraction_updated_time = result.latestCursor; + } else if (!state.last_extraction_updated_time) { + // Cold-start guard: if runner returned void (e.g. extraction failure) and + // last_extraction_updated_time is still empty, initialize it to now so + // the next L2 run doesn't do a full table scan. + state.last_extraction_updated_time = new Date().toISOString(); } await this.persistStates();