@fgv/ts-agent-memory-sqlite-vec 5.1.0-45 → 5.1.0-46

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.
Files changed (25) hide show
  1. package/.rush/temp/{e3385c5c74e11d46b4fbe400b497eb3f33a009b6.tar.log → b39f85377e1ce7a5b4a0aad208a6f48e4fba124b.tar.log} +2 -2
  2. package/.rush/temp/chunked-rush-logs/ts-agent-memory-sqlite-vec.build.chunks.jsonl +2 -2
  3. package/.rush/temp/operation/build/all.log +2 -2
  4. package/.rush/temp/operation/build/log-chunks.jsonl +2 -2
  5. package/.rush/temp/operation/build/state.json +1 -1
  6. package/README.md +16 -2
  7. package/dist/packlets/sqlite-vec-index/sqliteVecFragmentIndex.js +144 -26
  8. package/dist/packlets/sqlite-vec-index/sqliteVecFragmentIndex.js.map +1 -1
  9. package/dist/test/unit/sqliteVecFragmentIndex.test.js +168 -7
  10. package/dist/test/unit/sqliteVecFragmentIndex.test.js.map +1 -1
  11. package/dist/ts-agent-memory-sqlite-vec.d.ts +68 -11
  12. package/lib/packlets/sqlite-vec-index/sqliteVecFragmentIndex.d.ts +68 -11
  13. package/lib/packlets/sqlite-vec-index/sqliteVecFragmentIndex.d.ts.map +1 -1
  14. package/lib/packlets/sqlite-vec-index/sqliteVecFragmentIndex.js +144 -26
  15. package/lib/packlets/sqlite-vec-index/sqliteVecFragmentIndex.js.map +1 -1
  16. package/lib/test/unit/sqliteVecFragmentIndex.test.js +168 -7
  17. package/lib/test/unit/sqliteVecFragmentIndex.test.js.map +1 -1
  18. package/package.json +7 -7
  19. package/rush-logs/ts-agent-memory-sqlite-vec.build.cache.log +1 -1
  20. package/rush-logs/ts-agent-memory-sqlite-vec.build.log +2 -2
  21. package/src/packlets/sqlite-vec-index/sqliteVecFragmentIndex.ts +184 -25
  22. package/src/test/unit/sqliteVecFragmentIndex.test.ts +236 -11
  23. package/temp/build/lint/_eslint-5eVG3S6w.json +2 -2
  24. package/temp/build/typescript/ts_8nwakTlr.json +1 -1
  25. package/temp/ts-agent-memory-sqlite-vec.api.json +2 -2
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import '@fgv/ts-utils-jest';
6
6
  import BetterSqlite3 from 'better-sqlite3';
7
+ import { load as loadSqliteVec } from 'sqlite-vec';
7
8
  import * as fs from 'fs';
8
9
  import * as os from 'os';
9
10
  import * as path from 'path';
@@ -46,10 +47,52 @@ describe('SqliteVecFragmentIndex', () => {
46
47
  closed.close();
47
48
  expect(await SqliteVecFragmentIndex.create({ database: closed })).toFailWith(/failed to initialize/i);
48
49
  });
49
- test('recovers no dimension from a pre-existing non-vec0 table of the same name', async () => {
50
+ test('rejects a pre-existing non-vec0 table of the same name rather than adopting it', async () => {
50
51
  db.exec('CREATE TABLE memory_fragments (foo TEXT)');
51
- expect(await SqliteVecFragmentIndex.create({ database: db })).toSucceedAndSatisfy((index) => {
52
- expect(index.recordCount).toBe(0);
52
+ expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/auxiliary columns \[\] but this index requires \[start_off, end_off, fragment_id\]/i);
53
+ });
54
+ describe('auxiliary-column schema detection', () => {
55
+ // `CREATE VIRTUAL TABLE IF NOT EXISTS` is a no-op against an existing table and
56
+ // vec0 has no `ALTER TABLE ADD COLUMN`, so a database written by an earlier
57
+ // version keeps its narrower column set. Without detection the widened INSERT
58
+ // surfaces an opaque `no such column: fragment_id` at statement-prepare time.
59
+ function createLegacyTable(database) {
60
+ loadSqliteVec(database);
61
+ database.exec('CREATE VIRTUAL TABLE memory_fragments USING vec0(' +
62
+ 'target_key TEXT PARTITION KEY, embedding float[2] distance_metric=cosine, ' +
63
+ '+start_off integer, +end_off integer)');
64
+ }
65
+ test('fails with an actionable message naming expected and found columns', async () => {
66
+ createLegacyTable(db);
67
+ expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/auxiliary columns \[start_off, end_off\] but this index requires \[start_off, end_off, fragment_id\]/i);
68
+ });
69
+ test('states that a drop-and-re-index is required and that no data is lost', async () => {
70
+ createLegacyTable(db);
71
+ expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/cannot be altered in place[\s\S]*drop-and-re-index[\s\S]*DROP TABLE "memory_fragments"[\s\S]*costs embedding time, never data/i);
72
+ });
73
+ test('does not surface the opaque sqlite "no such column" error', async () => {
74
+ createLegacyTable(db);
75
+ const created = await SqliteVecFragmentIndex.create({ database: db });
76
+ expect(created).toFail();
77
+ expect(created.isFailure() && created.message).not.toMatch(/no such column/i);
78
+ });
79
+ test('accepts a table whose auxiliary columns match, regardless of declaration order', async () => {
80
+ loadSqliteVec(db);
81
+ db.exec('CREATE VIRTUAL TABLE memory_fragments USING vec0(' +
82
+ 'target_key TEXT PARTITION KEY, embedding float[3] distance_metric=cosine, ' +
83
+ '+fragment_id text, +end_off integer, +start_off integer)');
84
+ expect(await SqliteVecFragmentIndex.create({ database: db })).toSucceed();
85
+ });
86
+ test('rejects a table that mimics the auxiliary columns but has no vec0 embedding column', async () => {
87
+ db.exec('CREATE TABLE memory_fragments ("+start_off" integer, "+end_off" integer, "+fragment_id" text)');
88
+ expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/no vec0 embedding column/i);
89
+ });
90
+ test('rejects a table with the right number of columns but a different one', async () => {
91
+ loadSqliteVec(db);
92
+ db.exec('CREATE VIRTUAL TABLE memory_fragments USING vec0(' +
93
+ 'target_key TEXT PARTITION KEY, embedding float[2] distance_metric=cosine, ' +
94
+ '+start_off integer, +end_off integer, +frag_id text)');
95
+ expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/auxiliary columns \[start_off, end_off, frag_id\]/i);
53
96
  });
54
97
  });
55
98
  });
@@ -128,11 +171,11 @@ describe('SqliteVecFragmentIndex', () => {
128
171
  });
129
172
  test('fails loudly (never silently corrupts) when the table name collides with a non-vec0 table', async () => {
130
173
  // A plain table already occupies the default name. `CREATE VIRTUAL TABLE IF NOT
131
- // EXISTS` no-ops against it, so preparing the vector INSERT against the missing
132
- // columns must fail loudly rather than corrupt state.
174
+ // EXISTS` no-ops against it, so the collision must fail loudly rather than
175
+ // corrupt state `create` now catches it up front via the auxiliary-column
176
+ // check, so the index is never handed out at all.
133
177
  db.exec('CREATE TABLE memory_fragments (foo TEXT)');
134
- const index = (await SqliteVecFragmentIndex.create({ database: db })).orThrow();
135
- expect(await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).toFailWith(/cannot add 'knowledge\0doc-a'/i);
178
+ expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/auxiliary columns/i);
136
179
  });
137
180
  });
