open-brainy/tests/integration/adopt-drift-cure.test.ts
David Snelling 25f0dd964e
Some checks failed
CI / Node 22 (push) Successful in 12m17s
CI / Node 24 (push) Successful in 12m8s
CI / Bun (latest) (push) Failing after 5m41s
fix(adoption): the baseline backfill cures hydration-law drift — existing brains reach the crash-safe default with zero operator steps
The last rung of the default-flip ruling: with the sentinel exemption in,
real production-shaped brains still refused adoption over state-differs
mismatches the backfill could not cure — rows written before the
hydration law carry denormalized wrapper fields that disagree with their
own metadata leg, and the previous as-is identity re-commit PRESERVED
that drift, so the oracle re-flagged it every pass and the flip never
happened. In practice the crash-safe default reached zero existing
brains: the exact outcome the hold ruling forbade.

The cure: the backfill now rewrites canonical in the LAW SHAPE — exactly
the wrapper the log's reconstruction produces (denormalized enumeration
fields derived from the metadata leg, which is their authority under the
field-addressing law; the embedding floats ride through byte-identical;
adjacency residue keeps its own rebuild path). The oracle then verifies
the rewrite before the flip — the same safety, no operator chore.
Log-ahead divergence classes (a log the witness denies) still refuse
loudly, exactly as before.

Classification note for the record: the flagged uuid-v7 rows postdate the
fact log's introduction, so they classify as state-differs (in-log,
drift-shaped) rather than pre-log — both classes ride the same backfill.

Pins: a manufactured depot-shape drifted wrapper adopts green with floats
preserved and metadata intact; log-ahead still refuses typed.
Gates: unit 2065/2065 · integration 832 · conformance 31/31.
2026-08-12 11:48:17 -07:00

107 lines
4.4 KiB
TypeScript

/**
* @module tests/integration/adopt-drift-cure
* @description THE DRIFT-CURING BACKFILL — the actual completion of the
* default-flip ruling: existing brains whose canonical wrappers carry
* pre-hydration-law drift (denormalized fields disagreeing with their own
* metadata leg — the real depot-brain shape, uuid-v7 rows from the 9.0 era)
* must ADOPT AUTOMATICALLY: the backfill rewrites canonical in the law
* shape (metadata leg = the authority; floats preserved), the oracle then
* verifies the rewrite before flipping. Same safety, zero operator chores.
* Log-ahead divergences still refuse as before.
*/
import { describe, it, expect, afterEach } from 'vitest'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { Brainy } from '../../src/index.js'
import { NounType } 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 })
})
type RawBox = {
storage: {
readNounRaw(id: string): Promise<{ metadata: unknown; vector: unknown }>
writeNounRaw(id: string, r: { metadata: unknown; vector: unknown }): Promise<void>
}
}
describe('adoption cures hydration-law drift automatically', () => {
it('a drifted wrapper (stale denormalized fields) adopts green with floats preserved', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-drift-cure-'))
dirs.push(dir)
const brain = new Brainy({
storage: { type: 'filesystem', path: dir },
requireSubtype: false,
logAuthority: 'defer'
})
await brain.init()
brains.push(brain)
const id = await brain.add({
data: 'early-era row with drift',
type: NounType.Document,
metadata: { k: 1 }
})
await brain.flush()
const before = await brain.get(id, { includeVectors: true })
const floats = [...(before!.vector as number[])]
expect(floats.length).toBeGreaterThan(0)
// Manufacture the depot shape: the stored wrapper's denormalized fields
// disagree with the metadata leg (pre-hydration-law drift) — an as-is
// identity re-commit preserves this forever; the law-shape rewrite cures it.
const storage = (brain as unknown as RawBox).storage
const raw = await storage.readNounRaw(id)
const wrapper = raw.vector as Record<string, unknown>
await storage.writeNounRaw(id, {
metadata: raw.metadata,
vector: {
...wrapper,
noun: 'thing', // stale denormalized type (metadata leg says document)
legacyField: 'pre-law residue',
createdAt: '1999-01-01T00:00:00.000Z'
}
})
// Confirm the drift is oracle-visible before the cure.
expect((await brain.verifyLogAuthority()).verdict, 'drift detected').toBe('red')
// THE PIN: adoption cures it without any operator step.
const report = await brain.adoptLogAuthority()
expect(report.verdict).toBe('green')
expect(brain.logAuthority().authority).toBe('log')
// Nothing degraded: floats byte-identical, metadata intact, row serves.
const after = await brain.get(id, { includeVectors: true })
expect(after!.vector as number[], 'floats preserved through the cure').toEqual(floats)
expect((after!.metadata as { k: number }).k).toBe(1)
expect((await brain.find({ where: { k: 1 }, limit: 5 })).map((r) => r.id)).toContain(id)
}, 120000)
it('log-ahead divergences still refuse — the backfill never papers over a log the witness denies', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-logahead-'))
dirs.push(dir)
const brain = new Brainy({
storage: { type: 'filesystem', path: dir },
requireSubtype: false,
logAuthority: 'defer'
})
await brain.init()
brains.push(brain)
const id = await brain.add({ data: 'row', type: NounType.Document, metadata: { k: 1 } })
await brain.flush()
// Log-ahead shape: canonical loses the record while the log still
// claims it live (log-live-canonical-absent — NOT curable by baseline).
const storage = (brain as unknown as RawBox).storage
await storage.writeNounRaw(id, { metadata: null, vector: null })
await expect(brain.adoptLogAuthority()).rejects.toThrow(
/log-ahead|witness denies|log claims/i
)
expect(brain.logAuthority().authority).toBe('tree')
}, 120000)
})