Skip to content

Commit b7e4073

Browse files
committed
perf(semantic-search): pin manifest snapshots per run
Cover the manifest snapshot invariant that scans use the create-time manifest even if the live catalog changes before scan. This protects the KV-only scan path from accidental live-manifest fallback.
1 parent cc39a00 commit b7e4073

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

packages/plugins/semantic-search/src/sdk/tool-search-index.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,44 @@ describe("ToolSearchIndex manifest snapshot", () => {
10011001
}),
10021002
);
10031003

1004+
it.effect("scans the create-time manifest snapshot when the live manifest changes", () =>
1005+
Effect.gen(function* () {
1006+
const [tool] = makeTools(1);
1007+
if (tool === undefined) return;
1008+
let liveManifests = [manifestForTool(tool, "fp-at-create", "source-at-create")];
1009+
const counters = { manifest: 0 };
1010+
const executor: Pick<Executor, "tools" | "cache"> = {
1011+
tools: {
1012+
list: () => Effect.succeed([tool]),
1013+
manifest: () => {
1014+
counters.manifest++;
1015+
return Effect.succeed(liveManifests);
1016+
},
1017+
schema: () => Effect.succeed(null),
1018+
},
1019+
cache: makeMemoryCache(),
1020+
};
1021+
const base = makeBase(executor as Executor);
1022+
1023+
yield* create({ ...base, runId: "run-snapshot-stability", partitionCount: 1 });
1024+
liveManifests = [manifestForTool(tool, "fp-after-create", "source-after-create")];
1025+
1026+
const scanned = yield* scan({
1027+
...base,
1028+
runId: "run-snapshot-stability",
1029+
partition: 0,
1030+
limit: 10,
1031+
});
1032+
1033+
expect(scanned).toMatchObject({ processed: 1, changed: 1, skipped: 0 });
1034+
expect(counters.manifest).toBe(1);
1035+
expect([...base.jobs.data.values()][0]).toMatchObject({
1036+
fingerprint: "fp-at-create",
1037+
sourceRevision: "source-at-create",
1038+
});
1039+
}),
1040+
);
1041+
10041042
it.effect("fails the scan when the run snapshot is missing (no D1 fallback)", () =>
10051043
Effect.gen(function* () {
10061044
const { executor, counters } = makeCountingExecutor(makeTools(2));

0 commit comments

Comments
 (0)