2026-07-07 15:49:49 -07:00
/ * *
* @module tests / unit / storage / sharding - new - installation - log
* @description Regression for BR - 8 - BOOT - INDEX symptom 1 . Brainy 8.0 stores
* entities in the canonical ` entities/nouns/<shard>/<id>/vectors.json ` layout ,
* but the legacy sharding probe ( ` detectExistingShardingDepth ` ) inspected
* ` entities/nouns/hnsw ` — a 7 . x directory the 8.0 write path never populates —
* so it returned null and logged "📁 New installation" for EVERY store on EVERY
* boot , including established brains holding thousands of entities . The
* new - vs - existing decision now consults the canonical layout the DB actually
* uses ( ` hasCanonicalEntities ` ) , so an established brain reports its true entity
* count and only a genuinely empty store says "New installation" .
* /
import { describe , it , expect , vi , afterEach } from 'vitest'
import { mkdtempSync , rmSync } from 'fs'
import { tmpdir } from 'os'
import { join } from 'path'
import { FileSystemStorage } from '../../../src/storage/adapters/fileSystemStorage.js'
import type { NounMetadata } from '../../../src/coreTypes.js'
const dirs : string [ ] = [ ]
function mkTmp ( ) : string {
const d = mkdtempSync ( join ( tmpdir ( ) , 'brainy-newinstall-' ) )
dirs . push ( d )
return d
}
afterEach ( ( ) = > {
for ( const d of dirs . splice ( 0 ) ) rmSync ( d , { recursive : true , force : true } )
vi . restoreAllMocks ( )
} )
/** Release a raw FileSystemStorage so a subsequent open of the dir is unblocked. */
async function teardown ( s : any ) : Promise < void > {
try { await s . flush ? . ( ) } catch { /* best effort */ }
try { s . stopFlushRequestWatcher ? . ( ) } catch { /* best effort */ }
try { await s . releaseWriterLock ? . ( ) } catch { /* best effort */ }
}
/** Capture everything written to console.log during `fn()`. */
async function captureLog ( fn : ( ) = > Promise < void > ) : Promise < string > {
const lines : string [ ] = [ ]
const spy = vi
. spyOn ( console , 'log' )
. mockImplementation ( ( . . . args : any [ ] ) = > {
lines . push ( args . map ( String ) . join ( ' ' ) )
} )
try {
await fn ( )
} finally {
spy . mockRestore ( )
}
return lines . join ( '\n' )
}
const VEC = [ 0.1 , 0.2 , 0.3 , 0.4 , 0.5 , 0.6 , 0.7 , 0.8 ]
async function seedOne ( s : any , id : string ) : Promise < void > {
await s . saveNounMetadata ( id , {
noun : 'thing' ,
createdAt : Date.now ( ) ,
updatedAt : Date.now ( )
} as NounMetadata )
await s . saveNoun ( { id , vector : VEC , connections : new Map ( ) , level : 0 } )
}
describe ( 'FileSystemStorage boot log: an established brain is not "New installation" (BR-8-BOOT-INDEX)' , ( ) = > {
it ( 'a genuinely fresh store still logs "New installation"' , async ( ) = > {
const dir = mkTmp ( )
const storage = new FileSystemStorage ( dir )
const out = await captureLog ( ( ) = > storage . init ( ) )
expect ( out ) . toContain ( 'New installation' )
await teardown ( storage )
} )
it ( 'an established store (canonical entities present) does NOT log "New installation" on reopen' , async ( ) = > {
const dir = mkTmp ( )
// 1. Author an entity → canonical entities/nouns/<shard>/<id>/vectors.json.
const first = new FileSystemStorage ( dir )
await first . init ( )
await seedOne ( first , 'a' . repeat ( 32 ) )
await teardown ( first )
// 2. Reopen: the boot log must reflect the established store, not "New installation".
const second = new FileSystemStorage ( dir )
const out = await captureLog ( ( ) = > second . init ( ) )
expect ( out ) . not . toContain ( 'New installation' )
expect ( out ) . toContain ( 'Using depth 1 sharding' )
await teardown ( second )
} )
fix: count recovery scans the canonical layout; remove the dead 7.x hnsw sharding machinery
Sweeping the vestigial hnsw sharding machinery surfaced two real defects on
the counts-recovery path (the code that rebuilds totalNounCount/totalVerbCount
when counts.json is lost or corrupted — container restarts, partial copies):
- initializeCountsFromDisk counted files in entities/*/hnsw/ — directories the
8.0 write path never populates — so an established store recovered to ZERO
counts on real data: wrong getNounCount()/stats, a "New installation"-style
boot log, and a mis-sized rebuild-strategy decision at open. The scan now
walks the canonical entities/<kind>/<shard>/<id>/ tree (one entity per id
directory), with the same sampled type-distribution estimate as before.
- The sampler called getNounMetadata — whose ensureInitialized() re-enters
init() — from INSIDE init(), a latent deadlock reachable the moment the scan
found anything to sample. The sampled metadata files are now read directly
with fs (gz-transparent), no guarded accessors inside init.
The dead machinery itself (verified zero callers by reachability analysis
before deletion): the nine 7.x hnsw-layout entity/edge CRUD methods, the
sharding-depth prober + its depth-migration engine (unreachable — the probe
always returned null on 8.0 stores), an orphaned streaming verb paginator,
their path/scan helpers, and the now-unused type aliases and fields. The init
block keeps the truthful new-vs-established boot log introduced in 8.0.13,
now decided directly from the canonical layout. Net -1,138 lines; no public
API touched.
Adds a regression test: delete counts.json from a populated store, reopen,
counts recover exactly from the canonical tree.
2026-07-08 15:49:19 -07:00
it ( 'counts RECOVER from the canonical layout when counts.json is lost (container-restart case)' , async ( ) = > {
const dir = mkTmp ( )
// Establish a store with 3 entities (canonical layout + counts.json).
const first : any = new FileSystemStorage ( dir )
await first . init ( )
for ( const c of [ 'a' , 'b' , 'c' ] ) await seedOne ( first , c . repeat ( 32 ) )
await teardown ( first )
// Simulate the lost/corrupted counts.json a container restart can leave.
for ( const f of [ 'counts.json' , 'counts.json.gz' ] ) {
rmSync ( join ( dir , '_system' , f ) , { force : true } )
}
// Reopen: the recovery scan must count the CANONICAL tree. The removed
// implementation scanned the vestigial `entities/*/hnsw` dirs and
// re-initialized every counter to ZERO on real data.
const second : any = new FileSystemStorage ( dir )
await second . init ( )
expect ( await second . getNounCount ( ) ) . toBe ( 3 )
await teardown ( second )
} )
2026-07-07 15:49:49 -07:00
it ( 'hasCanonicalEntities() sees the canonical shard tree — independent of counts.json' , async ( ) = > {
const dir = mkTmp ( )
const s : any = new FileSystemStorage ( dir )
await s . init ( )
// Fresh: only the vestigial `hnsw` dir exists → no canonical entities.
expect ( await s . hasCanonicalEntities ( ) ) . toBe ( false )
// After a canonical write the 2-hex shard dir exists → established, even if
// counts.json were later lost on a container restart (the fallback path).
await seedOne ( s , 'c' . repeat ( 32 ) )
expect ( await s . hasCanonicalEntities ( ) ) . toBe ( true )
await teardown ( s )
} )
} )