138
181
  describe('query', () => {
@@ -269,6 +312,28 @@ describe('SqliteVecFragmentIndex', () => {
269
312
  function insertRaw(key, start, end, ...vec) {
270
313
  db.prepare('INSERT INTO memory_fragments(target_key, embedding, start_off, end_off) VALUES (?, ?, ?, ?)').run(key, toBlob(...vec), start, end);
271
314
  }
315
+ /** Insert a row with arbitrary (possibly NULL) identity columns, bypassing the write-side guards. */
316
+ function insertRawIdentity(key, start, end, fragmentId, ...vec) {
317
+ db.prepare('INSERT INTO memory_fragments(target_key, embedding, start_off, end_off, fragment_id) ' +
318
+ 'VALUES (?, ?, ?, ?, ?)').run(key, toBlob(...vec), start, end, fragmentId);
319
+ }
320
+ test('fails loudly when a stored locator has a start offset but no end offset', async () => {
321
+ // `Number(null)` is 0, so coercing a half-NULL pair would silently fabricate a
322
+ // span rather than surface the corruption.
323
+ const index = await seededWithRow();
324
+ insertRawIdentity('knowledge\0doc-b', BigInt(3), null, 'frag-1', 0, 1);
325
+ expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(/locator has only one of its start\/end offsets/i);
326
+ });
327
+ test('fails loudly when a stored locator has an end offset but no start offset', async () => {
328
+ const index = await seededWithRow();
329
+ insertRawIdentity('knowledge\0doc-b', null, BigInt(9), 'frag-1', 0, 1);
330
+ expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(/locator has only one of its start\/end offsets/i);
331
+ });
332
+ test('fails loudly when a stored row carries neither a locator nor a fragment id', async () => {
333
+ const index = await seededWithRow();
334
+ insertRawIdentity('knowledge\0doc-b', null, null, null, 0, 1);
335
+ expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(/carries neither a locator nor a fragment id/i);
336
+ });
272
337
  test('coerces bigint offsets (better-sqlite3 safe-integer mode) to number locators', async () => {
273
338
  const index = await seededWithRow();
274
339
  // Under safe-integer mode every integer column comes back as a bigint.
@@ -294,6 +359,102 @@ describe('SqliteVecFragmentIndex', () => {
294
359
  expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(/missing scope\/id separator/i);
295
360
  });
296
361
  });
362
+ describe('fragment identity', () => {
363
+ /** A fragment identified only by an opaque id — no honest body span. */
364
+ function idFrag(fragmentId, ...values) {
365
+ return { fragmentId, vector: Float32Array.from(values) };
366
+ }
367
+ test('rejects a fragment carrying neither a locator nor a fragmentId', async () => {
368
+ const index = await makeIndex();
369
+ expect(await index.addFragments(target('knowledge', 'doc-a'), [{ vector: Float32Array.from([1, 0]) }])).toFailWith(/at least one of 'locator' or 'fragmentId'/i);
370
+ expect(index.fragmentCount).toBe(0);
371
+ });
372
+ test('carries an opaque fragmentId through to the query hit verbatim', async () => {
373
+ const index = await makeIndex();
374
+ const opaque = 'urn:frag:9f8e::{not-parsed}';
375
+ (await index.addFragments(target('knowledge', 'doc-a'), [idFrag(opaque, 1, 0)])).orThrow();
376
+ expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy((hits) => {
377
+ expect(hits[0].fragmentId).toBe(opaque);
378
+ expect(hits[0].locator).toBeUndefined();
379
+ });
380
+ });
381
+ test('carries both identities when a fragment supplies both', async () => {
382
+ const index = await makeIndex();
383
+ (await index.addFragments(target('knowledge', 'doc-a'), [
384
+ Object.assign(Object.assign({}, frag(2, 8, 1, 0)), { fragmentId: 'frag-1' })
385
+ ])).orThrow();
386
+ expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy((hits) => {
387
+ expect(hits[0].locator).toEqual(loc(2, 8));
388
+ expect(hits[0].fragmentId).toBe('frag-1');
389
+ });
390
+ });
391
+ test('a locator-only fragment produces a hit with no fragmentId key at all', async () => {
392
+ // Byte-identical to what this index produced before `fragment_id` existed: the
393
+ // key is absent, not present-and-undefined, so an existing caller's structural
394
+ // comparisons are unaffected by the addition.
395
+ const index = await makeIndex();
396
+ (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();
397
+ expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy((hits) => {
398
+ expect(Object.keys(hits[0]).sort()).toEqual(['locator', 'score', 'target']);
399
+ expect(hits[0]).toStrictEqual({
400
+ target: target('knowledge', 'doc-a'),
401
+ score: hits[0].score,
402
+ locator: loc(0, 5)
403
+ });
404
+ });
405
+ });
406
+ test('an id-only fragment produces a hit with no locator key at all', async () => {
407
+ const index = await makeIndex();
408
+ (await index.addFragments(target('knowledge', 'doc-a'), [idFrag('frag-1', 1, 0)])).orThrow();
409
+ expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy((hits) => {
410
+ expect(Object.keys(hits[0]).sort()).toEqual(['fragmentId', 'score', 'target']);
411
+ });
412
+ });
413
+ test('skips the safe-integer offset check for a fragment with no locator', async () => {
414
+ // The write-side offset validation must not fire (or throw on `BigInt(undefined)`)
415
+ // when there is no locator to validate.
416
+ const index = await makeIndex();
417
+ expect(await index.addFragments(target('knowledge', 'doc-a'), [idFrag('frag-1', 1, 0)])).toSucceedWith(1);
418
+ });
419
+ test('still rejects a non-safe-integer offset when a locator IS supplied', async () => {
420
+ const index = await makeIndex();
421
+ expect(await index.addFragments(target('knowledge', 'doc-a'), [
422
+ { locator: loc(0.5, 5), fragmentId: 'frag-1', vector: Float32Array.from([1, 0]) }
423
+ ])).toFailWith(/offsets must be safe integers/i);
424
+ });
425
+ test('round-trips every identity shape across a close + reopen', async () => {
426
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'svfragid-'));
427
+ const dbPath = path.join(dir, 'fragments.db');
428
+ const first = new BetterSqlite3(dbPath);
429
+ try {
430
+ const writeIndex = (await SqliteVecFragmentIndex.create({ database: first })).orThrow();
431
+ (await writeIndex.addFragments(target('knowledge', 'doc-a'), [
432
+ frag(0, 5, 1, 0),
433
+ idFrag('frag-rewritten', 0, 1),
434
+ Object.assign(Object.assign({}, frag(5, 9, 0.9, 0.1)), { fragmentId: 'frag-both' })
435
+ ])).orThrow();
436
+ }
437
+ finally {
438
+ first.close();
439
+ }
440
+ const second = new BetterSqlite3(dbPath);
441
+ try {
442
+ const reopened = (await SqliteVecFragmentIndex.create({ database: second })).orThrow();
443
+ expect(reopened.fragmentCount).toBe(3);
444
+ expect(await reopened.query(Float32Array.from([1, 0]), 3)).toSucceedAndSatisfy((hits) => {
445
+ var _a, _b, _c;
446
+ const byShape = new Map(hits.map((h) => { var _a; return [(_a = h.fragmentId) !== null && _a !== void 0 ? _a : '<none>', h]; }));
447
+ expect((_a = byShape.get('<none>')) === null || _a === void 0 ? void 0 : _a.locator).toEqual(loc(0, 5));
448
+ expect((_b = byShape.get('frag-rewritten')) === null || _b === void 0 ? void 0 : _b.locator).toBeUndefined();
449
+ expect((_c = byShape.get('frag-both')) === null || _c === void 0 ? void 0 : _c.locator).toEqual(loc(5, 9));
450
+ });
451
+ }
452
+ finally {
453
+ second.close();
454
+ fs.rmSync(dir, { recursive: true, force: true });
455
+ }
456
+ });
457
+ });
297
458
  describe('custom table name', () => {
298
459
  test('two fragment indexes on distinct tables in one database are independent', async () => {
299
460
  const a = (await SqliteVecFragmentIndex.create({ database: db, tableName: 'frag_a' })).orThrow();
@@ -1 +1 @@
1
- {"version":3,"file":"sqliteVecFragmentIndex.test.js","sourceRoot":"","sources":["../../../src/test/unit/sqliteVecFragmentIndex.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport '@fgv/ts-utils-jest';\n\nimport BetterSqlite3 from 'better-sqlite3';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\nimport {\n IEdgeTarget,\n IEmbeddedFragment,\n IFragmentLocator,\n IVectorQueryHit,\n MemoryId,\n MemoryScopeKey\n} from '@fgv/ts-agent-memory';\nimport { SqliteVecFragmentIndex } from '../../index';\n\nfunction target(scope: string, id: string): IEdgeTarget {\n return { scope: scope as unknown as MemoryScopeKey, id: id as unknown as MemoryId };\n}\nfunction loc(start: number, end: number): IFragmentLocator {\n return { start, end };\n}\nfunction frag(start: number, end: number, ...values: number[]): IEmbeddedFragment {\n return { locator: loc(start, end), vector: Float32Array.from(values) };\n}\n\ndescribe('SqliteVecFragmentIndex', () => {\n let db: BetterSqlite3.Database;\n\n beforeEach(() => {\n db = new BetterSqlite3(':memory:');\n });\n afterEach(() => {\n // Some tests close `db` themselves to exercise error paths; guard double-close.\n if (db.open) {\n db.close();\n }\n });\n\n async function makeIndex(): Promise<SqliteVecFragmentIndex> {\n return (await SqliteVecFragmentIndex.create({ database: db })).orThrow();\n }\n\n describe('create', () => {\n test('succeeds over a fresh database with an empty index', async () => {\n expect(await SqliteVecFragmentIndex.create({ database: db })).toSucceedAndSatisfy(\n (index: SqliteVecFragmentIndex) => {\n expect(index.recordCount).toBe(0);\n expect(index.fragmentCount).toBe(0);\n }\n );\n });\n\n test('rejects a table name that is not a simple identifier', async () => {\n expect(\n await SqliteVecFragmentIndex.create({ database: db, tableName: 'bad name; DROP TABLE x' })\n ).toFailWith(/not a simple SQL identifier/i);\n });\n\n test('fails loudly when the sqlite-vec extension cannot load (closed database)', async () => {\n const closed = new BetterSqlite3(':memory:');\n closed.close();\n expect(await SqliteVecFragmentIndex.create({ database: closed })).toFailWith(/failed to initialize/i);\n });\n\n test('recovers no dimension from a pre-existing non-vec0 table of the same name', async () => {\n db.exec('CREATE TABLE memory_fragments (foo TEXT)');\n expect(await SqliteVecFragmentIndex.create({ database: db })).toSucceedAndSatisfy(\n (index: SqliteVecFragmentIndex) => {\n expect(index.recordCount).toBe(0);\n }\n );\n });\n });\n\n describe('addFragments', () => {\n test('stores every fragment and reports the count; tracks record/fragment counts', async () => {\n const index = await makeIndex();\n expect(\n await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0), frag(5, 10, 0, 1)])\n ).toSucceedWith(2);\n expect(index.recordCount).toBe(1);\n expect(index.fragmentCount).toBe(2);\n });\n\n test('whole-record replace — a second addFragments drops the prior fragments', async () => {\n const index = await makeIndex();\n const t = target('knowledge', 'doc-a');\n (await index.addFragments(t, [frag(0, 5, 1, 0), frag(5, 10, 0, 1)])).orThrow();\n expect(await index.addFragments(t, [frag(0, 3, 1, 1)])).toSucceedWith(1);\n expect(index.recordCount).toBe(1);\n expect(index.fragmentCount).toBe(1);\n expect(await index.query(Float32Array.from([1, 1]), 5)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(1);\n expect(hits[0].locator).toEqual(loc(0, 3));\n }\n );\n });\n\n test('an empty fragments array drops an existing record', async () => {\n const index = await makeIndex();\n const t = target('knowledge', 'doc-a');\n (await index.addFragments(t, [frag(0, 5, 1, 0)])).orThrow();\n expect(await index.addFragments(t, [])).toSucceedWith(0);\n expect(index.recordCount).toBe(0);\n expect(index.fragmentCount).toBe(0);\n });\n\n test('an empty fragments array on a fresh index is a no-op (no table created)', async () => {\n const index = await makeIndex();\n expect(await index.addFragments(target('knowledge', 'doc-a'), [])).toSucceedWith(0);\n expect(index.recordCount).toBe(0);\n // A later real add still establishes the dimension cleanly.\n expect(await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 1, 0)])).toSucceedWith(1);\n });\n\n test('same stem in different scopes are distinct entries', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('conversations/a', 'turn-3'), [frag(0, 5, 1, 0)])).orThrow();\n (await index.addFragments(target('conversations/b', 'turn-3'), [frag(0, 5, 0, 1)])).orThrow();\n expect(index.recordCount).toBe(2);\n expect(index.fragmentCount).toBe(2);\n });\n\n test('fails loudly on an empty fragment vector — and stores nothing', async () => {\n const index = await makeIndex();\n expect(\n await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0), frag(5, 10)])\n ).toFailWith(/cannot add 'knowledge\\0doc-a': empty fragment vector/i);\n expect(index.recordCount).toBe(0);\n });\n\n test('fails loudly on a fragment-dimension mismatch against the established dimension', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'a'), [frag(0, 5, 1, 0)])).orThrow();\n expect(await index.addFragments(target('knowledge', 'b'), [frag(0, 5, 1, 0, 0)])).toFailWith(\n /fragment dimension 3 does not match index dimension 2/i\n );\n });\n\n test('rejects a non-safe-integer locator offset up front (never persists an unreadable locator)', async () => {\n const index = await makeIndex();\n // A non-integer offset: reject before the write, with a clear message.\n expect(await index.addFragments(target('knowledge', 'doc-a'), [frag(0.5, 5, 1, 0)])).toFailWith(\n /locator \\[0\\.5, 5\\) offsets must be safe integers/i\n );\n // A too-large (non-safe) integer offset is likewise rejected.\n expect(\n await index.addFragments(target('knowledge', 'doc-b'), [frag(0, Number.MAX_SAFE_INTEGER + 1, 1, 0)])\n ).toFailWith(/offsets must be safe integers/i);\n expect(index.recordCount).toBe(0);\n });\n\n test('a failed multi-fragment add on a fresh index does not establish a dimension (all-or-nothing)', async () => {\n const index = await makeIndex();\n // dim 2 then dim 3 in the same batch: fails, and must NOT commit dim 2.\n expect(\n await index.addFragments(target('knowledge', 'doc-1'), [frag(0, 5, 1, 0), frag(5, 10, 1, 0, 0)])\n ).toFailWith(/fragment dimension 3 does not match index dimension 2/i);\n expect(index.recordCount).toBe(0);\n // A fresh dim-3 record now indexes cleanly (the index was never poisoned to dim 2).\n expect(await index.addFragments(target('knowledge', 'doc-2'), [frag(0, 5, 1, 0, 0)])).toSucceedWith(1);\n });\n\n test('fails loudly (best-effort caller unaffected) when the underlying add throws', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n db.close();\n expect(await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 0, 1)])).toFailWith(\n /cannot add 'knowledge\\0doc-b'/i\n );\n });\n\n test('fails loudly (never silently corrupts) when the table name collides with a non-vec0 table', async () => {\n // A plain table already occupies the default name. `CREATE VIRTUAL TABLE IF NOT\n // EXISTS` no-ops against it, so preparing the vector INSERT against the missing\n // columns must fail loudly rather than corrupt state.\n db.exec('CREATE TABLE memory_fragments (foo TEXT)');\n const index = (await SqliteVecFragmentIndex.create({ database: db })).orThrow();\n expect(await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).toFailWith(\n /cannot add 'knowledge\\0doc-a'/i\n );\n });\n });\n\n describe('query', () => {\n async function seeded(): Promise<SqliteVecFragmentIndex> {\n const index = await makeIndex();\n (\n await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0), frag(5, 10, 0, 1)])\n ).orThrow();\n (await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 1, 1)])).orThrow();\n return index;\n }\n\n test('returns fragment hits in descending score order, each carrying its locator', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 3)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].target.id).toBe('doc-a');\n expect(hits[0].locator).toEqual(loc(0, 5));\n expect(hits[0].score).toBeCloseTo(1, 5);\n expect(hits[1].target.id).toBe('doc-b');\n expect(hits[1].score).toBeCloseTo(1 / Math.sqrt(2), 5);\n expect(hits[2].target.id).toBe('doc-a');\n expect(hits[2].locator).toEqual(loc(5, 10));\n expect(hits[2].score).toBeCloseTo(0, 5);\n }\n );\n });\n\n test('truncates to topK', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 2)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(2);\n expect(hits.map((h) => h.target.id)).toEqual(['doc-a', 'doc-b']);\n }\n );\n });\n\n test('maxPerRecord caps fragments per record during selection (before the topK cut)', async () => {\n const index = await makeIndex();\n (\n await index.addFragments(target('knowledge', 'doc-a'), [\n frag(0, 5, 1, 0),\n frag(5, 10, 0.9, 0.1),\n frag(10, 15, 0.8, 0.2)\n ])\n ).orThrow();\n (await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 0.7, 0.3)])).orThrow();\n // Without a cap the top-2 would be doc-a twice; maxPerRecord=1 surfaces doc-b.\n expect(await index.query(Float32Array.from([1, 0]), 2, 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(2);\n expect(hits.map((h) => h.target.id)).toEqual(['doc-a', 'doc-b']);\n expect(hits[0].locator).toEqual(loc(0, 5));\n }\n );\n });\n\n test('maxPerRecord=0 yields no hits', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 5, 0)).toSucceedWith([]);\n });\n\n test('maxPerRecord larger than any record leaves the ranking unchanged', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 5, 10)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(3);\n expect(hits[0].target.id).toBe('doc-a');\n }\n );\n });\n\n test('returns empty for a non-positive topK', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 0)).toSucceedWith([]);\n expect(await index.query(Float32Array.from([1, 0]), -5)).toSucceedWith([]);\n });\n\n test('returns empty before any add (no established dimension)', async () => {\n const index = await makeIndex();\n expect(await index.query(Float32Array.from([1, 0, 0]), 5)).toSucceedWith([]);\n });\n\n test('returns empty when a capped query runs against an emptied (but existing) table', async () => {\n const index = await makeIndex();\n const t = target('knowledge', 'doc-a');\n (await index.addFragments(t, [frag(0, 5, 1, 0)])).orThrow();\n (await index.addFragments(t, [])).orThrow(); // table now exists but holds 0 rows\n // fetchK derives from the (zero) fragment count under a cap → short-circuits to [].\n expect(await index.query(Float32Array.from([1, 0]), 5, 2)).toSucceedWith([]);\n });\n\n test('rejects a query vector of the wrong dimension', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0, 0]), 3)).toFailWith(\n /query dimension 3 does not match index dimension 2/i\n );\n });\n\n test('a capped query stops at topK even when more ranked rows remain', async () => {\n // maxPerRecord makes the fetch span the full ranked set (3 fragments), but\n // topK=1 must return exactly one hit — the top row — and stop.\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 1, 5)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(1);\n expect(hits[0].target.id).toBe('doc-a');\n expect(hits[0].locator).toEqual(loc(0, 5));\n }\n );\n });\n\n test('fails loudly when the underlying query throws', async () => {\n const index = await seeded();\n db.close();\n expect(await index.query(Float32Array.from([1, 0]), 3)).toFailWith(/query failed/i);\n });\n });\n\n describe('remove', () => {\n test('removes every fragment of a record and is reflected in subsequent queries', async () => {\n const index = await makeIndex();\n const a = target('knowledge', 'doc-a');\n const b = target('knowledge', 'doc-b');\n (await index.addFragments(a, [frag(0, 5, 1, 0), frag(5, 10, 1, 0)])).orThrow();\n (await index.addFragments(b, [frag(0, 5, 0, 1)])).orThrow();\n expect(await index.remove(a)).toSucceedWith(a);\n expect(index.recordCount).toBe(1);\n expect(index.fragmentCount).toBe(1);\n expect(await index.query(Float32Array.from([1, 0]), 5)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits.map((h) => h.target.id)).toEqual(['doc-b']);\n }\n );\n });\n\n test('is idempotent — removing a missing target succeeds', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n expect(await index.remove(target('knowledge', 'missing'))).toSucceedWith(\n target('knowledge', 'missing')\n );\n expect(index.recordCount).toBe(1);\n });\n\n test('succeeds before any add (no table yet)', async () => {\n const index = await makeIndex();\n expect(await index.remove(target('knowledge', 'doc-a'))).toSucceedWith(target('knowledge', 'doc-a'));\n expect(index.recordCount).toBe(0);\n });\n\n test('fails loudly when the underlying remove throws', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n db.close();\n expect(await index.remove(target('knowledge', 'doc-a'))).toFailWith(\n /cannot remove 'knowledge\\0doc-a'/i\n );\n });\n });\n\n describe('safe-integer mode and corrupt persisted data', () => {\n const toBlob = (...v: number[]): Uint8Array => new Uint8Array(Float32Array.from(v).buffer);\n\n async function seededWithRow(): Promise<SqliteVecFragmentIndex> {\n // A valid add creates the table and establishes dim 2; corrupt rows are then\n // inserted directly to model externally-edited / safe-integer-mode data.\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n return index;\n }\n\n function insertRaw(key: string, start: bigint, end: bigint, ...vec: number[]): void {\n db.prepare(\n 'INSERT INTO memory_fragments(target_key, embedding, start_off, end_off) VALUES (?, ?, ?, ?)'\n ).run(key, toBlob(...vec), start, end);\n }\n\n test('coerces bigint offsets (better-sqlite3 safe-integer mode) to number locators', async () => {\n const index = await seededWithRow();\n // Under safe-integer mode every integer column comes back as a bigint.\n db.defaultSafeIntegers(true);\n expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n const locator = hits[0].locator;\n expect(locator).toEqual(loc(0, 5));\n expect(typeof locator?.start).toBe('number');\n expect(typeof locator?.end).toBe('number');\n }\n );\n });\n\n test('fails loudly when a stored offset is outside the safe-integer range', async () => {\n const index = await seededWithRow();\n // Safe-integer mode returns the huge offset as a bigint (no read-time throw),\n // so the _toOffset guard is what must fire.\n db.defaultSafeIntegers(true);\n insertRaw('knowledge\\0doc-b', BigInt(2) ** BigInt(60), BigInt(0), 0, 1);\n expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(\n /locator offset .* is not a safe integer/i\n );\n });\n\n test('fails loudly when a stored key is missing the NUL separator', async () => {\n const index = await seededWithRow();\n insertRaw('nonulkey', BigInt(0), BigInt(5), 0, 1);\n expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(/missing scope\\/id separator/i);\n });\n });\n\n describe('custom table name', () => {\n test('two fragment indexes on distinct tables in one database are independent', async () => {\n const a = (await SqliteVecFragmentIndex.create({ database: db, tableName: 'frag_a' })).orThrow();\n const b = (await SqliteVecFragmentIndex.create({ database: db, tableName: 'frag_b' })).orThrow();\n (await a.addFragments(target('s', 'one'), [frag(0, 5, 1, 0)])).orThrow();\n expect(a.fragmentCount).toBe(1);\n expect(b.fragmentCount).toBe(0);\n });\n });\n\n describe('persistence across reopen (the durability guarantee)', () => {\n let dir: string;\n let dbPath: string;\n\n beforeEach(() => {\n dir = fs.mkdtempSync(path.join(os.tmpdir(), 'svfrag-'));\n dbPath = path.join(dir, 'fragments.db');\n });\n afterEach(() => {\n fs.rmSync(dir, { recursive: true, force: true });\n });\n\n test('fragments written to a file survive a close + reopen with no re-embed, dimension + locators recovered', async () => {\n const first = new BetterSqlite3(dbPath);\n const writeIndex = (await SqliteVecFragmentIndex.create({ database: first })).orThrow();\n (\n await writeIndex.addFragments(target('knowledge', 'doc-a'), [\n frag(0, 5, 1, 0, 0),\n frag(5, 12, 0, 1, 0)\n ])\n ).orThrow();\n (\n await writeIndex.addFragments(target('conversations/c', 'turn-1'), [frag(0, 8, 0.9, 0.1, 0)])\n ).orThrow();\n first.close();\n\n // Second session: a brand-new connection + index over the same file. No adds\n // (no re-embedding) — fragments, dimension, and locators come straight off disk.\n const second = new BetterSqlite3(dbPath);\n const reopened = (await SqliteVecFragmentIndex.create({ database: second })).orThrow();\n try {\n expect(reopened.recordCount).toBe(2);\n expect(reopened.fragmentCount).toBe(3);\n expect(await reopened.query(Float32Array.from([1, 0, 0]), 3)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].target).toEqual(target('knowledge', 'doc-a'));\n expect(hits[0].locator).toEqual(loc(0, 5));\n expect(hits[0].score).toBeCloseTo(1, 5);\n // the cross-scope target round-trips its full (scope, id) and locator\n expect(hits[1].target).toEqual(target('conversations/c', 'turn-1'));\n expect(hits[1].locator).toEqual(loc(0, 8));\n }\n );\n // The recovered dimension is enforced on a post-reopen add.\n expect(await reopened.addFragments(target('knowledge', 'w'), [frag(0, 4, 1, 0)])).toFailWith(\n /fragment dimension 2 does not match index dimension 3/i\n );\n // A matching-dimension add still works and persists incrementally.\n (await reopened.addFragments(target('knowledge', 'w'), [frag(0, 4, 0, 0, 1)])).orThrow();\n expect(reopened.recordCount).toBe(3);\n } finally {\n second.close();\n }\n });\n });\n});\n"]}
1
+ {"version":3,"file":"sqliteVecFragmentIndex.test.js","sourceRoot":"","sources":["../../../src/test/unit/sqliteVecFragmentIndex.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport '@fgv/ts-utils-jest';\n\nimport BetterSqlite3 from 'better-sqlite3';\nimport { load as loadSqliteVec } from 'sqlite-vec';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\nimport {\n IEdgeTarget,\n IEmbeddedFragment,\n IFragmentLocator,\n IVectorQueryHit,\n MemoryId,\n MemoryScopeKey\n} from '@fgv/ts-agent-memory';\nimport { SqliteVecFragmentIndex } from '../../index';\n\nfunction target(scope: string, id: string): IEdgeTarget {\n return { scope: scope as unknown as MemoryScopeKey, id: id as unknown as MemoryId };\n}\nfunction loc(start: number, end: number): IFragmentLocator {\n return { start, end };\n}\nfunction frag(start: number, end: number, ...values: number[]): IEmbeddedFragment {\n return { locator: loc(start, end), vector: Float32Array.from(values) };\n}\n\ndescribe('SqliteVecFragmentIndex', () => {\n let db: BetterSqlite3.Database;\n\n beforeEach(() => {\n db = new BetterSqlite3(':memory:');\n });\n afterEach(() => {\n // Some tests close `db` themselves to exercise error paths; guard double-close.\n if (db.open) {\n db.close();\n }\n });\n\n async function makeIndex(): Promise<SqliteVecFragmentIndex> {\n return (await SqliteVecFragmentIndex.create({ database: db })).orThrow();\n }\n\n describe('create', () => {\n test('succeeds over a fresh database with an empty index', async () => {\n expect(await SqliteVecFragmentIndex.create({ database: db })).toSucceedAndSatisfy(\n (index: SqliteVecFragmentIndex) => {\n expect(index.recordCount).toBe(0);\n expect(index.fragmentCount).toBe(0);\n }\n );\n });\n\n test('rejects a table name that is not a simple identifier', async () => {\n expect(\n await SqliteVecFragmentIndex.create({ database: db, tableName: 'bad name; DROP TABLE x' })\n ).toFailWith(/not a simple SQL identifier/i);\n });\n\n test('fails loudly when the sqlite-vec extension cannot load (closed database)', async () => {\n const closed = new BetterSqlite3(':memory:');\n closed.close();\n expect(await SqliteVecFragmentIndex.create({ database: closed })).toFailWith(/failed to initialize/i);\n });\n\n test('rejects a pre-existing non-vec0 table of the same name rather than adopting it', async () => {\n db.exec('CREATE TABLE memory_fragments (foo TEXT)');\n expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(\n /auxiliary columns \\[\\] but this index requires \\[start_off, end_off, fragment_id\\]/i\n );\n });\n\n describe('auxiliary-column schema detection', () => {\n // `CREATE VIRTUAL TABLE IF NOT EXISTS` is a no-op against an existing table and\n // vec0 has no `ALTER TABLE ADD COLUMN`, so a database written by an earlier\n // version keeps its narrower column set. Without detection the widened INSERT\n // surfaces an opaque `no such column: fragment_id` at statement-prepare time.\n function createLegacyTable(database: BetterSqlite3.Database): void {\n loadSqliteVec(database);\n database.exec(\n 'CREATE VIRTUAL TABLE memory_fragments USING vec0(' +\n 'target_key TEXT PARTITION KEY, embedding float[2] distance_metric=cosine, ' +\n '+start_off integer, +end_off integer)'\n );\n }\n\n test('fails with an actionable message naming expected and found columns', async () => {\n createLegacyTable(db);\n expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(\n /auxiliary columns \\[start_off, end_off\\] but this index requires \\[start_off, end_off, fragment_id\\]/i\n );\n });\n\n test('states that a drop-and-re-index is required and that no data is lost', async () => {\n createLegacyTable(db);\n expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(\n /cannot be altered in place[\\s\\S]*drop-and-re-index[\\s\\S]*DROP TABLE \"memory_fragments\"[\\s\\S]*costs embedding time, never data/i\n );\n });\n\n test('does not surface the opaque sqlite \"no such column\" error', async () => {\n createLegacyTable(db);\n const created = await SqliteVecFragmentIndex.create({ database: db });\n expect(created).toFail();\n expect(created.isFailure() && created.message).not.toMatch(/no such column/i);\n });\n\n test('accepts a table whose auxiliary columns match, regardless of declaration order', async () => {\n loadSqliteVec(db);\n db.exec(\n 'CREATE VIRTUAL TABLE memory_fragments USING vec0(' +\n 'target_key TEXT PARTITION KEY, embedding float[3] distance_metric=cosine, ' +\n '+fragment_id text, +end_off integer, +start_off integer)'\n );\n expect(await SqliteVecFragmentIndex.create({ database: db })).toSucceed();\n });\n\n test('rejects a table that mimics the auxiliary columns but has no vec0 embedding column', async () => {\n db.exec(\n 'CREATE TABLE memory_fragments (\"+start_off\" integer, \"+end_off\" integer, \"+fragment_id\" text)'\n );\n expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/no vec0 embedding column/i);\n });\n\n test('rejects a table with the right number of columns but a different one', async () => {\n loadSqliteVec(db);\n db.exec(\n 'CREATE VIRTUAL TABLE memory_fragments USING vec0(' +\n 'target_key TEXT PARTITION KEY, embedding float[2] distance_metric=cosine, ' +\n '+start_off integer, +end_off integer, +frag_id text)'\n );\n expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(\n /auxiliary columns \\[start_off, end_off, frag_id\\]/i\n );\n });\n });\n });\n\n describe('addFragments', () => {\n test('stores every fragment and reports the count; tracks record/fragment counts', async () => {\n const index = await makeIndex();\n expect(\n await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0), frag(5, 10, 0, 1)])\n ).toSucceedWith(2);\n expect(index.recordCount).toBe(1);\n expect(index.fragmentCount).toBe(2);\n });\n\n test('whole-record replace — a second addFragments drops the prior fragments', async () => {\n const index = await makeIndex();\n const t = target('knowledge', 'doc-a');\n (await index.addFragments(t, [frag(0, 5, 1, 0), frag(5, 10, 0, 1)])).orThrow();\n expect(await index.addFragments(t, [frag(0, 3, 1, 1)])).toSucceedWith(1);\n expect(index.recordCount).toBe(1);\n expect(index.fragmentCount).toBe(1);\n expect(await index.query(Float32Array.from([1, 1]), 5)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(1);\n expect(hits[0].locator).toEqual(loc(0, 3));\n }\n );\n });\n\n test('an empty fragments array drops an existing record', async () => {\n const index = await makeIndex();\n const t = target('knowledge', 'doc-a');\n (await index.addFragments(t, [frag(0, 5, 1, 0)])).orThrow();\n expect(await index.addFragments(t, [])).toSucceedWith(0);\n expect(index.recordCount).toBe(0);\n expect(index.fragmentCount).toBe(0);\n });\n\n test('an empty fragments array on a fresh index is a no-op (no table created)', async () => {\n const index = await makeIndex();\n expect(await index.addFragments(target('knowledge', 'doc-a'), [])).toSucceedWith(0);\n expect(index.recordCount).toBe(0);\n // A later real add still establishes the dimension cleanly.\n expect(await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 1, 0)])).toSucceedWith(1);\n });\n\n test('same stem in different scopes are distinct entries', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('conversations/a', 'turn-3'), [frag(0, 5, 1, 0)])).orThrow();\n (await index.addFragments(target('conversations/b', 'turn-3'), [frag(0, 5, 0, 1)])).orThrow();\n expect(index.recordCount).toBe(2);\n expect(index.fragmentCount).toBe(2);\n });\n\n test('fails loudly on an empty fragment vector — and stores nothing', async () => {\n const index = await makeIndex();\n expect(\n await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0), frag(5, 10)])\n ).toFailWith(/cannot add 'knowledge\\0doc-a': empty fragment vector/i);\n expect(index.recordCount).toBe(0);\n });\n\n test('fails loudly on a fragment-dimension mismatch against the established dimension', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'a'), [frag(0, 5, 1, 0)])).orThrow();\n expect(await index.addFragments(target('knowledge', 'b'), [frag(0, 5, 1, 0, 0)])).toFailWith(\n /fragment dimension 3 does not match index dimension 2/i\n );\n });\n\n test('rejects a non-safe-integer locator offset up front (never persists an unreadable locator)', async () => {\n const index = await makeIndex();\n // A non-integer offset: reject before the write, with a clear message.\n expect(await index.addFragments(target('knowledge', 'doc-a'), [frag(0.5, 5, 1, 0)])).toFailWith(\n /locator \\[0\\.5, 5\\) offsets must be safe integers/i\n );\n // A too-large (non-safe) integer offset is likewise rejected.\n expect(\n await index.addFragments(target('knowledge', 'doc-b'), [frag(0, Number.MAX_SAFE_INTEGER + 1, 1, 0)])\n ).toFailWith(/offsets must be safe integers/i);\n expect(index.recordCount).toBe(0);\n });\n\n test('a failed multi-fragment add on a fresh index does not establish a dimension (all-or-nothing)', async () => {\n const index = await makeIndex();\n // dim 2 then dim 3 in the same batch: fails, and must NOT commit dim 2.\n expect(\n await index.addFragments(target('knowledge', 'doc-1'), [frag(0, 5, 1, 0), frag(5, 10, 1, 0, 0)])\n ).toFailWith(/fragment dimension 3 does not match index dimension 2/i);\n expect(index.recordCount).toBe(0);\n // A fresh dim-3 record now indexes cleanly (the index was never poisoned to dim 2).\n expect(await index.addFragments(target('knowledge', 'doc-2'), [frag(0, 5, 1, 0, 0)])).toSucceedWith(1);\n });\n\n test('fails loudly (best-effort caller unaffected) when the underlying add throws', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n db.close();\n expect(await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 0, 1)])).toFailWith(\n /cannot add 'knowledge\\0doc-b'/i\n );\n });\n\n test('fails loudly (never silently corrupts) when the table name collides with a non-vec0 table', async () => {\n // A plain table already occupies the default name. `CREATE VIRTUAL TABLE IF NOT\n // EXISTS` no-ops against it, so the collision must fail loudly rather than\n // corrupt state — `create` now catches it up front via the auxiliary-column\n // check, so the index is never handed out at all.\n db.exec('CREATE TABLE memory_fragments (foo TEXT)');\n expect(await SqliteVecFragmentIndex.create({ database: db })).toFailWith(/auxiliary columns/i);\n });\n });\n\n describe('query', () => {\n async function seeded(): Promise<SqliteVecFragmentIndex> {\n const index = await makeIndex();\n (\n await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0), frag(5, 10, 0, 1)])\n ).orThrow();\n (await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 1, 1)])).orThrow();\n return index;\n }\n\n test('returns fragment hits in descending score order, each carrying its locator', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 3)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].target.id).toBe('doc-a');\n expect(hits[0].locator).toEqual(loc(0, 5));\n expect(hits[0].score).toBeCloseTo(1, 5);\n expect(hits[1].target.id).toBe('doc-b');\n expect(hits[1].score).toBeCloseTo(1 / Math.sqrt(2), 5);\n expect(hits[2].target.id).toBe('doc-a');\n expect(hits[2].locator).toEqual(loc(5, 10));\n expect(hits[2].score).toBeCloseTo(0, 5);\n }\n );\n });\n\n test('truncates to topK', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 2)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(2);\n expect(hits.map((h) => h.target.id)).toEqual(['doc-a', 'doc-b']);\n }\n );\n });\n\n test('maxPerRecord caps fragments per record during selection (before the topK cut)', async () => {\n const index = await makeIndex();\n (\n await index.addFragments(target('knowledge', 'doc-a'), [\n frag(0, 5, 1, 0),\n frag(5, 10, 0.9, 0.1),\n frag(10, 15, 0.8, 0.2)\n ])\n ).orThrow();\n (await index.addFragments(target('knowledge', 'doc-b'), [frag(0, 5, 0.7, 0.3)])).orThrow();\n // Without a cap the top-2 would be doc-a twice; maxPerRecord=1 surfaces doc-b.\n expect(await index.query(Float32Array.from([1, 0]), 2, 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(2);\n expect(hits.map((h) => h.target.id)).toEqual(['doc-a', 'doc-b']);\n expect(hits[0].locator).toEqual(loc(0, 5));\n }\n );\n });\n\n test('maxPerRecord=0 yields no hits', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 5, 0)).toSucceedWith([]);\n });\n\n test('maxPerRecord larger than any record leaves the ranking unchanged', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 5, 10)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(3);\n expect(hits[0].target.id).toBe('doc-a');\n }\n );\n });\n\n test('returns empty for a non-positive topK', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 0)).toSucceedWith([]);\n expect(await index.query(Float32Array.from([1, 0]), -5)).toSucceedWith([]);\n });\n\n test('returns empty before any add (no established dimension)', async () => {\n const index = await makeIndex();\n expect(await index.query(Float32Array.from([1, 0, 0]), 5)).toSucceedWith([]);\n });\n\n test('returns empty when a capped query runs against an emptied (but existing) table', async () => {\n const index = await makeIndex();\n const t = target('knowledge', 'doc-a');\n (await index.addFragments(t, [frag(0, 5, 1, 0)])).orThrow();\n (await index.addFragments(t, [])).orThrow(); // table now exists but holds 0 rows\n // fetchK derives from the (zero) fragment count under a cap → short-circuits to [].\n expect(await index.query(Float32Array.from([1, 0]), 5, 2)).toSucceedWith([]);\n });\n\n test('rejects a query vector of the wrong dimension', async () => {\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0, 0]), 3)).toFailWith(\n /query dimension 3 does not match index dimension 2/i\n );\n });\n\n test('a capped query stops at topK even when more ranked rows remain', async () => {\n // maxPerRecord makes the fetch span the full ranked set (3 fragments), but\n // topK=1 must return exactly one hit — the top row — and stop.\n const index = await seeded();\n expect(await index.query(Float32Array.from([1, 0]), 1, 5)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits).toHaveLength(1);\n expect(hits[0].target.id).toBe('doc-a');\n expect(hits[0].locator).toEqual(loc(0, 5));\n }\n );\n });\n\n test('fails loudly when the underlying query throws', async () => {\n const index = await seeded();\n db.close();\n expect(await index.query(Float32Array.from([1, 0]), 3)).toFailWith(/query failed/i);\n });\n });\n\n describe('remove', () => {\n test('removes every fragment of a record and is reflected in subsequent queries', async () => {\n const index = await makeIndex();\n const a = target('knowledge', 'doc-a');\n const b = target('knowledge', 'doc-b');\n (await index.addFragments(a, [frag(0, 5, 1, 0), frag(5, 10, 1, 0)])).orThrow();\n (await index.addFragments(b, [frag(0, 5, 0, 1)])).orThrow();\n expect(await index.remove(a)).toSucceedWith(a);\n expect(index.recordCount).toBe(1);\n expect(index.fragmentCount).toBe(1);\n expect(await index.query(Float32Array.from([1, 0]), 5)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits.map((h) => h.target.id)).toEqual(['doc-b']);\n }\n );\n });\n\n test('is idempotent — removing a missing target succeeds', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n expect(await index.remove(target('knowledge', 'missing'))).toSucceedWith(\n target('knowledge', 'missing')\n );\n expect(index.recordCount).toBe(1);\n });\n\n test('succeeds before any add (no table yet)', async () => {\n const index = await makeIndex();\n expect(await index.remove(target('knowledge', 'doc-a'))).toSucceedWith(target('knowledge', 'doc-a'));\n expect(index.recordCount).toBe(0);\n });\n\n test('fails loudly when the underlying remove throws', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n db.close();\n expect(await index.remove(target('knowledge', 'doc-a'))).toFailWith(\n /cannot remove 'knowledge\\0doc-a'/i\n );\n });\n });\n\n describe('safe-integer mode and corrupt persisted data', () => {\n const toBlob = (...v: number[]): Uint8Array => new Uint8Array(Float32Array.from(v).buffer);\n\n async function seededWithRow(): Promise<SqliteVecFragmentIndex> {\n // A valid add creates the table and establishes dim 2; corrupt rows are then\n // inserted directly to model externally-edited / safe-integer-mode data.\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n return index;\n }\n\n function insertRaw(key: string, start: bigint, end: bigint, ...vec: number[]): void {\n db.prepare(\n 'INSERT INTO memory_fragments(target_key, embedding, start_off, end_off) VALUES (?, ?, ?, ?)'\n ).run(key, toBlob(...vec), start, end);\n }\n\n /** Insert a row with arbitrary (possibly NULL) identity columns, bypassing the write-side guards. */\n function insertRawIdentity(\n key: string,\n start: bigint | null,\n end: bigint | null,\n fragmentId: string | null,\n ...vec: number[]\n ): void {\n db.prepare(\n 'INSERT INTO memory_fragments(target_key, embedding, start_off, end_off, fragment_id) ' +\n 'VALUES (?, ?, ?, ?, ?)'\n ).run(key, toBlob(...vec), start, end, fragmentId);\n }\n\n test('fails loudly when a stored locator has a start offset but no end offset', async () => {\n // `Number(null)` is 0, so coercing a half-NULL pair would silently fabricate a\n // span rather than surface the corruption.\n const index = await seededWithRow();\n insertRawIdentity('knowledge\\0doc-b', BigInt(3), null, 'frag-1', 0, 1);\n expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(\n /locator has only one of its start\\/end offsets/i\n );\n });\n\n test('fails loudly when a stored locator has an end offset but no start offset', async () => {\n const index = await seededWithRow();\n insertRawIdentity('knowledge\\0doc-b', null, BigInt(9), 'frag-1', 0, 1);\n expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(\n /locator has only one of its start\\/end offsets/i\n );\n });\n\n test('fails loudly when a stored row carries neither a locator nor a fragment id', async () => {\n const index = await seededWithRow();\n insertRawIdentity('knowledge\\0doc-b', null, null, null, 0, 1);\n expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(\n /carries neither a locator nor a fragment id/i\n );\n });\n\n test('coerces bigint offsets (better-sqlite3 safe-integer mode) to number locators', async () => {\n const index = await seededWithRow();\n // Under safe-integer mode every integer column comes back as a bigint.\n db.defaultSafeIntegers(true);\n expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n const locator = hits[0].locator;\n expect(locator).toEqual(loc(0, 5));\n expect(typeof locator?.start).toBe('number');\n expect(typeof locator?.end).toBe('number');\n }\n );\n });\n\n test('fails loudly when a stored offset is outside the safe-integer range', async () => {\n const index = await seededWithRow();\n // Safe-integer mode returns the huge offset as a bigint (no read-time throw),\n // so the _toOffset guard is what must fire.\n db.defaultSafeIntegers(true);\n insertRaw('knowledge\\0doc-b', BigInt(2) ** BigInt(60), BigInt(0), 0, 1);\n expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(\n /locator offset .* is not a safe integer/i\n );\n });\n\n test('fails loudly when a stored key is missing the NUL separator', async () => {\n const index = await seededWithRow();\n insertRaw('nonulkey', BigInt(0), BigInt(5), 0, 1);\n expect(await index.query(Float32Array.from([0, 1]), 5)).toFailWith(/missing scope\\/id separator/i);\n });\n });\n\n describe('fragment identity', () => {\n /** A fragment identified only by an opaque id — no honest body span. */\n function idFrag(fragmentId: string, ...values: number[]): IEmbeddedFragment {\n return { fragmentId, vector: Float32Array.from(values) };\n }\n\n test('rejects a fragment carrying neither a locator nor a fragmentId', async () => {\n const index = await makeIndex();\n expect(\n await index.addFragments(target('knowledge', 'doc-a'), [{ vector: Float32Array.from([1, 0]) }])\n ).toFailWith(/at least one of 'locator' or 'fragmentId'/i);\n expect(index.fragmentCount).toBe(0);\n });\n\n test('carries an opaque fragmentId through to the query hit verbatim', async () => {\n const index = await makeIndex();\n const opaque = 'urn:frag:9f8e::{not-parsed}';\n (await index.addFragments(target('knowledge', 'doc-a'), [idFrag(opaque, 1, 0)])).orThrow();\n expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].fragmentId).toBe(opaque);\n expect(hits[0].locator).toBeUndefined();\n }\n );\n });\n\n test('carries both identities when a fragment supplies both', async () => {\n const index = await makeIndex();\n (\n await index.addFragments(target('knowledge', 'doc-a'), [\n { ...frag(2, 8, 1, 0), fragmentId: 'frag-1' }\n ])\n ).orThrow();\n expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].locator).toEqual(loc(2, 8));\n expect(hits[0].fragmentId).toBe('frag-1');\n }\n );\n });\n\n test('a locator-only fragment produces a hit with no fragmentId key at all', async () => {\n // Byte-identical to what this index produced before `fragment_id` existed: the\n // key is absent, not present-and-undefined, so an existing caller's structural\n // comparisons are unaffected by the addition.\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [frag(0, 5, 1, 0)])).orThrow();\n expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(Object.keys(hits[0]).sort()).toEqual(['locator', 'score', 'target']);\n expect(hits[0]).toStrictEqual({\n target: target('knowledge', 'doc-a'),\n score: hits[0].score,\n locator: loc(0, 5)\n });\n }\n );\n });\n\n test('an id-only fragment produces a hit with no locator key at all', async () => {\n const index = await makeIndex();\n (await index.addFragments(target('knowledge', 'doc-a'), [idFrag('frag-1', 1, 0)])).orThrow();\n expect(await index.query(Float32Array.from([1, 0]), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(Object.keys(hits[0]).sort()).toEqual(['fragmentId', 'score', 'target']);\n }\n );\n });\n\n test('skips the safe-integer offset check for a fragment with no locator', async () => {\n // The write-side offset validation must not fire (or throw on `BigInt(undefined)`)\n // when there is no locator to validate.\n const index = await makeIndex();\n expect(await index.addFragments(target('knowledge', 'doc-a'), [idFrag('frag-1', 1, 0)])).toSucceedWith(\n 1\n );\n });\n\n test('still rejects a non-safe-integer offset when a locator IS supplied', async () => {\n const index = await makeIndex();\n expect(\n await index.addFragments(target('knowledge', 'doc-a'), [\n { locator: loc(0.5, 5), fragmentId: 'frag-1', vector: Float32Array.from([1, 0]) }\n ])\n ).toFailWith(/offsets must be safe integers/i);\n });\n\n test('round-trips every identity shape across a close + reopen', async () => {\n const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'svfragid-'));\n const dbPath = path.join(dir, 'fragments.db');\n const first = new BetterSqlite3(dbPath);\n try {\n const writeIndex = (await SqliteVecFragmentIndex.create({ database: first })).orThrow();\n (\n await writeIndex.addFragments(target('knowledge', 'doc-a'), [\n frag(0, 5, 1, 0),\n idFrag('frag-rewritten', 0, 1),\n { ...frag(5, 9, 0.9, 0.1), fragmentId: 'frag-both' }\n ])\n ).orThrow();\n } finally {\n first.close();\n }\n\n const second = new BetterSqlite3(dbPath);\n try {\n const reopened = (await SqliteVecFragmentIndex.create({ database: second })).orThrow();\n expect(reopened.fragmentCount).toBe(3);\n expect(await reopened.query(Float32Array.from([1, 0]), 3)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n const byShape = new Map(hits.map((h) => [h.fragmentId ?? '<none>', h]));\n expect(byShape.get('<none>')?.locator).toEqual(loc(0, 5));\n expect(byShape.get('frag-rewritten')?.locator).toBeUndefined();\n expect(byShape.get('frag-both')?.locator).toEqual(loc(5, 9));\n }\n );\n } finally {\n second.close();\n fs.rmSync(dir, { recursive: true, force: true });\n }\n });\n });\n\n describe('custom table name', () => {\n test('two fragment indexes on distinct tables in one database are independent', async () => {\n const a = (await SqliteVecFragmentIndex.create({ database: db, tableName: 'frag_a' })).orThrow();\n const b = (await SqliteVecFragmentIndex.create({ database: db, tableName: 'frag_b' })).orThrow();\n (await a.addFragments(target('s', 'one'), [frag(0, 5, 1, 0)])).orThrow();\n expect(a.fragmentCount).toBe(1);\n expect(b.fragmentCount).toBe(0);\n });\n });\n\n describe('persistence across reopen (the durability guarantee)', () => {\n let dir: string;\n let dbPath: string;\n\n beforeEach(() => {\n dir = fs.mkdtempSync(path.join(os.tmpdir(), 'svfrag-'));\n dbPath = path.join(dir, 'fragments.db');\n });\n afterEach(() => {\n fs.rmSync(dir, { recursive: true, force: true });\n });\n\n test('fragments written to a file survive a close + reopen with no re-embed, dimension + locators recovered', async () => {\n const first = new BetterSqlite3(dbPath);\n const writeIndex = (await SqliteVecFragmentIndex.create({ database: first })).orThrow();\n (\n await writeIndex.addFragments(target('knowledge', 'doc-a'), [\n frag(0, 5, 1, 0, 0),\n frag(5, 12, 0, 1, 0)\n ])\n ).orThrow();\n (\n await writeIndex.addFragments(target('conversations/c', 'turn-1'), [frag(0, 8, 0.9, 0.1, 0)])\n ).orThrow();\n first.close();\n\n // Second session: a brand-new connection + index over the same file. No adds\n // (no re-embedding) — fragments, dimension, and locators come straight off disk.\n const second = new BetterSqlite3(dbPath);\n const reopened = (await SqliteVecFragmentIndex.create({ database: second })).orThrow();\n try {\n expect(reopened.recordCount).toBe(2);\n expect(reopened.fragmentCount).toBe(3);\n expect(await reopened.query(Float32Array.from([1, 0, 0]), 3)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].target).toEqual(target('knowledge', 'doc-a'));\n expect(hits[0].locator).toEqual(loc(0, 5));\n expect(hits[0].score).toBeCloseTo(1, 5);\n // the cross-scope target round-trips its full (scope, id) and locator\n expect(hits[1].target).toEqual(target('conversations/c', 'turn-1'));\n expect(hits[1].locator).toEqual(loc(0, 8));\n }\n );\n // The recovered dimension is enforced on a post-reopen add.\n expect(await reopened.addFragments(target('knowledge', 'w'), [frag(0, 4, 1, 0)])).toFailWith(\n /fragment dimension 2 does not match index dimension 3/i\n );\n // A matching-dimension add still works and persists incrementally.\n (await reopened.addFragments(target('knowledge', 'w'), [frag(0, 4, 0, 0, 1)])).orThrow();\n expect(reopened.recordCount).toBe(3);\n } finally {\n second.close();\n }\n });\n });\n});\n"]}
@@ -63,12 +63,25 @@ export declare interface ISqliteVecVectorIndexCreateParams {
63
63
  * @remarks
64
64
  * Where {@link SqliteVecVectorIndex} keys one vector per record on a
65
65
  * `target_key` primary key, this index holds **many** vectors per record — one per
66
- * in-record `[start, end)` span — so it keys the `vec0` table on `target_key` as a
67
- * **`PARTITION KEY`** (many rows may share it) and stores each fragment's locator
68
- * offsets in two auxiliary columns (`+start_off`, `+end_off`) that ride alongside
69
- * the vector and are returned on query but never filtered. A query is a brute-force
70
- * `vec0` KNN scan across all partitions returning per-fragment hits, each carrying
71
- * its record `target` and the matched `locator`.
66
+ * fragment — so it keys the `vec0` table on `target_key` as a **`PARTITION KEY`**
67
+ * (many rows may share it) and stores each fragment's identity in three auxiliary
68
+ * columns (`+start_off`, `+end_off`, `+fragment_id`) that ride alongside the vector
69
+ * and are returned on query but never filtered in particular `fragment_id` is
70
+ * stored and returned verbatim, never parsed and never part of the query path. A
71
+ * query is a brute-force `vec0` KNN scan across all partitions returning per-fragment
72
+ * hits, each carrying its record `target` plus whichever identity fields the stored
73
+ * fragment was added with (a fragment must carry at least one).
74
+ *
75
+ * **`vec0` schema changes require a drop-and-re-index.** A
76
+ * `CREATE VIRTUAL TABLE IF NOT EXISTS` is a no-op against an existing table (SQLite
77
+ * does not compare schemas) and `vec0` has no `ALTER TABLE ADD COLUMN`, so a database written by an
78
+ * earlier version of this package keeps its old auxiliary columns. `create` detects
79
+ * that by parsing the stored `CREATE VIRTUAL TABLE` SQL and fails with an actionable
80
+ * message naming the expected and found columns, rather than letting a widened
81
+ * `INSERT` surface an opaque `no such column` at statement-prepare time. There are no
82
+ * in-place migrations: drop the table (or use a fresh `tableName`) and re-index.
83
+ * Fragment vectors are re-derivable from the records, so this costs embedding time,
84
+ * never data.
72
85
  *
73
86
  * Semantics match `InMemoryFragmentCosineIndex` exactly: `addFragments` is
74
87
  * whole-record-replace (a single transaction deletes every prior fragment of the
@@ -100,12 +113,15 @@ export declare class SqliteVecFragmentIndex implements IFragmentVectorIndex {
100
113
  /**
101
114
  * Family-convention factory. Loads the `sqlite-vec` extension onto the supplied
102
115
  * `better-sqlite3` connection and, if the fragment table already exists (a
103
- * reopened persistent file), recovers its established dimension so no
104
- * re-embedding is needed on open.
116
+ * reopened persistent file), verifies its auxiliary-column set matches this
117
+ * version's and recovers its established dimension so no re-embedding is needed on
118
+ * open.
105
119
  *
106
120
  * @param params - See {@link ISqliteVecFragmentIndexCreateParams}.
107
121
  * @returns `Success` with the index, or `Failure` if the table name is not a
108
- * simple identifier or the extension fails to load.
122
+ * simple identifier, the extension fails to load, or the existing table was
123
+ * written by a version with a different auxiliary-column set (which requires a
124
+ * drop-and-re-index — `vec0` cannot be altered in place).
109
125
  */
110
126
  static create(params: ISqliteVecFragmentIndexCreateParams): Promise<Result<SqliteVecFragmentIndex>>;
111
127
  /** {@inheritDoc IFragmentVectorIndex.addFragments} */
@@ -114,16 +130,57 @@ export declare class SqliteVecFragmentIndex implements IFragmentVectorIndex {
114
130
  remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
115
131
  /** {@inheritDoc IFragmentVectorIndex.query} */
116
132
  query(vector: Float32Array, topK: number, maxPerRecord?: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
117
- /** Create the fragment `vec0` virtual table with the established dimension. */
133
+ /**
134
+ * Create the fragment `vec0` virtual table with the established dimension. The
135
+ * auxiliary columns must stay in sync with `AUXILIARY_COLUMNS`, which
136
+ * `create` compares against an existing table's stored DDL.
137
+ */
118
138
  private _createTable;
119
139
  /** Prepare the statements the index reuses. Requires the table to exist. */
120
140
  private _prepare;
121
141
  /**
122
142
  * Recover the established dimension of an existing fragment `vec0` table from its
123
- * stored `CREATE VIRTUAL TABLE` SQL (`float[<n>]`). Returns `undefined` when the
143
+ * stored `CREATE VIRTUAL TABLE` SQL (`float[<n>]`), after checking that the table's
144
+ * auxiliary columns match `AUXILIARY_COLUMNS`. Returns `undefined` when the
124
145
  * table does not exist yet (a fresh database — dimension is set by the first add).
146
+ *
147
+ * Throws when a table of that name exists but is not a usable fragment index (a
148
+ * mismatched auxiliary-column set, or no `vec0` embedding column); the caller runs
149
+ * this inside `captureResult`, so it surfaces as a loud `Failure` from `create`.
150
+ * The same stored DDL answers every one of those questions, so the checks cost
151
+ * nothing extra.
125
152
  */
126
153
  private static _readExistingDimension;
154
+ /**
155
+ * Compare an existing table's auxiliary columns against `AUXILIARY_COLUMNS`.
156
+ *
157
+ * `CREATE VIRTUAL TABLE IF NOT EXISTS` is a no-op against an existing table (SQLite
158
+ * never compares schemas) and `vec0` has no `ALTER TABLE ADD COLUMN`, so a table
159
+ * written by an earlier version of this package silently keeps its old columns and
160
+ * only fails later — as an opaque `no such column` when the widened `INSERT` is
161
+ * prepared. Detect it here instead and say what to do about it. Order is not
162
+ * compared: every statement names its columns explicitly, so only the set matters.
163
+ */
164
+ private static _verifyAuxiliaryColumns;
165
+ /**
166
+ * Rebuild the identity fields of a hit from a persisted row, omitting each field
167
+ * the stored fragment did not carry (so a hit is structurally identical to one this
168
+ * index produced before `fragment_id` existed).
169
+ *
170
+ * A row carrying neither identity violates the write-side invariant and could not
171
+ * be resolved by the caller, so it fails loudly instead of yielding an anonymous
172
+ * hit.
173
+ */
174
+ private static _toIdentity;
175
+ /**
176
+ * Rebuild a fragment's locator from its persisted offsets, or `undefined` when the
177
+ * fragment was stored without one (both offsets `NULL`).
178
+ *
179
+ * The pair is written all-or-nothing, so a half-`NULL` pair can only come from
180
+ * corrupt / externally-edited data. Throw rather than coerce — `Number(null)` is
181
+ * `0`, which would silently fabricate a span starting at the top of the body.
182
+ */
183
+ private static _toLocator;
127
184
  /** Pack a `Float32Array` as the little-endian byte blob `vec0` stores. Copies, so the caller may reuse its buffer. */
128
185
  private static _toBlob;
129
186
  /**