feat(8.0): asOf at-gen vector defer — provider-served historical semantic search (#35)
A filtered semantic read at a historical generation (db.asOf(g).find({ query, where }))
no longer unconditionally rebuilds an ephemeral JS-HNSW over every at-g vector
(O(n@G), the OOM ceiling the 2026-06-24 scaling audit flagged). When the vector
index is a VersionedIndexProvider that advertises isGenerationVisible(g), Brainy:
1. resolves the at-g metadata∩graph universe from the record-overlay path (no
materialization — it's the metadata-only historical find),
2. routes the vector leg to the provider with { allowedIds, generation }, and
3. composes the at-g entities ranked by the provider's at-g vector distance.
Without a versioned provider (the JS index, or a native one that refuses the
generation) it falls through to the existing materialization — unchanged.
- Seam (A): VectorIndexProvider.search gains an optional `generation?: bigint`
("omitted = now"), the vector mirror of the graph provider's trailing-gen + the
#46 allowedIds field. JsHnswVectorIndex accepts and ignores it (no per-gen
segments → refuse/fall-back posture; Brainy never routes a historical read there).
- Gate: Db.find tries the native at-gen vector path before materialize(); host
exposes canServeVectorAtGeneration + vectorSearchAtGeneration.
- generation is Brainy's u64 commit counter — the same value handed to the graph
index on writes (graphWriteGeneration), so it maps 1:1 to the native side.
Decided lockstep with the cor team (handoff #35 thread: (A) + vector-only). The
gen-g candidate-vector supply for cor's exact-rerank (part-3) is a separate,
non-blocking seam still being confirmed; the honesty guard keeps this path inactive
(falls through to materialize) until cor's native at-gen rerank is live.
Tested: provider routing + at-gen universe correctness (excludes future-born,
applies the filter) + page window via a mock versioned provider; seam-ignore on the
JS index; 38 db-mvcc/db-temporal historical-read tests green (materialize fallback).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:52:09 -07:00
/ * *
* @module tests / integration / db - asof - vector - defer
* @description 8.0 # 35 — a FILTERED semantic / vector read at a historical generation
* defers to a native at - gen ` VersionedIndexProvider ` instead of the O ( n @G ) JS - HNSW
* materialization . Brainy resolves the at - gen metadata ∩ graph universe from the record
* overlay ( no rebuild ) and hands the provider ` { allowedIds, generation } ` ; the
* provider serves the vector leg , brainy composes . CI has no native provider , so this
* registers a faithful MOCK versioned vector index ( it advertises visibility + records
* what it receives ) to lock the routing + the seam . The JS index is NOT versioned , so
* the un - mocked path correctly falls through to materialization .
* /
import { describe , it , expect , beforeEach , afterEach } from 'vitest'
import { Brainy } from '../../src/index.js'
import { NounType } from '../../src/types/graphTypes.js'
import { createTestConfig } from '../helpers/test-factory.js'
/** A versioned vector provider that advertises visibility + records each search. */
function makeVersionedVectorMock ( ranking : string [ ] ) {
feat(8.0): #35 part-3 — supply at-gen candidate vectors for the native exact-rerank
Completes brainy's #35 side. When the at-gen vector gate serves a filtered
semantic read, Brainy now ships the historically-correct candidate vectors so the
native provider reranks against them with zero per-vector FFI crossing — the
provider need not duplicate the per-generation retention Brainy already does.
- New `AtGenerationVectors { ids: BigInt64Array; vectors: Float32Array; dim }` on
the VectorIndexProvider.search options bag (row-major: vectors[i*dim..] == ids[i];
invariant vectors.length === ids.length*dim; ids = the candidate set; dim must
match the index dim). The built-in JS index ignores it.
- buildAtGenerationVectors resolves each universe id's vector AS OF the generation
(the record before-image, or live getNoun when untouched since the pin — not
readNounRaw, whose canonical path is empty under lazy-vector eviction), interns
the id via the shared mapper, and packs row-major. Absent/vectorless/wrong-dim
ids are dropped (not vector-rankable). Bounded by the filtered universe.
Shape + the four clarifications (row-major, ids-are-the-candidate-set, dim-asserted,
filtered-path-only) confirmed with cor in the handoff #35 thread. Inert until cor's
native at-gen rerank advertises isGenerationVisible (honesty guard).
Tested: the mock versioned provider now asserts it receives atGenerationVectors with
the row-major invariant, correct dim, and ids resolving back to the at-gen universe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 16:50:41 -07:00
const calls : Array < {
generation? : bigint
allowedIds? : ReadonlySet < string >
atGenerationVectors ? : { ids : BigInt64Array ; vectors : Float32Array ; dim : number }
} > = [ ]
feat(8.0): asOf at-gen vector defer — provider-served historical semantic search (#35)
A filtered semantic read at a historical generation (db.asOf(g).find({ query, where }))
no longer unconditionally rebuilds an ephemeral JS-HNSW over every at-g vector
(O(n@G), the OOM ceiling the 2026-06-24 scaling audit flagged). When the vector
index is a VersionedIndexProvider that advertises isGenerationVisible(g), Brainy:
1. resolves the at-g metadata∩graph universe from the record-overlay path (no
materialization — it's the metadata-only historical find),
2. routes the vector leg to the provider with { allowedIds, generation }, and
3. composes the at-g entities ranked by the provider's at-g vector distance.
Without a versioned provider (the JS index, or a native one that refuses the
generation) it falls through to the existing materialization — unchanged.
- Seam (A): VectorIndexProvider.search gains an optional `generation?: bigint`
("omitted = now"), the vector mirror of the graph provider's trailing-gen + the
#46 allowedIds field. JsHnswVectorIndex accepts and ignores it (no per-gen
segments → refuse/fall-back posture; Brainy never routes a historical read there).
- Gate: Db.find tries the native at-gen vector path before materialize(); host
exposes canServeVectorAtGeneration + vectorSearchAtGeneration.
- generation is Brainy's u64 commit counter — the same value handed to the graph
index on writes (graphWriteGeneration), so it maps 1:1 to the native side.
Decided lockstep with the cor team (handoff #35 thread: (A) + vector-only). The
gen-g candidate-vector supply for cor's exact-rerank (part-3) is a separate,
non-blocking seam still being confirmed; the honesty guard keeps this path inactive
(falls through to materialize) until cor's native at-gen rerank is live.
Tested: provider routing + at-gen universe correctness (excludes future-born,
applies the filter) + page window via a mock versioned provider; seam-ignore on the
JS index; 38 db-mvcc/db-temporal historical-read tests green (materialize fallback).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:52:09 -07:00
const provider = {
// VersionedIndexProvider quartet (duck-typed by isVersionedIndexProvider).
generation : ( ) = > 0 n ,
isGenerationVisible : ( _g : bigint ) = > true ,
pin : ( _g : bigint ) = > { } ,
release : ( _g : bigint ) = > { } ,
// The at-gen vector leg: record the seam fields, return ranked allowed ids.
search : async ( _vec : number [ ] , _k : number , _filter : unknown , opts : any ) = > {
feat(8.0): #35 part-3 — supply at-gen candidate vectors for the native exact-rerank
Completes brainy's #35 side. When the at-gen vector gate serves a filtered
semantic read, Brainy now ships the historically-correct candidate vectors so the
native provider reranks against them with zero per-vector FFI crossing — the
provider need not duplicate the per-generation retention Brainy already does.
- New `AtGenerationVectors { ids: BigInt64Array; vectors: Float32Array; dim }` on
the VectorIndexProvider.search options bag (row-major: vectors[i*dim..] == ids[i];
invariant vectors.length === ids.length*dim; ids = the candidate set; dim must
match the index dim). The built-in JS index ignores it.
- buildAtGenerationVectors resolves each universe id's vector AS OF the generation
(the record before-image, or live getNoun when untouched since the pin — not
readNounRaw, whose canonical path is empty under lazy-vector eviction), interns
the id via the shared mapper, and packs row-major. Absent/vectorless/wrong-dim
ids are dropped (not vector-rankable). Bounded by the filtered universe.
Shape + the four clarifications (row-major, ids-are-the-candidate-set, dim-asserted,
filtered-path-only) confirmed with cor in the handoff #35 thread. Inert until cor's
native at-gen rerank advertises isGenerationVisible (honesty guard).
Tested: the mock versioned provider now asserts it receives atGenerationVectors with
the row-major invariant, correct dim, and ids resolving back to the at-gen universe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 16:50:41 -07:00
calls . push ( {
generation : opts?.generation ,
allowedIds : opts?.allowedIds ,
atGenerationVectors : opts?.atGenerationVectors
} )
feat(8.0): asOf at-gen vector defer — provider-served historical semantic search (#35)
A filtered semantic read at a historical generation (db.asOf(g).find({ query, where }))
no longer unconditionally rebuilds an ephemeral JS-HNSW over every at-g vector
(O(n@G), the OOM ceiling the 2026-06-24 scaling audit flagged). When the vector
index is a VersionedIndexProvider that advertises isGenerationVisible(g), Brainy:
1. resolves the at-g metadata∩graph universe from the record-overlay path (no
materialization — it's the metadata-only historical find),
2. routes the vector leg to the provider with { allowedIds, generation }, and
3. composes the at-g entities ranked by the provider's at-g vector distance.
Without a versioned provider (the JS index, or a native one that refuses the
generation) it falls through to the existing materialization — unchanged.
- Seam (A): VectorIndexProvider.search gains an optional `generation?: bigint`
("omitted = now"), the vector mirror of the graph provider's trailing-gen + the
#46 allowedIds field. JsHnswVectorIndex accepts and ignores it (no per-gen
segments → refuse/fall-back posture; Brainy never routes a historical read there).
- Gate: Db.find tries the native at-gen vector path before materialize(); host
exposes canServeVectorAtGeneration + vectorSearchAtGeneration.
- generation is Brainy's u64 commit counter — the same value handed to the graph
index on writes (graphWriteGeneration), so it maps 1:1 to the native side.
Decided lockstep with the cor team (handoff #35 thread: (A) + vector-only). The
gen-g candidate-vector supply for cor's exact-rerank (part-3) is a separate,
non-blocking seam still being confirmed; the honesty guard keeps this path inactive
(falls through to materialize) until cor's native at-gen rerank is live.
Tested: provider routing + at-gen universe correctness (excludes future-born,
applies the filter) + page window via a mock versioned provider; seam-ignore on the
JS index; 38 db-mvcc/db-temporal historical-read tests green (materialize fallback).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:52:09 -07:00
const allowed = opts ? . allowedIds as ReadonlySet < string > | undefined
const out : Array < [ string , number ] > = [ ]
let distance = 0.1
for ( const id of ranking ) {
if ( ! allowed || allowed . has ( id ) ) {
out . push ( [ id , distance ] )
distance += 0.1
}
}
return out
} ,
// Unused VectorIndexProvider surface — no-op stubs so close()/flush() are safe.
addItem : async ( ) = > '' ,
removeItem : async ( ) = > true ,
size : ( ) = > 0 ,
clear : ( ) = > { } ,
rebuild : async ( ) = > { } ,
flush : async ( ) = > 0 ,
getPersistMode : ( ) = > 'immediate' as const
}
return { provider , calls }
}
describe ( '#35 asOf filtered vector read defers to the versioned provider' , ( ) = > {
let brain : Brainy
let a : string , b : string , c : string
beforeEach ( async ( ) = > {
brain = new Brainy ( createTestConfig ( ) )
await brain . init ( )
a = await brain . add ( { type : NounType . Document , data : 'alpha machine learning' , metadata : { team : 'x' } } )
b = await brain . add ( { type : NounType . Document , data : 'beta machine learning' , metadata : { team : 'x' } } )
c = await brain . add ( { type : NounType . Document , data : 'gamma cooking' , metadata : { team : 'y' } } )
} )
afterEach ( async ( ) = > {
await brain . close ( )
} )
it ( 'routes to the provider with {allowedIds, generation} (no materialization) — at-gen universe is correct' , async ( ) = > {
const db = brain . now ( ) // pin the generation after a, b, c
// A later write advances the generation → `db` is now historical, and `later`
// (team x) did NOT exist at the pinned generation.
const later = await brain . add ( { type : NounType . Document , data : 'delta machine learning' , metadata : { team : 'x' } } )
// Inject a versioned vector provider that can serve the pinned generation.
const mock = makeVersionedVectorMock ( [ b , a ] ) // ranks b before a
; ( brain as any ) . index = mock . provider
const results = await db . find ( { query : 'machine learning' , where : { team : 'x' } } )
// Served natively — the provider was hit exactly once with the seam fields.
expect ( mock . calls ) . toHaveLength ( 1 )
expect ( typeof mock . calls [ 0 ] . generation ) . toBe ( 'bigint' )
// allowedIds = the at-gen `team: x` universe = {a, b}; NOT `later` (born after the pin).
const allowed = mock . calls [ 0 ] . allowedIds !
expect ( allowed . has ( a ) ) . toBe ( true )
expect ( allowed . has ( b ) ) . toBe ( true )
expect ( allowed . has ( later ) ) . toBe ( false )
expect ( allowed . has ( c ) ) . toBe ( false ) // team y, filtered out
// Results = the at-gen entities, in the provider's ranking (b before a).
expect ( results . map ( ( r ) = > r . id ) ) . toEqual ( [ b , a ] )
await db . release ( )
} )
it ( 'respects the page window on the provider-served path' , async ( ) = > {
const db = brain . now ( )
await brain . add ( { type : NounType . Document , data : 'epsilon' , metadata : { team : 'z' } } ) // advance gen
const mock = makeVersionedVectorMock ( [ b , a ] )
; ( brain as any ) . index = mock . provider
const page = await db . find ( { query : 'machine learning' , where : { team : 'x' } , limit : 1 } )
expect ( page . map ( ( r ) = > r . id ) ) . toEqual ( [ b ] ) // top-1 by the provider ranking
await db . release ( )
} )
feat(8.0): #35 part-3 — supply at-gen candidate vectors for the native exact-rerank
Completes brainy's #35 side. When the at-gen vector gate serves a filtered
semantic read, Brainy now ships the historically-correct candidate vectors so the
native provider reranks against them with zero per-vector FFI crossing — the
provider need not duplicate the per-generation retention Brainy already does.
- New `AtGenerationVectors { ids: BigInt64Array; vectors: Float32Array; dim }` on
the VectorIndexProvider.search options bag (row-major: vectors[i*dim..] == ids[i];
invariant vectors.length === ids.length*dim; ids = the candidate set; dim must
match the index dim). The built-in JS index ignores it.
- buildAtGenerationVectors resolves each universe id's vector AS OF the generation
(the record before-image, or live getNoun when untouched since the pin — not
readNounRaw, whose canonical path is empty under lazy-vector eviction), interns
the id via the shared mapper, and packs row-major. Absent/vectorless/wrong-dim
ids are dropped (not vector-rankable). Bounded by the filtered universe.
Shape + the four clarifications (row-major, ids-are-the-candidate-set, dim-asserted,
filtered-path-only) confirmed with cor in the handoff #35 thread. Inert until cor's
native at-gen rerank advertises isGenerationVisible (honesty guard).
Tested: the mock versioned provider now asserts it receives atGenerationVectors with
the row-major invariant, correct dim, and ids resolving back to the at-gen universe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 16:50:41 -07:00
it ( 'supplies the at-gen candidate vectors (part-3) — row-major, dim-correct, ids = the universe' , async ( ) = > {
const db = brain . now ( )
await brain . add ( { type : NounType . Document , data : 'zeta machine learning' , metadata : { team : 'z' } } ) // advance gen
const mock = makeVersionedVectorMock ( [ b , a ] )
; ( brain as any ) . index = mock . provider
await db . find ( { query : 'machine learning' , where : { team : 'x' } } )
const agv = mock . calls [ 0 ] . atGenerationVectors
expect ( agv ) . toBeDefined ( )
// ids = the at-gen `team: x` universe {a, b}, interned via the shared mapper.
expect ( agv ! . ids . length ) . toBe ( 2 )
expect ( agv ! . dim ) . toBeGreaterThan ( 0 )
// The row-major invariant cor asserts on ingest.
expect ( agv ! . vectors . length ) . toBe ( agv ! . ids . length * agv ! . dim )
// Each interned id resolves back to a universe entity.
const mapper = ( brain as any ) . metadataIndex . getIdMapper ( )
const uuids = Array . from ( agv ! . ids ) . map ( ( i ) = > mapper . getUuid ( Number ( i ) ) )
expect ( new Set ( uuids ) ) . toEqual ( new Set ( [ a , b ] ) )
await db . release ( )
} )
feat(8.0): asOf at-gen vector defer — provider-served historical semantic search (#35)
A filtered semantic read at a historical generation (db.asOf(g).find({ query, where }))
no longer unconditionally rebuilds an ephemeral JS-HNSW over every at-g vector
(O(n@G), the OOM ceiling the 2026-06-24 scaling audit flagged). When the vector
index is a VersionedIndexProvider that advertises isGenerationVisible(g), Brainy:
1. resolves the at-g metadata∩graph universe from the record-overlay path (no
materialization — it's the metadata-only historical find),
2. routes the vector leg to the provider with { allowedIds, generation }, and
3. composes the at-g entities ranked by the provider's at-g vector distance.
Without a versioned provider (the JS index, or a native one that refuses the
generation) it falls through to the existing materialization — unchanged.
- Seam (A): VectorIndexProvider.search gains an optional `generation?: bigint`
("omitted = now"), the vector mirror of the graph provider's trailing-gen + the
#46 allowedIds field. JsHnswVectorIndex accepts and ignores it (no per-gen
segments → refuse/fall-back posture; Brainy never routes a historical read there).
- Gate: Db.find tries the native at-gen vector path before materialize(); host
exposes canServeVectorAtGeneration + vectorSearchAtGeneration.
- generation is Brainy's u64 commit counter — the same value handed to the graph
index on writes (graphWriteGeneration), so it maps 1:1 to the native side.
Decided lockstep with the cor team (handoff #35 thread: (A) + vector-only). The
gen-g candidate-vector supply for cor's exact-rerank (part-3) is a separate,
non-blocking seam still being confirmed; the honesty guard keeps this path inactive
(falls through to materialize) until cor's native at-gen rerank is live.
Tested: provider routing + at-gen universe correctness (excludes future-born,
applies the filter) + page window via a mock versioned provider; seam-ignore on the
JS index; 38 db-mvcc/db-temporal historical-read tests green (materialize fallback).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:52:09 -07:00
} )