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

@ -17,10 +17,11 @@
* (4) LEGACY FILES DERIVE ONCE a counts.json written before the ledger is
* upgraded from the canonical id tree at open, then persisted.
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import * as fs from 'node:fs'
import * as os from 'node:os'
import * as path from 'node:path'
import * as zlib from 'node:zlib'
import { Brainy } from '../../src/index.js'
/** Count canonical `<root>/entities/<kind>/<shard>/<id>` directories — every tier. */
@ -180,3 +181,176 @@ describe('canonical count ledger — ALL-visibility scalars, unclamped totals, r
expect(ledger.nouns.all).toBe(truth)
})
})
/** Count `<root>/entities/nouns/<shard>/<id>/vectors.json[.gz]` files holding a non-empty `vector`. */
function countVectoredNouns(root: string): number {
const base = path.join(root, 'entities', 'nouns')
if (!fs.existsSync(base)) return 0
let n = 0
for (const shard of fs.readdirSync(base)) {
const shardDir = path.join(base, shard)
if (!fs.statSync(shardDir).isDirectory()) continue
for (const id of fs.readdirSync(shardDir)) {
const idDir = path.join(shardDir, id)
if (!fs.statSync(idDir).isDirectory()) continue
const plainPath = path.join(idDir, 'vectors.json')
const gzPath = `${plainPath}.gz`
let record: any = null
if (fs.existsSync(plainPath)) {
record = JSON.parse(fs.readFileSync(plainPath, 'utf-8'))
} else if (fs.existsSync(gzPath)) {
record = JSON.parse(zlib.gunzipSync(fs.readFileSync(gzPath)).toString('utf-8'))
} else {
continue
}
if (Array.isArray(record.vector) && record.vector.length > 0) n++
}
}
return n
}
describe('canonical count ledger — the vectored-noun scalar (the vector leg\'s coverage denominator)', () => {
let dir: string
let brain: any
const open = async () => {
const b: any = new Brainy({
requireSubtype: false,
storage: { type: 'filesystem', path: dir },
silent: true,
dimensions: 384
})
await b.init()
return b
}
/** Baseline vectored count right after a fresh open() init() creates a
* hidden system VFS-root noun that itself carries a real vector, so a
* brand-new store's `vectors.all` is 1, not 0. Tests assert DELTAS off
* this baseline rather than hardcoding it away. */
let baseline: number
beforeEach(async () => {
process.env.BRAINY_DETERMINISTIC_EMBEDDINGS = 'true'
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'brainy-vectored-ledger-'))
brain = await open()
baseline = (await brain.storage.getCanonicalCounts()).vectors.all
})
afterEach(async () => {
vi.restoreAllMocks()
await brain.close?.().catch(() => {})
fs.rmSync(dir, { recursive: true, force: true })
})
it('an explicit-vector add counts immediately; the ledger matches the on-disk vectors.json content', async () => {
await brain.add({ data: 'a', type: 'document', vector: Array(384).fill(0).map((_, i) => Math.sin(i)) })
await brain.add({ data: 'b', type: 'document' }) // embedded (non-deferred) — also a real vector
await brain.flush()
const ledger = await brain.storage.getCanonicalCounts()
expect(ledger.vectors.all).toBe(baseline + 2)
expect(ledger.vectors.all).toBe(countVectoredNouns(dir))
expect(ledger.suspect).toBe(false)
})
it('a deferred-embed add does NOT count until its embed LANDS', async () => {
// Hold the background worker's embed call open under manual control — a
// deterministic embedder is fast enough that the landing could otherwise
// race ahead of the "still unlanded" assertion below.
let resolveEmbed: ((v: number[]) => void) | undefined
vi.spyOn(brain, 'embed').mockImplementation(
() => new Promise<number[]>((resolve) => { resolveEmbed = resolve })
)
const id = await brain.add({ data: 'deferred content', type: 'document', deferEmbedding: true })
await brain.flush()
// Landed nothing yet — the ledger must not count the stub.
let ledger = await brain.storage.getCanonicalCounts()
expect(ledger.vectors.all).toBe(baseline)
expect(ledger.vectors.all).toBe(countVectoredNouns(dir))
// Release the held embed, then cross the barrier: the vector lands
// (system:embed-landing).
resolveEmbed!(Array(384).fill(0).map((_, i) => Math.cos(i)))
await brain.awaitPendingEmbeds()
const landed = await brain.get(id, { includeVectors: true })
expect((landed!.vector as number[]).length).toBeGreaterThan(0)
ledger = await brain.storage.getCanonicalCounts()
expect(ledger.vectors.all).toBe(baseline + 1)
expect(ledger.vectors.all).toBe(countVectoredNouns(dir))
expect(ledger.suspect).toBe(false)
})
it('a proven delete of a vectored noun decrements; a non-vectored (unlanded) delete does not', async () => {
const vectoredId = await brain.add({ data: 'v', type: 'document' }) // real embed, unmocked
// Block the embed worker AFTER the real add above — a deterministic
// embedder is fast enough that the deferred noun below could otherwise
// land before this test observes its "still unlanded" state.
vi.spyOn(brain, 'embed').mockImplementation(() => new Promise(() => {}))
const deferredId = await brain.add({ data: 'd', type: 'document', deferEmbedding: true })
await brain.flush()
expect((await brain.storage.getCanonicalCounts()).vectors.all).toBe(baseline + 1)
await brain.remove(vectoredId)
await brain.flush()
let ledger = await brain.storage.getCanonicalCounts()
expect(ledger.vectors.all).toBe(baseline)
expect(ledger.suspect).toBe(false)
await brain.remove(deferredId) // never had a real vector — no decrement, still unsuspect
await brain.flush()
ledger = await brain.storage.getCanonicalCounts()
expect(ledger.vectors.all).toBe(baseline)
expect(ledger.suspect).toBe(false)
expect(ledger.vectors.all).toBe(countVectoredNouns(dir))
})
it('the recount corrects a tampered vectors.all scalar, surviving reopen', async () => {
await brain.add({ data: 'real 1', type: 'document' })
await brain.add({ data: 'real 2', type: 'document' })
await brain.flush()
const truth = countVectoredNouns(dir)
expect(truth).toBe(baseline + 2)
;(brain.storage as any).totalVectoredNounCount = truth + 40
await (brain.storage as any).persistCounts()
await brain.close()
brain = await open()
// The lie survives reopen (never clamped).
expect((await brain.storage.getCanonicalCounts()).vectors.all).toBe(truth + 40)
await brain.repairIndex()
expect((await brain.storage.getCanonicalCounts()).vectors.all).toBe(truth)
await brain.close()
brain = await open()
expect((await brain.storage.getCanonicalCounts()).vectors.all).toBe(truth)
})
it('a legacy counts.json without totalVectoredNounCount is derived once from vectors.json content and persisted', async () => {
await brain.add({ data: 'one', type: 'document' }) // real embed, unmocked
// Block the embed worker AFTER the real add above — a deterministic
// embedder is fast enough that the deferred noun below could otherwise
// land before close(), which would inflate this test's expected count.
vi.spyOn(brain, 'embed').mockImplementation(() => new Promise(() => {}))
await brain.add({ data: 'two deferred', type: 'document', deferEmbedding: true })
await brain.flush()
await brain.close()
const countsPath = path.join(dir, '_system', 'counts.json')
const raw = JSON.parse(fs.readFileSync(countsPath, 'utf-8'))
expect(typeof raw.totalVectoredNounCount).toBe('number')
delete raw.totalVectoredNounCount
fs.writeFileSync(countsPath, JSON.stringify(raw, null, 2))
brain = await open()
const ledger = await brain.storage.getCanonicalCounts()
expect(ledger.vectors.all).toBe(baseline + 1) // the root + the one non-deferred noun
expect(ledger.vectors.all).toBe(countVectoredNouns(dir))
const persisted = JSON.parse(fs.readFileSync(countsPath, 'utf-8'))
expect(persisted.totalVectoredNounCount).toBe(baseline + 1)
})
})