@hraness/oh 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1114 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Database, type SQLQueryBindings } from "bun:sqlite";
3
+
4
+ import { canonicalJson, canonicalSha256, sha256Hex, type Sha256Hex } from "./canonical";
5
+ import {
6
+ OH_CLOUDFLARE_EMBEDDING_PROFILE_V1,
7
+ OhCloudflareEmbeddingClientV1,
8
+ } from "./cloudflare-embedding";
9
+ import type {
10
+ OhLibSqlClientV1,
11
+ OhLibSqlResultV1,
12
+ OhLibSqlStatementV1,
13
+ } from "./libsql";
14
+ import {
15
+ bootstrapOhLibSqlSemanticCacheV2,
16
+ deriveOhSemanticIsolationSha256V2,
17
+ OhLibSqlSemanticV2Error,
18
+ openOhLibSqlSemanticCacheV2,
19
+ type OhSemanticAuthorityRefV2,
20
+ type OhSemanticDocumentV2,
21
+ } from "./libsql-semantic-v2";
22
+ import { openOhLibSqlSemanticCacheV1 } from "./libsql-semantic";
23
+
24
+ class SqliteCompatibleLibSqlClient implements OhLibSqlClientV1 {
25
+ readonly database = new Database(":memory:", { strict: true });
26
+
27
+ #execute(statement: OhLibSqlStatementV1 | string): OhLibSqlResultV1 {
28
+ const sql = typeof statement === "string" ? statement : statement.sql;
29
+ const args = typeof statement === "string" ? [] : statement.args ?? [];
30
+ const bindings: SQLQueryBindings[] = args.map((value) => value instanceof Date
31
+ ? value.toISOString() : value instanceof ArrayBuffer ? new Uint8Array(value) : value);
32
+ if (/^\s*(?:SELECT|PRAGMA)\b/iu.test(sql)) {
33
+ return {
34
+ rows: this.database.query<Record<string, unknown>, SQLQueryBindings[]>(sql).all(...bindings),
35
+ };
36
+ }
37
+ const result = this.database.query<never, SQLQueryBindings[]>(sql).run(...bindings);
38
+ return { rows: [], rowsAffected: result.changes };
39
+ }
40
+
41
+ async execute(statement: OhLibSqlStatementV1 | string): Promise<OhLibSqlResultV1> {
42
+ return this.#execute(statement);
43
+ }
44
+
45
+ async batch(
46
+ statements: readonly OhLibSqlStatementV1[],
47
+ _mode?: "deferred" | "read" | "write",
48
+ ): Promise<readonly OhLibSqlResultV1[]> {
49
+ return this.database.transaction((items: readonly OhLibSqlStatementV1[]) =>
50
+ items.map((statement) => this.#execute(statement)))(statements);
51
+ }
52
+
53
+ close(): void { this.database.close(); }
54
+ }
55
+
56
+ class InterleavingLibSqlClient extends SqliteCompatibleLibSqlClient {
57
+ beforeVectorWrite: (() => Promise<void>) | null = null;
58
+ afterSecondVectorRead: (() => Promise<void>) | null = null;
59
+ #vectorReads = 0;
60
+
61
+ override async execute(statement: OhLibSqlStatementV1 | string): Promise<OhLibSqlResultV1> {
62
+ const result = await super.execute(statement);
63
+ const sql = typeof statement === "string" ? statement : statement.sql;
64
+ if (/SELECT\s+input_sha256,\s*vector_sha256,\s*vector\s+FROM\s+oh_semantic_vectors/iu
65
+ .test(sql)) {
66
+ this.#vectorReads += 1;
67
+ if (this.#vectorReads === 2 && this.afterSecondVectorRead !== null) {
68
+ const hook = this.afterSecondVectorRead;
69
+ this.afterSecondVectorRead = null;
70
+ await hook();
71
+ }
72
+ }
73
+ return result;
74
+ }
75
+
76
+ override async batch(
77
+ statements: readonly OhLibSqlStatementV1[],
78
+ mode?: "deferred" | "read" | "write",
79
+ ): Promise<readonly OhLibSqlResultV1[]> {
80
+ if (this.beforeVectorWrite !== null
81
+ && statements.some(({ sql }) => /INSERT\s+INTO\s+oh_semantic_vectors/iu.test(sql))) {
82
+ const hook = this.beforeVectorWrite;
83
+ this.beforeVectorWrite = null;
84
+ await hook();
85
+ }
86
+ return await super.batch(statements, mode);
87
+ }
88
+ }
89
+
90
+ class PublishedHeadInterleavingLibSqlClient extends SqliteCompatibleLibSqlClient {
91
+ afterHeadRead: (() => Promise<void>) | null = null;
92
+
93
+ override async execute(statement: OhLibSqlStatementV1 | string): Promise<OhLibSqlResultV1> {
94
+ const result = await super.execute(statement);
95
+ const sql = typeof statement === "string" ? statement : statement.sql;
96
+ if (/FROM\s+oh_semantic_heads\s+WHERE\s+authority_id\s*=\s*\?/iu.test(sql)
97
+ && this.afterHeadRead !== null) {
98
+ const hook = this.afterHeadRead;
99
+ this.afterHeadRead = null;
100
+ await hook();
101
+ }
102
+ return result;
103
+ }
104
+ }
105
+
106
+ class CrashAfterTransitionPageClient extends SqliteCompatibleLibSqlClient {
107
+ #armed = false;
108
+ #offline = false;
109
+
110
+ arm(): void { this.#armed = true; }
111
+ recover(): void { this.#offline = false; }
112
+
113
+ override async execute(statement: OhLibSqlStatementV1 | string): Promise<OhLibSqlResultV1> {
114
+ if (this.#offline) throw new Error("Simulated process crash.");
115
+ return await super.execute(statement);
116
+ }
117
+
118
+ override async batch(
119
+ statements: readonly OhLibSqlStatementV1[],
120
+ mode?: "deferred" | "read" | "write",
121
+ ): Promise<readonly OhLibSqlResultV1[]> {
122
+ if (this.#offline) throw new Error("Simulated process crash.");
123
+ const crash = this.#armed && statements.some(({ sql }) =>
124
+ /DELETE\s+FROM\s+oh_semantic_v1_purge_transition/iu.test(sql));
125
+ const result = await super.batch(statements, mode);
126
+ if (crash) {
127
+ this.#armed = false;
128
+ this.#offline = true;
129
+ throw new Error("Simulated process crash after a committed transition page.");
130
+ }
131
+ return result;
132
+ }
133
+ }
134
+
135
+ class BootstrapVerificationRaceClient extends SqliteCompatibleLibSqlClient {
136
+ afterLegacyMarkerRead: (() => Promise<void>) | null = null;
137
+
138
+ override async execute(statement: OhLibSqlStatementV1 | string): Promise<OhLibSqlResultV1> {
139
+ const result = await super.execute(statement);
140
+ const sql = typeof statement === "string" ? statement : statement.sql;
141
+ const args = typeof statement === "string" ? [] : statement.args ?? [];
142
+ if (/SELECT\s+name,\s*schema_sha256\s+FROM\s+oh_semantic_schemas/iu.test(sql)
143
+ && args[0] === 1 && this.afterLegacyMarkerRead !== null) {
144
+ const hook = this.afterLegacyMarkerRead;
145
+ this.afterLegacyMarkerRead = null;
146
+ await hook();
147
+ }
148
+ return result;
149
+ }
150
+ }
151
+
152
+ class TransitionStartRaceClient extends SqliteCompatibleLibSqlClient {
153
+ beforeTransitionWrite: (() => Promise<void>) | null = null;
154
+
155
+ override async batch(
156
+ statements: readonly OhLibSqlStatementV1[],
157
+ mode?: "deferred" | "read" | "write",
158
+ ): Promise<readonly OhLibSqlResultV1[]> {
159
+ if (statements.some(({ sql }) =>
160
+ /CREATE\s+TABLE\s+oh_semantic_v1_purge_transition/iu.test(sql))
161
+ && this.beforeTransitionWrite !== null) {
162
+ const hook = this.beforeTransitionWrite;
163
+ this.beforeTransitionWrite = null;
164
+ await hook();
165
+ }
166
+ return await super.batch(statements, mode);
167
+ }
168
+ }
169
+
170
+ const instant1 = "2026-08-31T12:00:00.000Z";
171
+ const instant2 = "2026-08-31T12:01:00.000Z";
172
+ const instant3 = "2026-08-31T12:02:00.000Z";
173
+ const digest = (value: string): Sha256Hex => sha256Hex(value);
174
+
175
+ function unitVector(index: number): number[] {
176
+ return Array.from(
177
+ { length: OH_CLOUDFLARE_EMBEDDING_PROFILE_V1.dimensions },
178
+ (_, ordinal) => ordinal === index ? 1 : 0,
179
+ );
180
+ }
181
+
182
+ function embeddingClient(calls: string[][]): OhCloudflareEmbeddingClientV1 {
183
+ return new OhCloudflareEmbeddingClientV1({
184
+ accountId: "0123456789abcdef0123456789abcdef",
185
+ apiToken: "test-token-with-no-provider-authority",
186
+ fetch: async (_input, init) => {
187
+ const body = JSON.parse(String(init?.body)) as { text: string[] };
188
+ calls.push(body.text);
189
+ const vectors = body.text.map((text) => unitVector(
190
+ text.includes("needle-beta") ? 1 : text.includes("needle-gamma") ? 2 : 0,
191
+ ));
192
+ return Response.json({
193
+ result: { data: vectors, shape: [vectors.length, 768] },
194
+ success: true,
195
+ });
196
+ },
197
+ });
198
+ }
199
+
200
+ function document(
201
+ key: string,
202
+ marker: "needle-alpha" | "needle-beta" | "needle-gamma",
203
+ ): OhSemanticDocumentV2 {
204
+ return {
205
+ content: `private body ${marker}`,
206
+ key,
207
+ recordSha256: digest(`record:${key}:${marker}`),
208
+ title: `private title ${marker}`,
209
+ v: 2,
210
+ };
211
+ }
212
+
213
+ async function bootstrapped(): Promise<SqliteCompatibleLibSqlClient> {
214
+ const client = new SqliteCompatibleLibSqlClient();
215
+ expect(await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant1 }))
216
+ .toEqual({
217
+ schemaSha256: "679edfc3cb02dc768843976093f90d5879d53e84b797ac60d77956a634facae9" as Sha256Hex,
218
+ schemaVersion: 2,
219
+ v: 2,
220
+ });
221
+ return client;
222
+ }
223
+
224
+ async function installLegacySemanticSchema(
225
+ client: SqliteCompatibleLibSqlClient,
226
+ ): Promise<void> {
227
+ const sql = await Bun.file(new URL(
228
+ "../spec/v1/libsql-semantic-cache-schema-v1.sql",
229
+ import.meta.url,
230
+ )).text();
231
+ client.database.exec(sql);
232
+ const objects = client.database.query<{
233
+ name: string;
234
+ sql: string;
235
+ tableName: string;
236
+ type: "index" | "table" | "trigger";
237
+ }, []>(`SELECT type, name, tbl_name AS tableName, sql FROM sqlite_schema
238
+ WHERE sql IS NOT NULL AND (name GLOB 'oh_semantic_*' OR tbl_name GLOB 'oh_semantic_*')
239
+ ORDER BY type, name`).all().map((object) => ({
240
+ ...object,
241
+ sql: object.sql.replace(/\bIF\s+NOT\s+EXISTS\b/giu, "").replace(/\s+/gu, " ").trim(),
242
+ })).sort((left, right) => canonicalJson([left.type, left.name])
243
+ .localeCompare(canonicalJson([right.type, right.name])));
244
+ client.database.query(`INSERT INTO oh_semantic_schemas(
245
+ version, name, schema_sha256, applied_at) VALUES (?, ?, ?, ?)`)
246
+ .run(1, "oh.libsql-semantic-cache.v1", canonicalSha256(objects), instant1);
247
+ }
248
+
249
+ async function installV2SemanticSchemaFixture(
250
+ client: SqliteCompatibleLibSqlClient,
251
+ ): Promise<void> {
252
+ const sql = await Bun.file(new URL(
253
+ "../spec/v2/libsql-semantic-cache-schema-v2.sql",
254
+ import.meta.url,
255
+ )).text();
256
+ client.database.exec(sql);
257
+ const objects = client.database.query<{
258
+ name: string;
259
+ sql: string;
260
+ tableName: string;
261
+ type: "index" | "table" | "trigger";
262
+ }, []>(`SELECT type, name, tbl_name AS tableName, sql FROM sqlite_schema
263
+ WHERE sql IS NOT NULL AND (name GLOB 'oh_semantic_*' OR tbl_name GLOB 'oh_semantic_*')
264
+ ORDER BY type, name`).all().map((object) => ({
265
+ ...object,
266
+ sql: object.sql.replace(/\bIF\s+NOT\s+EXISTS\b/giu, "").replace(/\s+/gu, " ").trim(),
267
+ })).sort((left, right) => canonicalJson([left.type, left.name])
268
+ .localeCompare(canonicalJson([right.type, right.name])));
269
+ client.database.query(`INSERT INTO oh_semantic_schemas(
270
+ version, name, schema_sha256, applied_at) VALUES (?, ?, ?, ?)`)
271
+ .run(2, "oh.libsql-semantic-cache.v2", canonicalSha256(objects), instant1);
272
+ }
273
+
274
+ function authority(
275
+ authorityId: string,
276
+ generation: number,
277
+ authoritySha256: Sha256Hex,
278
+ documents: readonly OhSemanticDocumentV2[],
279
+ isolationSha256?: Sha256Hex,
280
+ ): OhSemanticAuthorityRefV2 {
281
+ return {
282
+ authorityId,
283
+ authoritySha256,
284
+ generation,
285
+ ...(isolationSha256 === undefined ? {} : { isolationSha256 }),
286
+ records: documents.map(({ key, recordSha256 }) => ({ key, recordSha256 })),
287
+ v: 2,
288
+ };
289
+ }
290
+
291
+ describe("libSQL derived semantic cache", () => {
292
+ test("reproduces the fixed isolated V2 digest fixture", async () => {
293
+ const fixture = await Bun.file(new URL(
294
+ "../spec/v2/libsql-semantic-digest-fixture-v2.json",
295
+ import.meta.url,
296
+ )).json() as Readonly<{
297
+ authorityId: string;
298
+ authoritySha256: Sha256Hex;
299
+ content: string;
300
+ generation: number;
301
+ generationSha256: Sha256Hex;
302
+ inputSha256: Sha256Hex;
303
+ isolationSha256: Sha256Hex;
304
+ membershipSha256: Sha256Hex;
305
+ recordKey: string;
306
+ recordSha256: Sha256Hex;
307
+ title: string;
308
+ v: 2;
309
+ }>;
310
+ const client = await bootstrapped();
311
+ const cache = await openOhLibSqlSemanticCacheV2(client);
312
+ const calls: string[][] = [];
313
+ const staged = await cache.stage({
314
+ authorityId: fixture.authorityId,
315
+ authoritySha256: fixture.authoritySha256,
316
+ createdAt: instant1,
317
+ documents: [{
318
+ content: fixture.content,
319
+ key: fixture.recordKey,
320
+ recordSha256: fixture.recordSha256,
321
+ title: fixture.title,
322
+ v: fixture.v,
323
+ }],
324
+ embeddingClient: embeddingClient(calls),
325
+ generation: fixture.generation,
326
+ isolationSha256: fixture.isolationSha256,
327
+ });
328
+ expect(deriveOhSemanticIsolationSha256V2(fixture.authorityId))
329
+ .toBe(fixture.isolationSha256);
330
+ expect(staged).toMatchObject({
331
+ generationSha256: fixture.generationSha256,
332
+ isolationSha256: fixture.isolationSha256,
333
+ membershipSha256: fixture.membershipSha256,
334
+ v: 2,
335
+ });
336
+ expect(calls).toHaveLength(1);
337
+ expect(sha256Hex(calls[0]?.[0] ?? "")).toBe(fixture.inputSha256);
338
+ await cache.close();
339
+ client.close();
340
+ });
341
+
342
+ test("migrates v1 by invalidating live derived rows and retaining purge tombstones", async () => {
343
+ const client = new SqliteCompatibleLibSqlClient();
344
+ await installLegacySemanticSchema(client);
345
+ const liveAuthority = "agent:legacy-live:epoch-1";
346
+ const purgedAuthority = "agent:legacy-purged:epoch-1";
347
+ client.database.query(`INSERT INTO oh_semantic_vectors(profile_sha256,
348
+ renderer_sha256, input_sha256, vector_sha256, vector, created_at)
349
+ VALUES (?, ?, ?, ?, ?, ?)`)
350
+ .run(digest("legacy-profile"), digest("legacy-renderer"), digest("legacy-input"),
351
+ digest("legacy-vector"), new Uint8Array([1]), instant1);
352
+ client.database.query(`INSERT INTO oh_semantic_generations(authority_id, generation,
353
+ authority_sha256, profile_sha256, renderer_sha256, membership_sha256,
354
+ generation_sha256, document_count, chunk_count, created_at)
355
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
356
+ .run(liveAuthority, 1, digest("legacy-authority"), digest("legacy-profile"),
357
+ digest("legacy-renderer"), digest("legacy-membership"), digest("legacy-generation"),
358
+ 1, 1, instant1);
359
+ client.database.query("INSERT INTO oh_semantic_purges(authority_id, purged_at) VALUES (?, ?)")
360
+ .run(purgedAuthority, instant2);
361
+
362
+ expect(await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 }))
363
+ .toMatchObject({ schemaVersion: 2, v: 2 });
364
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
365
+ FROM oh_semantic_vectors`).get()?.count).toBe(0);
366
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
367
+ FROM oh_semantic_generations`).get()?.count).toBe(0);
368
+ const cache = await openOhLibSqlSemanticCacheV2(client);
369
+ const migrated = await cache.purgeReceipt({ authorityId: purgedAuthority });
370
+ if (migrated === null) throw new Error("Expected the migrated purge receipt.");
371
+ expect(migrated).toMatchObject({
372
+ authorityId: purgedAuthority,
373
+ countsRecorded: false,
374
+ generations: 0,
375
+ isolationScopes: 1,
376
+ memberships: 0,
377
+ orphanVectors: 0,
378
+ purgedAt: instant2,
379
+ residualGenerations: 0,
380
+ residualMemberships: 0,
381
+ residualScopedVectors: 0,
382
+ });
383
+ expect(await cache.purgeAuthority({
384
+ authorityId: purgedAuthority,
385
+ purgedAt: "2026-08-31T12:05:00.000Z",
386
+ })).toEqual(migrated);
387
+ await cache.close();
388
+ client.close();
389
+ });
390
+
391
+ test("resumes an uncapped paged tombstone transition after a committed-page crash", async () => {
392
+ const client = new CrashAfterTransitionPageClient();
393
+ await installLegacySemanticSchema(client);
394
+ const tombstones = 4_097;
395
+ client.database.exec(`WITH RECURSIVE sequence(value) AS (
396
+ SELECT 0 UNION ALL SELECT value + 1 FROM sequence WHERE value + 1 < ${tombstones}
397
+ ) INSERT INTO oh_semantic_purges(authority_id, purged_at)
398
+ SELECT printf('agent:legacy:%05d', value), '${instant2}' FROM sequence`);
399
+ const legacyCache = await openOhLibSqlSemanticCacheV1(client);
400
+ client.arm();
401
+ await expect(bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 }))
402
+ .rejects.toThrow("Simulated process crash");
403
+
404
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
405
+ FROM oh_semantic_v1_purge_transition`).get()?.count).toBe(tombstones - 32);
406
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
407
+ FROM oh_semantic_purges`).get()?.count).toBe(32);
408
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
409
+ FROM oh_semantic_schemas`).get()?.count).toBe(0);
410
+
411
+ client.recover();
412
+ await expect(openOhLibSqlSemanticCacheV2(client))
413
+ .rejects.toMatchObject({ code: "schema-unavailable" });
414
+ await expect(legacyCache.purgeAuthority({
415
+ authorityId: "agent:legacy:late-purge",
416
+ purgedAt: instant3,
417
+ })).rejects.toBeDefined();
418
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
419
+ FROM oh_semantic_v1_purge_transition`).get()?.count).toBe(tombstones - 32);
420
+
421
+ // Re-present one already materialized page row to prove receipt replay is
422
+ // safe even when another bootstrap selected the same page before commit.
423
+ client.database.query(`INSERT INTO oh_semantic_v1_purge_transition(
424
+ authority_id, purged_at) VALUES (?, ?)`)
425
+ .run("agent:legacy:00000", instant2);
426
+
427
+ expect(await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 }))
428
+ .toMatchObject({ schemaVersion: 2, v: 2 });
429
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
430
+ FROM oh_semantic_purges`).get()?.count).toBe(tombstones);
431
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
432
+ FROM sqlite_schema WHERE name = 'oh_semantic_v1_purge_transition'`).get()?.count).toBe(0);
433
+ const cache = await openOhLibSqlSemanticCacheV2(client);
434
+ expect(await cache.purgeReceipt({ authorityId: "agent:legacy:04096" }))
435
+ .toMatchObject({ countsRecorded: false, v: 2 });
436
+ await cache.close();
437
+ await legacyCache.close();
438
+ client.close();
439
+ });
440
+
441
+ test("converges concurrent V2 bootstraps without losing a successful V1 purge", async () => {
442
+ const client = new SqliteCompatibleLibSqlClient();
443
+ await installLegacySemanticSchema(client);
444
+ const legacyCache = await openOhLibSqlSemanticCacheV1(client);
445
+ const authorityId = "agent:legacy:concurrent-purge";
446
+ const [purge, firstUpgrade, secondUpgrade] = await Promise.allSettled([
447
+ legacyCache.purgeAuthority({ authorityId, purgedAt: instant2 }),
448
+ bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 }),
449
+ bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 }),
450
+ ]);
451
+ if (firstUpgrade.status === "rejected") throw firstUpgrade.reason;
452
+ if (secondUpgrade.status === "rejected") throw secondUpgrade.reason;
453
+ const cache = await openOhLibSqlSemanticCacheV2(client);
454
+ const receipt = await cache.purgeReceipt({ authorityId });
455
+ if (purge.status === "fulfilled") {
456
+ expect(receipt).toMatchObject({ authorityId, countsRecorded: false, purgedAt: instant2 });
457
+ } else {
458
+ expect(receipt).toBeNull();
459
+ }
460
+ await cache.close();
461
+ await legacyCache.close();
462
+ client.close();
463
+ });
464
+
465
+ test("converges when another bootstrap wins between V1 marker and inventory reads", async () => {
466
+ const client = new BootstrapVerificationRaceClient();
467
+ await installLegacySemanticSchema(client);
468
+ let competing: Awaited<ReturnType<typeof bootstrapOhLibSqlSemanticCacheV2>> | null = null;
469
+ client.afterLegacyMarkerRead = async () => {
470
+ competing = await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 });
471
+ };
472
+ expect(await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 }))
473
+ .toMatchObject({ schemaVersion: 2, v: 2 });
474
+ expect(competing).toMatchObject({ schemaVersion: 2, v: 2 });
475
+ await expect(openOhLibSqlSemanticCacheV2(client)).resolves.toBeDefined();
476
+ client.close();
477
+ });
478
+
479
+ test("copies a V1 purge that commits immediately before transition custody", async () => {
480
+ const client = new TransitionStartRaceClient();
481
+ await installLegacySemanticSchema(client);
482
+ const legacyCache = await openOhLibSqlSemanticCacheV1(client);
483
+ const authorityId = "agent:legacy:last-v1-purge";
484
+ let legacyPurge: Awaited<ReturnType<typeof legacyCache.purgeAuthority>> | null = null;
485
+ client.beforeTransitionWrite = async () => {
486
+ legacyPurge = await legacyCache.purgeAuthority({ authorityId, purgedAt: instant2 });
487
+ };
488
+ await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant3 });
489
+ expect(legacyPurge).toMatchObject({ authorityId, purgedAt: instant2, v: 1 });
490
+ const cache = await openOhLibSqlSemanticCacheV2(client);
491
+ expect(await cache.purgeReceipt({ authorityId })).toMatchObject({
492
+ authorityId,
493
+ countsRecorded: false,
494
+ purgedAt: instant2,
495
+ v: 2,
496
+ });
497
+ await cache.close();
498
+ await legacyCache.close();
499
+ client.close();
500
+ });
501
+
502
+ test("requires explicit bootstrap and refuses a partial or drifted schema", async () => {
503
+ const empty = new SqliteCompatibleLibSqlClient();
504
+ await expect(openOhLibSqlSemanticCacheV2(empty)).rejects.toMatchObject({
505
+ code: "schema-unavailable",
506
+ });
507
+ expect(empty.database.query<{ count: number }, []>(`SELECT count(*) AS count
508
+ FROM sqlite_schema WHERE name GLOB 'oh_semantic_*'`).get()?.count).toBe(0);
509
+ empty.close();
510
+
511
+ const fixedV2 = new SqliteCompatibleLibSqlClient();
512
+ await installV2SemanticSchemaFixture(fixedV2);
513
+ await expect(openOhLibSqlSemanticCacheV2(fixedV2)).resolves.toBeDefined();
514
+ fixedV2.close();
515
+
516
+ const coTenant = new SqliteCompatibleLibSqlClient();
517
+ coTenant.database.exec("CREATE TABLE ohXsemanticYforeign(value TEXT) STRICT");
518
+ await expect(bootstrapOhLibSqlSemanticCacheV2(coTenant, { appliedAt: instant1 }))
519
+ .resolves.toMatchObject({ schemaVersion: 2, v: 2 });
520
+ await expect(openOhLibSqlSemanticCacheV2(coTenant)).resolves.toBeDefined();
521
+ coTenant.close();
522
+
523
+ const partial = new SqliteCompatibleLibSqlClient();
524
+ partial.database.exec("CREATE TABLE oh_semantic_foreign(value TEXT) STRICT");
525
+ await expect(bootstrapOhLibSqlSemanticCacheV2(partial, { appliedAt: instant1 }))
526
+ .rejects.toMatchObject({ code: "integrity" });
527
+ partial.close();
528
+
529
+ const drifted = await bootstrapped();
530
+ drifted.database.exec("DROP INDEX oh_semantic_memberships_input");
531
+ await expect(openOhLibSqlSemanticCacheV2(drifted)).rejects.toMatchObject({ code: "integrity" });
532
+ drifted.close();
533
+
534
+ const ownerDrift = await bootstrapped();
535
+ ownerDrift.database.exec(`CREATE TRIGGER foreign_named_semantic_trigger
536
+ AFTER INSERT ON oh_semantic_vectors BEGIN SELECT 1; END`);
537
+ await expect(openOhLibSqlSemanticCacheV2(ownerDrift))
538
+ .rejects.toMatchObject({ code: "integrity" });
539
+ ownerDrift.close();
540
+ });
541
+
542
+ test("stages immutable generations, reuses vectors, publishes by CAS, and searches exactly", async () => {
543
+ const client = await bootstrapped();
544
+ const cache = await openOhLibSqlSemanticCacheV2(client);
545
+ const calls: string[][] = [];
546
+ const embedder = embeddingClient(calls);
547
+ const authorityId = "agent:session-1:epoch-1";
548
+ const firstDocuments = [
549
+ document("memory:one", "needle-alpha"),
550
+ document("memory:two", "needle-beta"),
551
+ ] as const;
552
+ const firstAuthoritySha256 = digest("authority:first");
553
+ expect(await cache.publishedHead({ authorityId })).toBeNull();
554
+ const first = await cache.stage({
555
+ authorityId,
556
+ authoritySha256: firstAuthoritySha256,
557
+ createdAt: instant1,
558
+ documents: firstDocuments,
559
+ embeddingClient: embedder,
560
+ generation: 1,
561
+ });
562
+ expect(first).toMatchObject({ chunks: 2, documents: 2, embedded: 2, reused: 0 });
563
+ expect(calls).toHaveLength(1);
564
+ expect(await cache.publishedHead({ authorityId })).toBeNull();
565
+ expect(await cache.stage({
566
+ authorityId,
567
+ authoritySha256: firstAuthoritySha256,
568
+ createdAt: instant2,
569
+ documents: firstDocuments,
570
+ embeddingClient: embedder,
571
+ generation: 1,
572
+ })).toMatchObject({ embedded: 0, generationSha256: first.generationSha256, reused: 2 });
573
+ expect(calls).toHaveLength(1);
574
+
575
+ const storedVectors = client.database.query<{
576
+ bytes: number;
577
+ count: number;
578
+ }, []>("SELECT count(*) AS count, min(length(vector)) AS bytes FROM oh_semantic_vectors").get();
579
+ expect(storedVectors).toEqual({ bytes: 3_072, count: 2 });
580
+ const storedText = JSON.stringify(client.database.query<Record<string, unknown>, []>(`
581
+ SELECT authority_id, authority_sha256, profile_sha256, renderer_sha256,
582
+ membership_sha256, generation_sha256 FROM oh_semantic_generations`).all());
583
+ expect(storedText).not.toContain("private title");
584
+ expect(storedText).not.toContain("private body");
585
+ expect(storedText).not.toContain("needle-alpha");
586
+
587
+ expect(await cache.publish({
588
+ authorityId,
589
+ expectedPublishedGeneration: null,
590
+ generation: 1,
591
+ publishedAt: instant1,
592
+ })).toMatchObject({ published: true });
593
+ expect(await cache.publishedHead({ authorityId })).toEqual({
594
+ authorityId,
595
+ authoritySha256: firstAuthoritySha256,
596
+ generation: 1,
597
+ generationSha256: first.generationSha256,
598
+ isolationSha256: deriveOhSemanticIsolationSha256V2(authorityId),
599
+ membershipSha256: first.membershipSha256,
600
+ profileSha256: OH_CLOUDFLARE_EMBEDDING_PROFILE_V1.profileSha256,
601
+ publishedAt: instant1,
602
+ rendererSha256: expect.stringMatching(/^[a-f0-9]{64}$/u),
603
+ v: 2,
604
+ });
605
+ expect(await cache.publish({
606
+ authorityId,
607
+ expectedPublishedGeneration: null,
608
+ generation: 1,
609
+ publishedAt: instant2,
610
+ })).toMatchObject({ published: false });
611
+ expect(await cache.stage({
612
+ authorityId,
613
+ authoritySha256: firstAuthoritySha256,
614
+ createdAt: instant2,
615
+ documents: firstDocuments,
616
+ embeddingClient: embedder,
617
+ generation: 1,
618
+ })).toMatchObject({ embedded: 0, generationSha256: first.generationSha256, reused: 2 });
619
+ expect(calls).toHaveLength(1);
620
+
621
+ const hits = await cache.search({
622
+ authority: authority(authorityId, 1, firstAuthoritySha256, firstDocuments),
623
+ embeddingClient: embedder,
624
+ limit: 2,
625
+ query: "needle-alpha",
626
+ });
627
+ expect(hits.map(({ key, score }) => ({ key, score }))).toEqual([
628
+ { key: "memory:one", score: 1 },
629
+ { key: "memory:two", score: 0 },
630
+ ]);
631
+ expect(await cache.search({
632
+ authority: authority(authorityId, 1, digest("stale"), firstDocuments),
633
+ embeddingClient: embedder,
634
+ query: "needle-alpha",
635
+ })).toEqual([]);
636
+ expect((await cache.search({
637
+ authority: authority(authorityId, 1, firstAuthoritySha256, [
638
+ { ...firstDocuments[0], recordSha256: digest("changed") },
639
+ firstDocuments[1],
640
+ ]),
641
+ embeddingClient: embedder,
642
+ query: "needle-alpha",
643
+ })).map(({ key, score }) => ({ key, score }))).toEqual([
644
+ { key: "memory:two", score: 0 },
645
+ ]);
646
+
647
+ const secondDocuments = [
648
+ firstDocuments[0],
649
+ document("memory:three", "needle-gamma"),
650
+ ] as const;
651
+ const secondAuthoritySha256 = digest("authority:second");
652
+ expect(await cache.stage({
653
+ authorityId,
654
+ authoritySha256: secondAuthoritySha256,
655
+ createdAt: instant2,
656
+ documents: secondDocuments,
657
+ embeddingClient: embedder,
658
+ generation: 2,
659
+ })).toMatchObject({ embedded: 1, reused: 1 });
660
+ await expect(cache.publish({
661
+ authorityId,
662
+ expectedPublishedGeneration: 0,
663
+ generation: 2,
664
+ publishedAt: instant2,
665
+ })).rejects.toMatchObject({ code: "conflict" });
666
+ expect(await cache.publish({
667
+ authorityId,
668
+ expectedPublishedGeneration: 1,
669
+ generation: 2,
670
+ publishedAt: instant2,
671
+ })).toMatchObject({ published: true });
672
+ expect(await cache.publishedHead({ authorityId })).toMatchObject({
673
+ authoritySha256: secondAuthoritySha256,
674
+ generation: 2,
675
+ publishedAt: instant2,
676
+ v: 2,
677
+ });
678
+ expect(await cache.search({
679
+ authority: authority(authorityId, 1, firstAuthoritySha256, firstDocuments),
680
+ embeddingClient: embedder,
681
+ query: "needle-alpha",
682
+ })).toEqual([]);
683
+
684
+ expect(() => client.database.query(`INSERT INTO oh_semantic_memberships(
685
+ authority_id, generation, generation_sha256, record_key, record_sha256,
686
+ isolation_sha256, ordinal, input_sha256) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
687
+ .run(authorityId, 2, digest("generation"), "memory:late", digest("late"),
688
+ deriveOhSemanticIsolationSha256V2(authorityId), 0, digest("late")))
689
+ .toThrow("published");
690
+ await cache.close();
691
+ client.close();
692
+ });
693
+
694
+ test("namespaces identical rendered inputs without perturbing provider text", async () => {
695
+ const client = await bootstrapped();
696
+ const cache = await openOhLibSqlSemanticCacheV2(client);
697
+ const calls: string[][] = [];
698
+ const embedder = embeddingClient(calls);
699
+ const documents = [document("memory:shared", "needle-alpha")] as const;
700
+ const firstAuthorityId = "agent:isolated-a:epoch-1";
701
+ const secondAuthorityId = "agent:isolated-b:epoch-1";
702
+ const firstIsolation = digest("private-isolation:first");
703
+ const secondIsolation = digest("private-isolation:second");
704
+ for (const [authorityId, isolation] of [
705
+ [firstAuthorityId, firstIsolation],
706
+ [secondAuthorityId, secondIsolation],
707
+ ] as const) {
708
+ const staged = await cache.stage({
709
+ authorityId,
710
+ authoritySha256: digest(authorityId),
711
+ createdAt: instant1,
712
+ documents,
713
+ embeddingClient: embedder,
714
+ generation: 1,
715
+ isolationSha256: isolation,
716
+ });
717
+ expect(staged).toMatchObject({ embedded: 1, isolationSha256: isolation, reused: 0 });
718
+ await cache.publish({
719
+ authorityId,
720
+ expectedPublishedGeneration: null,
721
+ generation: 1,
722
+ isolationSha256: isolation,
723
+ publishedAt: instant1,
724
+ });
725
+ }
726
+ expect(calls).toHaveLength(2);
727
+ expect(calls[0]).toEqual(calls[1]);
728
+ expect(client.database.query<{
729
+ inputs: number;
730
+ isolations: number;
731
+ rows: number;
732
+ }, []>(`SELECT count(*) AS rows, count(DISTINCT isolation_sha256) AS isolations,
733
+ count(DISTINCT input_sha256) AS inputs FROM oh_semantic_vectors`).get())
734
+ .toEqual({ inputs: 1, isolations: 2, rows: 2 });
735
+ expect(await cache.publishedHead({
736
+ authorityId: firstAuthorityId,
737
+ isolationSha256: firstIsolation,
738
+ })).toMatchObject({ isolationSha256: firstIsolation });
739
+ expect(await cache.publishedHead({
740
+ authorityId: firstAuthorityId,
741
+ isolationSha256: secondIsolation,
742
+ })).toBeNull();
743
+ const callsBeforeMismatch = calls.length;
744
+ expect(await cache.search({
745
+ authority: authority(
746
+ firstAuthorityId,
747
+ 1,
748
+ digest(firstAuthorityId),
749
+ documents,
750
+ secondIsolation,
751
+ ),
752
+ embeddingClient: embedder,
753
+ query: "needle-alpha",
754
+ })).toEqual([]);
755
+ expect(calls).toHaveLength(callsBeforeMismatch);
756
+ await expect(cache.stage({
757
+ authorityId: "agent:isolated-attacker:epoch-1",
758
+ authoritySha256: digest("isolated-attacker"),
759
+ createdAt: instant2,
760
+ documents,
761
+ embeddingClient: embedder,
762
+ generation: 1,
763
+ isolationSha256: firstIsolation,
764
+ })).rejects.toMatchObject({ code: "conflict" });
765
+ expect(calls).toHaveLength(callsBeforeMismatch);
766
+ await cache.close();
767
+ client.close();
768
+ });
769
+
770
+ test("tombstones a purged authority without sharing vectors across authorities", async () => {
771
+ const client = await bootstrapped();
772
+ const cache = await openOhLibSqlSemanticCacheV2(client);
773
+ const calls: string[][] = [];
774
+ const embedder = embeddingClient(calls);
775
+ const shared = [document("memory:shared", "needle-alpha")] as const;
776
+ for (const authorityId of ["agent:session-a:epoch-1", "agent:session-b:epoch-1"] as const) {
777
+ await cache.stage({
778
+ authorityId,
779
+ authoritySha256: digest(authorityId),
780
+ createdAt: instant1,
781
+ documents: shared,
782
+ embeddingClient: embedder,
783
+ generation: 1,
784
+ });
785
+ await cache.publish({
786
+ authorityId,
787
+ expectedPublishedGeneration: null,
788
+ generation: 1,
789
+ publishedAt: instant1,
790
+ });
791
+ }
792
+ expect(calls).toHaveLength(2);
793
+ expect(client.database.query<{ count: number }, []>(
794
+ "SELECT count(*) AS count FROM oh_semantic_vectors",
795
+ ).get()?.count).toBe(2);
796
+ const firstReceipt = await cache.purgeAuthority({
797
+ authorityId: "agent:session-a:epoch-1",
798
+ purgedAt: instant2,
799
+ });
800
+ expect(firstReceipt).toMatchObject({
801
+ countsRecorded: true,
802
+ generations: 1,
803
+ isolationScopes: 1,
804
+ isolationSha256: deriveOhSemanticIsolationSha256V2("agent:session-a:epoch-1"),
805
+ memberships: 1,
806
+ orphanVectors: 1,
807
+ profileSha256: OH_CLOUDFLARE_EMBEDDING_PROFILE_V1.profileSha256,
808
+ publishedGeneration: 1,
809
+ publishedGenerationSha256: expect.stringMatching(/^[a-f0-9]{64}$/u),
810
+ purgeMarkerSha256: expect.stringMatching(/^[a-f0-9]{64}$/u),
811
+ purgeReceiptSha256: expect.stringMatching(/^[a-f0-9]{64}$/u),
812
+ residualGenerations: 0,
813
+ residualMemberships: 0,
814
+ residualScopedVectors: 0,
815
+ });
816
+ expect(await cache.purgeReceipt({
817
+ authorityId: "agent:session-a:epoch-1",
818
+ })).toEqual(firstReceipt);
819
+ expect(await cache.purgeAuthority({
820
+ authorityId: "agent:session-a:epoch-1",
821
+ purgedAt: instant3,
822
+ })).toEqual(firstReceipt);
823
+ await expect(cache.purgeReceipt({
824
+ authorityId: "agent:session-a:epoch-1",
825
+ isolationSha256: digest("wrong-isolation"),
826
+ })).rejects.toMatchObject({ code: "conflict" });
827
+ expect(client.database.query<{ count: number }, []>(
828
+ "SELECT count(*) AS count FROM oh_semantic_vectors",
829
+ ).get()?.count).toBe(1);
830
+ await expect(cache.stage({
831
+ authorityId: "agent:session-a:epoch-1",
832
+ authoritySha256: digest("replacement"),
833
+ createdAt: instant3,
834
+ documents: shared,
835
+ embeddingClient: embedder,
836
+ generation: 2,
837
+ })).rejects.toMatchObject({ code: "purged" });
838
+ expect(await cache.search({
839
+ authority: authority("agent:session-a:epoch-1", 1,
840
+ digest("agent:session-a:epoch-1"), shared),
841
+ embeddingClient: embedder,
842
+ query: "needle-alpha",
843
+ })).toEqual([]);
844
+ expect(await cache.publishedHead({
845
+ authorityId: "agent:session-a:epoch-1",
846
+ })).toBeNull();
847
+
848
+ const secondReceipt = await cache.purgeAuthority({
849
+ authorityId: "agent:session-b:epoch-1",
850
+ purgedAt: instant3,
851
+ });
852
+ expect(secondReceipt.orphanVectors).toBe(1);
853
+ expect(await cache.purgeAuthority({
854
+ authorityId: "agent:session-b:epoch-1",
855
+ purgedAt: "2026-08-31T12:03:00.000Z",
856
+ })).toEqual(secondReceipt);
857
+ expect(client.database.query<{ count: number }, []>(
858
+ "SELECT count(*) AS count FROM oh_semantic_vectors",
859
+ ).get()?.count).toBe(0);
860
+ await cache.close();
861
+ client.close();
862
+ });
863
+
864
+ test("rotates cache epochs within one authority and purges every reserved scope", async () => {
865
+ const client = await bootstrapped();
866
+ const cache = await openOhLibSqlSemanticCacheV2(client);
867
+ const calls: string[][] = [];
868
+ const embedder = embeddingClient(calls);
869
+ const authorityId = "agent:epoch-rotation:session-1";
870
+ const documents = [document("memory:one", "needle-alpha")] as const;
871
+ const firstIsolation = digest("epoch-rotation:first");
872
+ const secondIsolation = digest("epoch-rotation:second");
873
+ for (const [generation, isolation, publishedAt] of [
874
+ [1, firstIsolation, instant1],
875
+ [2, secondIsolation, instant2],
876
+ ] as const) {
877
+ await cache.stage({
878
+ authorityId,
879
+ authoritySha256: digest(`epoch-rotation:${generation}`),
880
+ createdAt: publishedAt,
881
+ documents,
882
+ embeddingClient: embedder,
883
+ generation,
884
+ isolationSha256: isolation,
885
+ });
886
+ await cache.publish({
887
+ authorityId,
888
+ expectedPublishedGeneration: generation === 1 ? null : 1,
889
+ generation,
890
+ isolationSha256: isolation,
891
+ publishedAt,
892
+ });
893
+ }
894
+ expect(calls).toHaveLength(2);
895
+ expect(await cache.publishedHead({
896
+ authorityId,
897
+ isolationSha256: firstIsolation,
898
+ })).toBeNull();
899
+ expect(await cache.publishedHead({
900
+ authorityId,
901
+ isolationSha256: secondIsolation,
902
+ })).toMatchObject({ generation: 2, isolationSha256: secondIsolation });
903
+ await expect(cache.purgeAuthority({
904
+ authorityId,
905
+ isolationSha256: firstIsolation,
906
+ purgedAt: instant3,
907
+ })).rejects.toMatchObject({ code: "conflict" });
908
+ expect(await cache.purgeReceipt({
909
+ authorityId,
910
+ isolationSha256: secondIsolation,
911
+ })).toBeNull();
912
+ expect(client.database.query<{ count: number }, []>(
913
+ "SELECT count(*) AS count FROM oh_semantic_generations",
914
+ ).get()?.count).toBe(2);
915
+ expect(client.database.query<{ count: number }, []>(
916
+ "SELECT count(*) AS count FROM oh_semantic_vectors",
917
+ ).get()?.count).toBe(2);
918
+ expect(client.database.query<{ count: number }, []>(
919
+ "SELECT count(*) AS count FROM oh_semantic_heads",
920
+ ).get()?.count).toBe(1);
921
+ const receipt = await cache.purgeAuthority({
922
+ authorityId,
923
+ isolationSha256: secondIsolation,
924
+ purgedAt: instant3,
925
+ });
926
+ expect(receipt).toMatchObject({
927
+ generations: 2,
928
+ isolationScopes: 2,
929
+ isolationSha256: secondIsolation,
930
+ memberships: 2,
931
+ orphanVectors: 2,
932
+ publishedGeneration: 2,
933
+ residualGenerations: 0,
934
+ residualMemberships: 0,
935
+ residualScopedVectors: 0,
936
+ });
937
+ await expect(cache.purgeAuthority({
938
+ authorityId,
939
+ isolationSha256: firstIsolation,
940
+ purgedAt: "2026-08-31T12:03:00.000Z",
941
+ })).rejects.toMatchObject({ code: "conflict" });
942
+ await cache.close();
943
+ client.close();
944
+ });
945
+
946
+ test("keeps an unrelated in-flight stage intact across an authority-scoped purge", async () => {
947
+ const client = new InterleavingLibSqlClient();
948
+ await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant1 });
949
+ const cache = await openOhLibSqlSemanticCacheV2(client);
950
+ const documents = [document("memory:in-flight", "needle-alpha")] as const;
951
+ let concurrentPurge: Awaited<ReturnType<typeof cache.purgeAuthority>> | null = null;
952
+ client.afterSecondVectorRead = async () => {
953
+ concurrentPurge = await cache.purgeAuthority({
954
+ authorityId: "agent:unrelated:epoch-1",
955
+ purgedAt: instant2,
956
+ });
957
+ };
958
+
959
+ await cache.stage({
960
+ authorityId: "agent:in-flight:epoch-1",
961
+ authoritySha256: digest("authority:in-flight"),
962
+ createdAt: instant1,
963
+ documents,
964
+ embeddingClient: embeddingClient([]),
965
+ generation: 1,
966
+ });
967
+
968
+ expect(concurrentPurge).toMatchObject({ orphanVectors: 0 });
969
+ expect(client.database.query<{ count: number }, []>(`SELECT count(*) AS count
970
+ FROM oh_semantic_memberships AS membership
971
+ LEFT JOIN oh_semantic_vectors AS vector
972
+ ON vector.isolation_sha256 = membership.isolation_sha256
973
+ AND vector.profile_sha256 = '${OH_CLOUDFLARE_EMBEDDING_PROFILE_V1.profileSha256}'
974
+ AND vector.renderer_sha256 = (SELECT renderer_sha256 FROM oh_semantic_generations
975
+ WHERE authority_id = membership.authority_id AND generation = membership.generation)
976
+ AND vector.input_sha256 = membership.input_sha256
977
+ WHERE membership.authority_id = 'agent:in-flight:epoch-1' AND vector.input_sha256 IS NULL`)
978
+ .get()?.count).toBe(0);
979
+ await cache.close();
980
+ client.close();
981
+ });
982
+
983
+ test("does not write a vector after the same authority purge has completed", async () => {
984
+ const client = new InterleavingLibSqlClient();
985
+ await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant1 });
986
+ const cache = await openOhLibSqlSemanticCacheV2(client);
987
+ const authorityId = "agent:purge-race:epoch-1";
988
+ client.beforeVectorWrite = async () => {
989
+ await cache.purgeAuthority({ authorityId, purgedAt: instant2 });
990
+ };
991
+
992
+ await expect(cache.stage({
993
+ authorityId,
994
+ authoritySha256: digest("authority:purge-race"),
995
+ createdAt: instant1,
996
+ documents: [document("memory:purge-race", "needle-alpha")],
997
+ embeddingClient: embeddingClient([]),
998
+ generation: 1,
999
+ })).rejects.toMatchObject({ code: "purged" });
1000
+ expect(client.database.query<{ count: number }, []>(
1001
+ "SELECT count(*) AS count FROM oh_semantic_vectors",
1002
+ ).get()?.count).toBe(0);
1003
+ expect(client.database.query<{ count: number }, []>(
1004
+ "SELECT count(*) AS count FROM oh_semantic_generations",
1005
+ ).get()?.count).toBe(0);
1006
+ await cache.close();
1007
+ client.close();
1008
+ });
1009
+
1010
+ test("fails closed on changed generation identity and invalid authority inputs", async () => {
1011
+ const client = await bootstrapped();
1012
+ const cache = await openOhLibSqlSemanticCacheV2(client);
1013
+ const embedder = embeddingClient([]);
1014
+ const documents = [document("memory:one", "needle-alpha")] as const;
1015
+ await cache.stage({
1016
+ authorityId: "agent:session-1:epoch-1",
1017
+ authoritySha256: digest("first"),
1018
+ createdAt: instant1,
1019
+ documents,
1020
+ embeddingClient: embedder,
1021
+ generation: 1,
1022
+ });
1023
+ await expect(cache.stage({
1024
+ authorityId: "agent:session-1:epoch-1",
1025
+ authoritySha256: digest("different"),
1026
+ createdAt: instant2,
1027
+ documents,
1028
+ embeddingClient: embedder,
1029
+ generation: 1,
1030
+ })).rejects.toMatchObject({ code: "conflict" });
1031
+ await expect(cache.search({
1032
+ authority: {
1033
+ authorityId: "INVALID",
1034
+ authoritySha256: digest("first"),
1035
+ generation: 1,
1036
+ records: [],
1037
+ v: 2,
1038
+ },
1039
+ embeddingClient: embedder,
1040
+ query: "needle-alpha",
1041
+ })).rejects.toBeInstanceOf(OhLibSqlSemanticV2Error);
1042
+ await expect(cache.publishedHead({ authorityId: "INVALID" }))
1043
+ .rejects.toMatchObject({ code: "invalid-input" });
1044
+ await cache.close();
1045
+ client.close();
1046
+ });
1047
+
1048
+ test("rejects a published pointer that diverges from its immutable generation", async () => {
1049
+ const client = await bootstrapped();
1050
+ const cache = await openOhLibSqlSemanticCacheV2(client);
1051
+ const authorityId = "agent:published-head-integrity:epoch-1";
1052
+ await cache.stage({
1053
+ authorityId,
1054
+ authoritySha256: digest("published-head-integrity"),
1055
+ createdAt: instant1,
1056
+ documents: [document("memory:one", "needle-alpha")],
1057
+ embeddingClient: embeddingClient([]),
1058
+ generation: 1,
1059
+ });
1060
+ await cache.publish({
1061
+ authorityId,
1062
+ expectedPublishedGeneration: null,
1063
+ generation: 1,
1064
+ publishedAt: instant1,
1065
+ });
1066
+ client.database.query(`UPDATE oh_semantic_heads SET authority_sha256 = ?
1067
+ WHERE authority_id = ?`).run(digest("forged-head"), authorityId);
1068
+ await expect(cache.publishedHead({ authorityId }))
1069
+ .rejects.toMatchObject({ code: "integrity" });
1070
+ await cache.close();
1071
+ client.close();
1072
+ });
1073
+
1074
+ test("does not return a head that changed during its bounded read", async () => {
1075
+ const client = new PublishedHeadInterleavingLibSqlClient();
1076
+ await bootstrapOhLibSqlSemanticCacheV2(client, { appliedAt: instant1 });
1077
+ const cache = await openOhLibSqlSemanticCacheV2(client);
1078
+ const authorityId = "agent:published-head-race:epoch-1";
1079
+ const embedder = embeddingClient([]);
1080
+ for (const generation of [1, 2] as const) {
1081
+ await cache.stage({
1082
+ authorityId,
1083
+ authoritySha256: digest(`published-head-race:${generation}`),
1084
+ createdAt: generation === 1 ? instant1 : instant2,
1085
+ documents: [document(
1086
+ `memory:${generation}`,
1087
+ generation === 1 ? "needle-alpha" : "needle-beta",
1088
+ )],
1089
+ embeddingClient: embedder,
1090
+ generation,
1091
+ });
1092
+ }
1093
+ await cache.publish({
1094
+ authorityId,
1095
+ expectedPublishedGeneration: null,
1096
+ generation: 1,
1097
+ publishedAt: instant1,
1098
+ });
1099
+ client.afterHeadRead = async () => {
1100
+ await cache.publish({
1101
+ authorityId,
1102
+ expectedPublishedGeneration: 1,
1103
+ generation: 2,
1104
+ publishedAt: instant2,
1105
+ });
1106
+ };
1107
+ await expect(cache.publishedHead({ authorityId }))
1108
+ .rejects.toMatchObject({ code: "conflict" });
1109
+ expect(await cache.publishedHead({ authorityId }))
1110
+ .toMatchObject({ generation: 2, publishedAt: instant2 });
1111
+ await cache.close();
1112
+ client.close();
1113
+ });
1114
+ });