feat(vector): the vectored-noun scalar joins the count ledger; the open gate closes the vector leg
All checks were successful
CI / Node 24 (push) Successful in 12m22s
CI / Node 22 (push) Successful in 12m32s
CI / Integration + conformance (Node 22) (push) Successful in 19m42s
CI / Bun (latest) (push) Successful in 12m15s

The coverage denominator the health-by-accounting ratification named for
the vector family — never built until now, and its absence was measured as
the exact outage class it existed to prevent: a migrated store with
canonical vectors and no derived index opened with the vector leg EMPTY,
served [] from vector search with no error, and the report-driven read gate
had nothing to refuse on (the provider's coverage invariant was honestly
unledgered — the denominator was ours to supply).

- getCanonicalCounts() gains vectors: { all } — the count of canonical
  nouns holding a REAL vector. Incremented where a vector lands (the
  isNew-gated metadata seam for explicit vectors — the same discipline that
  keeps HNSW neighbor-link re-saves from inflating counts; a narrow
  noteVectorLanded hook for the deferred-embed landing, gated on the
  worker's own pre-embed read). Decremented on a proven delete of a
  vectored noun; a vector-uncertain delete marks the ledger suspect rather
  than guessing (no new reads on the delete path). Recounted by the
  sanctioned recount; legacy counts.json derives it once (a deferred noun's
  vector file exists with an empty vector, so presence requires one
  content read at derivation — never on the hot path).
- The open gate's vector leg: when a health-reporting provider claims
  serving while the index holds zero nodes and the ledger proves vectored
  canonical rows exist, open BUILDS (narrated) — routed through the
  provider's idempotent fillFromCanonical() when exposed (the joint door;
  a partial shortfall stays repair()'s operator business), the JS rebuild
  otherwise — or fails typed pre-serve. Scoped exactly: bare isReady()
  providers, migrating providers, and white-box size stubs open as before.

Pinned end-to-end from the partner gate's probe shape (store with vectored
canonical rows, no derived index, reopen → search serves N, never []),
red-proved against the pre-fix path; the inverse (zero vectored rows) opens
without building and serves [] honestly.
This commit is contained in:
David Snelling 2026-08-25 15:31:19 -07:00
parent bce2593e24
commit 9730835bdf
10 changed files with 851 additions and 32 deletions

View file

@ -520,6 +520,12 @@ export class MemoryStorage extends BaseStorage {
let totalNouns = 0
let totalVerbs = 0
// Vectored-noun scalar: unlike the bare presence check above, this needs
// the vectors.json RECORD'S content — a deferred-embed noun's record
// exists with an empty `vector: []` until its embed lands. In-memory this
// is a free field access (no I/O), unlike the filesystem adapter's
// per-noun disk read.
let totalVectoredNouns = 0
// Scan all paths in objectStore
for (const path of this.objectStore.keys()) {
@ -528,6 +534,10 @@ export class MemoryStorage extends BaseStorage {
if (nounMatch) {
// Type is in metadata, not path - just count total
totalNouns++
const record = this.objectStore.get(path) as { vector?: unknown } | undefined
if (Array.isArray(record?.vector) && record.vector.length > 0) {
totalVectoredNouns++
}
}
// Count verbs (entities/verbs/{shard}/{id}/vectors.json)
@ -543,6 +553,7 @@ export class MemoryStorage extends BaseStorage {
// A scan of every canonical record IS the ALL-visibility count.
this.totalNounCountAll = totalNouns
this.totalVerbCountAll = totalVerbs
this.totalVectoredNounCount = totalVectoredNouns
this.allCountsSuspect = false
}