open-brainy/tests/integration/brain-relocation.test.ts
David Snelling b53e6e8987
Some checks failed
CI / Node 22 (push) Has been cancelled
CI / Node 24 (push) Has been cancelled
CI / Bun (latest) (push) Has been cancelled
feat(engine): the wiring wave — stamps ride every flush, provider generations, waitForIndexed, adopt-backfill, match-all serves
- Watermark stamping fans out at flush: all three projections stamped
  with the committed generation before their flushes persist.
- waitForIndexed(path?, {generation, timeoutMs}) — the one honest read
  barrier for write-then-recall consumers; typed timeout error carries
  the pending count and names the gauge; getIndexStatus() gains
  per-projection gauges. awaitPendingEmbeds() unchanged underneath.
- adoptLogAuthority() self-backfills curable divergences (pre-log
  records, witness drift) by identity re-commit before flipping — a
  fresh brain flips clean; log-ahead divergences still refuse loudly.
- The verification oracle gains VERB legs (all four divergence classes;
  unwired = honest verbsChecked: 0, never a scope claim).
- find({where: {}}) match-all serves (was silent-empty, warm AND cold;
  same fix in count/streaming/subgraph seeding); removeMany({where:{}})
  refuses typed — a match-all bulk delete must be explicit.
- Aggregation native envelope stamped via noteSourceGeneration before
  serializeState; the native-blob restore gates through the same
  adoption verdict as caller-side state (the unconditional adopt dies).
- LC8 pinned: a wholesale directory move opens and serves identically
  across all three intelligences, with history traveling.

Gates: unit 2031/2031 (156 files) · integration 812 (91 files) ·
conformance 27/27.
2026-08-10 10:55:11 -07:00

108 lines
4.2 KiB
TypeScript

/**
* @module tests/integration/brain-relocation
* @description LC8 — RELOCATABLE BRAIN DIRECTORY. A brain's directory moved
* wholesale to a new path (rename/copy — backup-restore, disk migration,
* container re-mount) must open and serve IDENTICALLY: no absolute paths may
* hide in any persisted artifact. Pinned across every intelligence: point
* reads, metadata find, semantic find, graph traversal, aggregation — plus
* continued writes with monotonic generations and time-travel reads over
* pre-move history.
*/
import { describe, it, expect, afterEach } from 'vitest'
import { mkdtempSync, rmSync, renameSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { Brainy } from '../../src/index.js'
import { NounType, VerbType } from '../../src/types/graphTypes.js'
const dirs: string[] = []
const brains: Brainy[] = []
afterEach(async () => {
for (const b of brains.splice(0)) await b.close().catch(() => {})
for (const d of dirs.splice(0)) rmSync(d, { recursive: true, force: true })
})
const AGG = {
name: 'by_kind',
source: { type: NounType.Document },
groupBy: ['kind'] as string[],
metrics: { count: { op: 'count' as const } }
}
describe('LC8 — a moved brain directory opens and serves identically', () => {
it('rename the directory: all three intelligences serve, writes continue, history travels', async () => {
const home = mkdtempSync(join(tmpdir(), 'brainy-reloc-'))
dirs.push(home)
const oldPath = join(home, 'brain-old')
const newPath = join(home, 'brain-new')
// Season a brain: rows, a relation, an aggregate, then flush + close.
let brain = new Brainy({ storage: { type: 'filesystem', path: oldPath }, requireSubtype: false })
await brain.init()
brains.push(brain)
brain.defineAggregate(AGG)
const alpha = await brain.add({
data: 'alpha document about mountain geology',
type: NounType.Document,
metadata: { kind: 'report', n: 1 }
})
const beta = await brain.add({
data: 'beta document about coastal erosion',
type: NounType.Document,
metadata: { kind: 'report', n: 2 }
})
await brain.relate({ from: alpha, to: beta, verb: VerbType.RelatedTo })
await brain.queryAggregate(AGG.name) // settle backfill
const preMoveGen = brain.generation()
await brain.flush()
await brain.close()
brains.pop()
// The move: wholesale directory rename.
renameSync(oldPath, newPath)
// Reopen at the NEW path — everything serves.
brain = new Brainy({ storage: { type: 'filesystem', path: newPath }, requireSubtype: false })
await brain.init()
brains.push(brain)
brain.defineAggregate(AGG)
// Point read + metadata find.
expect((await brain.get(alpha))!.data).toContain('mountain geology')
const found = await brain.find({ where: { kind: 'report' }, limit: 10 })
expect(found.map((r) => r.id).sort()).toEqual([alpha, beta].sort())
// Semantic find.
const sem = await brain.find({ query: 'alpha document about mountain geology', limit: 3 })
expect(sem.map((r) => r.id)).toContain(alpha)
// Graph traversal.
const related = await brain.related(alpha)
expect(related.map((r) => r.to)).toContain(beta)
// Aggregation.
const agg = (await brain.queryAggregate(AGG.name)) as Array<{
groupKey: Record<string, unknown>
metrics: Record<string, unknown>
}>
const reportRow = agg.find((g) => g.groupKey['kind'] === 'report')
expect(Number(reportRow?.metrics.count)).toBe(2)
// Writes continue with monotonic generations.
const gamma = await brain.add({
data: 'gamma addendum after the move',
type: NounType.Document,
metadata: { kind: 'report', n: 3 }
})
expect(brain.generation()).toBeGreaterThan(preMoveGen)
expect((await brain.get(gamma))!.data).toContain('addendum')
// Time travel across the move boundary: the pre-move pin sees exactly
// the pre-move world (no gamma), served from relocated history.
const dbPast = await brain.asOf(preMoveGen)
expect(await dbPast.get(gamma)).toBeNull()
expect((await dbPast.get(alpha))!.data).toContain('mountain geology')
await dbPast.release()
}, 120000)
})