Skip to content

Commit d9e9f7c

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 14f8258 commit d9e9f7c

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
@@ -1032,6 +1032,44 @@ describe("ToolSearchIndex manifest snapshot", () => {
10321032
}),
10331033
);
10341034

1035+
it.effect("scans the create-time manifest snapshot when the live manifest changes", () =>
1036+
Effect.gen(function* () {
1037+
const [tool] = makeTools(1);
1038+
if (tool === undefined) return;
1039+
let liveManifests = [manifestForTool(tool, "fp-at-create", "source-at-create")];
1040+
const counters = { manifest: 0 };
1041+
const executor: Pick<Executor, "tools" | "cache"> = {
1042+
tools: {
1043+
list: () => Effect.succeed([tool]),
1044+
manifest: () => {
1045+
counters.manifest++;
1046+
return Effect.succeed(liveManifests);
1047+
},
1048+
schema: () => Effect.succeed(null),
1049+
},
1050+
cache: makeMemoryCache(),
1051+
};
1052+
const base = makeBase(executor as Executor);
1053+
1054+
yield* create({ ...base, runId: "run-snapshot-stability", partitionCount: 1 });
1055+
liveManifests = [manifestForTool(tool, "fp-after-create", "source-after-create")];
1056+
1057+
const scanned = yield* scan({
1058+
...base,
1059+
runId: "run-snapshot-stability",
1060+
partition: 0,
1061+
limit: 10,
1062+
});
1063+
1064+
expect(scanned).toMatchObject({ processed: 1, changed: 1, skipped: 0 });
1065+
expect(counters.manifest).toBe(1);
1066+
expect([...base.jobs.data.values()][0]).toMatchObject({
1067+
fingerprint: "fp-at-create",
1068+
sourceRevision: "source-at-create",
1069+
});
1070+
}),
1071+
);
1072+
10351073
it.effect("fails the scan when the run snapshot is missing (no D1 fallback)", () =>
10361074
Effect.gen(function* () {
10371075
const { executor, counters } = makeCountingExecutor(makeTools(2));

0 commit comments

Comments
 (0)