T51 Rebuildable Vector Index Validation
T51 Rebuildable Vector Index Validation
Scope
- Task: T51 — Implement optional sqlite-vec generations and lexical fallback
- Requirements: VES-MEM-001…003
- Commit target:
feat(memory): add rebuildable vector index - Focused evidence: 35 cases (19 integration and 16 fault injection)
- Required minimum: 25 integration/fault cases
T51 adds an optional, exact-pinned sqlite-vec adapter over T50’s authoritative relational and FTS5 memory. Semantic data is a replaceable per-Workspace/Project projection: each generation binds the current lexical authority, embedding model identity, exact active chunks, Float32 embedding bytes, qualified extension runtime, and a two-slot atomic publication protocol. Disabled and preferred profiles preserve lexical-only operation; only an explicitly required semantic profile fails closed when the extension or a verified generation is unavailable.
Deterministic gates
| Command | Result |
|---|---|
node --test tests/integration/memory-vector-index.test.mjs tests/fault-injection/memory-vector-index-faults.test.mjs |
PASS — 35 passed, 0 failed/skipped |
node --test tests/architecture/*.test.mjs |
PASS — 10 passed, 0 failed/skipped |
node scripts/gate.mjs full |
PASS — format, lint, typecheck, 1,518 unit/property, 382 contract, 309 integration, 16 E2E, and 90 fault cases |
Adequacy matrix
| Done-when criterion / spec AC | Exact assertion evidence | Spec-defined outcome | Result |
|---|---|---|---|
| Only the qualified sqlite-vec artifact executes | tests/integration/memory-vector-index.test.mjs:48-66 — exact package/runtime version, byte length and SHA-256; connection is locked against later extension loads |
Native code identity is explicit and extension loading is temporary | PASS |
| Optional semantic retrieval preserves lexical-only operation | tests/integration/memory-vector-index.test.mjs:68-115 — disabled, missing, checksum-mismatched, and version-mismatched extension cases; explicit required-mode failure |
Incompatible/corrupt/missing extension never blocks lexical authority unless the profile requires semantic retrieval | PASS |
| A generation is complete, content-addressed, and deterministic | tests/integration/memory-vector-index.test.mjs:117-139,269-281 — verified generation metadata, order convergence, and identity changes for model/authority/vector changes |
Equal evidence converges; materially different evidence cannot alias | PASS |
| Retrieval uses real sqlite-vec and exact scope | tests/integration/memory-vector-index.test.mjs:141-174 — nearest-neighbor query, provenance-bound untrusted identity, Workspace/Project isolation |
Semantic candidates come from the requested scope and remain untrusted | PASS |
| Metadata is explicit and never stores vectors as JSON | tests/integration/memory-vector-index.test.mjs:176-186 — model/runtime/vector digests present; serialized metadata contains no embedding values |
Rebuild metadata is auditable without duplicating vector payloads | PASS |
| Generation replacement verifies before atomic swap | tests/integration/memory-vector-index.test.mjs:188-201; tests/fault-injection/memory-vector-index-faults.test.mjs:98-184 — inactive slot, rollback at insert/verify/pre-swap, post-commit acknowledgement convergence |
A failed replacement leaves the prior active generation usable or no generation published | PASS |
| Vector state never becomes lexical authority | tests/integration/memory-vector-index.test.mjs:204-236 — stable lexical state digest, valid backup with vec tables, clear-and-rebuild identity |
Derived state can be discarded without changing canonical memory | PASS |
| Authority change makes a vector generation stale | tests/integration/memory-vector-index.test.mjs:239-255; tests/fault-injection/memory-vector-index-faults.test.mjs:70-96,114-131 — missing/forged/stale inputs and TOCTOU mutation under writer lock |
Semantic results never survive divergence from active lexical evidence | PASS |
| Reopen verifies the complete active generation | tests/integration/memory-vector-index.test.mjs:257-267; tests/fault-injection/memory-vector-index-faults.test.mjs:187-248 — missing table, required corruption, member digest and control-slot tampering |
Structurally valid but semantically inconsistent vector state is rejected before retrieval | PASS |
| Invalid vectors and contention are atomic and recoverable | tests/fault-injection/memory-vector-index-faults.test.mjs:41-112,250-271 — dimension, finite-number, duplicate, completeness, digest, crash and real SQLite lock cases |
Bad input or transient failure writes no partial derived truth and leaves lexical state intact | PASS |
Necessary-test reverse map
| Test range | Maps to | Keep |
|---|---|---|
tests/integration/memory-vector-index.test.mjs:48-115 |
Exact native dependency qualification and profile fallback policy | Yes |
tests/integration/memory-vector-index.test.mjs:117-186 |
Content-bound generation, real KNN, scope, and metadata | Yes |
tests/integration/memory-vector-index.test.mjs:188-236 |
Two-slot replacement and separation from lexical authority | Yes |
tests/integration/memory-vector-index.test.mjs:239-281 |
Staleness, reopen verification, and generation identity | Yes |
tests/fault-injection/memory-vector-index-faults.test.mjs:41-96 |
Closed build input and authority binding | Yes |
tests/fault-injection/memory-vector-index-faults.test.mjs:98-184 |
Transaction, swap, TOCTOU, and acknowledgement failures | Yes |
tests/fault-injection/memory-vector-index-faults.test.mjs:187-248 |
Missing/corrupt/tampered active generation | Yes |
tests/fault-injection/memory-vector-index-faults.test.mjs:250-271 |
Real SQLite writer contention | Yes |
Non-shallow checks
sqlite-vecis pinned exactly to0.1.9; the runtime version, loadable asset byte count, and SHA-256 are checked before use. Native extension loading is disabled immediately after the controlled bootstrap.- Build input is closed-schema and complete. It must contain exactly one finite Float32 embedding for every active authoritative chunk and may not introduce foreign chunk identities or content digests.
- Embedding digests use explicit IEEE-754 Float32 little-endian bytes. They do not depend on host JSON number formatting.
- Generation identity binds scope, authority snapshot, source observations, active chunks, model metadata, extension identity, member identities, content digests, embedding digests, and the aggregate vector digest.
- Each Workspace/Project has two safely derived vec0 slots. Replacement builds and verifies the inactive slot inside
BEGIN IMMEDIATE, rechecks authority after acquiring the writer lock, and publishes the control row only after verification. - Reopen and pre-search checks validate control-slot consistency, runtime/model/generation identity, member set and digests, vector row count, vector payload digests, and current authority digest.
- Preferred mode degrades to an explicit availability status; required mode raises a stable recoverable error. Neither path changes T50 relational/FTS records or their canonical state digest.
- Backups remain valid with vec0 tables present, while vector tables and metadata remain excluded from the canonical lexical authority digest.
Verdict
PASS for T51. The semantic index is exact-pinned, optional, scope-isolated, content-bound, atomically replaceable, corruption-detecting, and reproducible. Lexical memory remains authoritative and fully operational without sqlite-vec; semantic retrieval blocks only when a profile explicitly requires it.