2026-07-15 12:44:52 -07:00
/ * *
* @module tests / integration / fact - log - contracts
* @description Pinned durability + stability contracts for the fact log .
*
* ( 1 ) FSYNC - BEFORE - ACK : an acknowledged write ' s fact survives an abrupt
* process end ( no flush , no close — reopen from disk ) .
feat(log): log authority is the fleet default — adopt-at-open, oracle-gated; plus the power-cut throw-site cures and the loud torn-record contract
THE DEFAULT FLIP (ruled on proven evidence — at-ack survived 301/301
acked-writes-through-power-cut in block-layer fault injection; deferred
tree authority demonstrably loses flush-covered acks): a brain with NO
stored authority artifact now ADOPTS LOG AUTHORITY AT OPEN. The oracle
gates the flip exactly as the guarded adoption path always did — curable
divergences baseline-backfilled, the flip lands ONLY on a green verdict —
and a brain that cannot verify STAYS tree-authoritative loudly, with the
refusal recorded on the switch artifact so subsequent opens are cheap.
config logAuthority: 'defer' is the explicit documented opt-out (no
automatic adoption; declared flush-window loss; adoptLogAuthority() flips
later). A stored artifact always wins. RELEASES.md carries the posture.
Two standing .fails debt pins FLIP TO HOLDING under the default: the
at-ack crash-survival gap and the ack-at-log durability target — both now
permanent asserted truths, not aspirations.
POWER-CUT THROW SITES (fault-injection findings, brainy-alone config):
- A manifest-listed-but-unloadable column segment QUARANTINES at
discovery (loud once, counted always, quarantinedSegments() exposed for
the heal) and the field serves its remaining segments DEGRADED — never
a raw throw killing every query on the field. Real storage faults still
propagate untouched.
- Torn generation artifacts (NaN/garbage in manifest or counter) DISCARD
with narration at the store's open and recovery re-derives — plus a
defensive finite-integer guard at the init consumer. Never a RangeError
killing an open.
THE LOUD TORN-RECORD CONTRACT: an existing-but-unparseable stored record
now surfaces as a typed, counted TornRecordError on every entity-read
surface (including fifteen previously-blind per-item batch catches);
ENOENT stays clean-absent; artifact readers with designed absent-recovery
keep null-tolerance behind the loud floor. Disk corruption can no longer
read as silent data invisibility.
Suite migration: the default's pins inverted deliberately, generation
baselines made relative, quarantine-contract pins rewritten to the ruled
behavior.
Gates: tsc 0 · unit 2065/2065 (159 files) · integration 826 (93 files) ·
conformance 31/31 · kill-matrix 15/15 · torn-open guards 2/2.
2026-08-11 08:37:38 -07:00
* - transact ( ) : HOLDS — the fact is fsync ' d before transact returns .
* - single - op : HOLDS ( was pinned ` it.fails ` until the ack - at - log
* destination landed ) : the 10.0 . 0 adopt - at - open fleet default flips a
* fresh brain to log authority at open , so single - op acks await the
* covering group fsync ( durable - at - ack ) and recovery REPLAYS intact
* facts above the manifest at the next open . The contract is now
* permanent on every path .
2026-07-15 12:44:52 -07:00
*
* ( 2 ) SCAN STABILITY UNDER ROTATION : a scan handle opened before segment
* rotation yields exactly its snapshot — byte - identical facts , no gaps ,
* no duplicates , and no bleed - in of facts appended after the snapshot .
* ( The reclaim - during - scan variant lands with fact - log compaction , which
* does not exist yet — segments only rotate today , never reclaim . )
* /
import { describe , it , expect , beforeEach , afterEach } from 'vitest'
import * as fs from 'node:fs'
import * as os from 'node:os'
import * as path from 'node:path'
import { Brainy , type CommitFact } from '../../src/index.js'
import { MemoryStorage } from '../../src/storage/adapters/memoryStorage.js'
import { FactLog , type FactLogStorage } from '../../src/db/factLog.js'
describe ( 'fsync-before-ack contract (fact durability at the ack boundary)' , ( ) = > {
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
}
beforeEach ( async ( ) = > {
process . env . BRAINY_DETERMINISTIC_EMBEDDINGS = 'true'
dir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'brainy-factack-' ) )
brain = await open ( )
} )
afterEach ( async ( ) = > {
await brain . close ? . ( ) . catch ( ( ) = > { } )
fs . rmSync ( dir , { recursive : true , force : true } )
} )
it ( 'transact(): the fact is durable the moment the ack returns (kill-after-ack safe)' , async ( ) = > {
const receipt = await brain . transact ( [
{ op : 'add' , type : 'document' , metadata : { durable : 1 } , data : 'ack-at-commit' }
] )
// Abrupt end: no flush(), no close() — a new instance reads only disk.
brain = await open ( )
const facts : CommitFact [ ] = [ ]
for await ( const b of brain . scanFacts ( ) ! . batches ( ) ) facts . push ( . . . b . facts )
expect ( facts . some ( ( f ) = > f . generation === receipt . generation ) ) . toBe ( true )
} )
feat(log): log authority is the fleet default — adopt-at-open, oracle-gated; plus the power-cut throw-site cures and the loud torn-record contract
THE DEFAULT FLIP (ruled on proven evidence — at-ack survived 301/301
acked-writes-through-power-cut in block-layer fault injection; deferred
tree authority demonstrably loses flush-covered acks): a brain with NO
stored authority artifact now ADOPTS LOG AUTHORITY AT OPEN. The oracle
gates the flip exactly as the guarded adoption path always did — curable
divergences baseline-backfilled, the flip lands ONLY on a green verdict —
and a brain that cannot verify STAYS tree-authoritative loudly, with the
refusal recorded on the switch artifact so subsequent opens are cheap.
config logAuthority: 'defer' is the explicit documented opt-out (no
automatic adoption; declared flush-window loss; adoptLogAuthority() flips
later). A stored artifact always wins. RELEASES.md carries the posture.
Two standing .fails debt pins FLIP TO HOLDING under the default: the
at-ack crash-survival gap and the ack-at-log durability target — both now
permanent asserted truths, not aspirations.
POWER-CUT THROW SITES (fault-injection findings, brainy-alone config):
- A manifest-listed-but-unloadable column segment QUARANTINES at
discovery (loud once, counted always, quarantinedSegments() exposed for
the heal) and the field serves its remaining segments DEGRADED — never
a raw throw killing every query on the field. Real storage faults still
propagate untouched.
- Torn generation artifacts (NaN/garbage in manifest or counter) DISCARD
with narration at the store's open and recovery re-derives — plus a
defensive finite-integer guard at the init consumer. Never a RangeError
killing an open.
THE LOUD TORN-RECORD CONTRACT: an existing-but-unparseable stored record
now surfaces as a typed, counted TornRecordError on every entity-read
surface (including fifteen previously-blind per-item batch catches);
ENOENT stays clean-absent; artifact readers with designed absent-recovery
keep null-tolerance behind the loud floor. Disk corruption can no longer
read as silent data invisibility.
Suite migration: the default's pins inverted deliberately, generation
baselines made relative, quarantine-contract pins rewritten to the ruled
behavior.
Gates: tsc 0 · unit 2065/2065 (159 files) · integration 826 (93 files) ·
conformance 31/31 · kill-matrix 15/15 · torn-open guards 2/2.
2026-08-11 08:37:38 -07:00
// THE ACK-AT-LOG CONTRACT, HELD (was `.fails` until it landed): under the
// adopt-at-open fleet default this brain runs durable-at-ack from open —
// the ack waits for the covering log fsync, and the log-authority recovery
// path replays the intact fact at the next open instead of truncating it.
it ( 'single-op: the fact is durable the moment the ack returns (the ack-at-log target)' , async ( ) = > {
2026-07-15 12:44:52 -07:00
await brain . add ( { data : 'acked single-op' , type : 'document' , metadata : { n : 1 } } )
const ackedHead = brain . scanFacts ( ) ! . headGeneration
// Abrupt end immediately after the ack — before any flush window.
brain = await open ( )
const facts : CommitFact [ ] = [ ]
for await ( const b of brain . scanFacts ( ) ! . batches ( ) ) facts . push ( . . . b . facts )
expect ( facts . some ( ( f ) = > f . generation === ackedHead ) ) . toBe ( true )
} )
} )
describe ( 'scan stability under rotation (the snapshot contract)' , ( ) = > {
const UUID = ( n : number ) : string = > ` 00000000-0000-4000-8000- ${ String ( n ) . padStart ( 12 , '0' ) } `
const fact = ( generation : number ) : CommitFact = > ( {
generation ,
timestamp : 1_700_000_000_000 + generation ,
ops : [
{
kind : 'noun' ,
id : UUID ( generation ) ,
// Padding makes each frame ~1KB so a small rotateBytes forces rotations.
record : { metadata : { noun : 'document' , pad : 'x' . repeat ( 900 ) , g : generation } , vector : null }
}
]
} )
it ( 'a scan opened before rotations yields its exact snapshot — no gaps, dups, or bleed-in' , async ( ) = > {
const mem : any = new MemoryStorage ( )
await mem . init ( )
const log = new FactLog ( mem as FactLogStorage , { rotateBytes : 4096 } ) // ~4 facts per segment
await log . open ( 0 )
for ( let g = 1 ; g <= 10 ; g ++ ) await log . append ( fact ( g ) )
await log . sync ( )
// Open the snapshot, THEN keep appending — forcing further rotations.
const scan = log . scanFacts ( )
expect ( scan . headGeneration ) . toBe ( 10 )
for ( let g = 11 ; g <= 25 ; g ++ ) await log . append ( fact ( g ) )
await log . sync ( )
expect ( log . headGeneration ( ) ) . toBe ( 25 )
const seen : number [ ] = [ ]
for await ( const batch of scan . batches ( ) ) {
for ( const f of batch . facts ) seen . push ( f . generation )
}
// Exactly the snapshot: 1..10 in order, nothing appended-after bleeds in.
expect ( seen ) . toEqual ( [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] )
expect ( scan . summary ( ) . factsYielded ) . toBe ( 10 )
// And a fresh scan sees everything, across all rotated segments.
const all : number [ ] = [ ]
for await ( const batch of log . scanFacts ( ) . batches ( ) ) {
for ( const f of batch . facts ) all . push ( f . generation )
}
expect ( all ) . toEqual ( Array . from ( { length : 25 } , ( _ , i ) = > i + 1 ) )
expect ( log . segmentPaths ( ) . length ) . toBeGreaterThanOrEqual ( 2 ) // rotations actually happened
} )
} )