/** * @module tests/unit/db/torn-open-guards * @description Power-cut throw-site cures (brainy-alone fault-injection * findings, both release-gating): * 1. A torn generation manifest/counter (NaN/garbage where a generation * belongs) DISCARDS with narration and re-derives — never a RangeError * killing the open. * 2. A manifest-listed-but-unloadable column segment QUARANTINES at * discovery with narration; the field serves its remaining segments * DEGRADED — never a raw throw killing every query on the field. */ import { describe, it, expect, afterEach } from 'vitest' import { mkdtempSync, rmSync, readdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { gzipSync } from 'node:zlib' 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 }) }) async function open(dir: string): Promise { const b = new Brainy({ storage: { type: 'filesystem', path: dir }, requireSubtype: false }) await b.init() brains.push(b) return b } describe('torn-open guards', () => { it('a torn generation manifest (NaN) opens with narrated discard — never a RangeError', async () => { const dir = mkdtempSync(join(tmpdir(), 'brainy-torn-gen-')) dirs.push(dir) let brain = await open(dir) const id = await brain.add({ data: 'survivor row', type: NounType.Document, metadata: { k: 1 } }) await brain.flush() await brain.close() brains.pop() // The power-cut shape: the manifest's generation field is garbage. const sys = join(dir, '_system') const manifestPath = ['manifest.json', 'manifest.json.gz'] .map((f) => join(sys, f)) .find((p) => existsSync(p))! const torn = { version: 1, generation: 'NaN-garbage', committedAt: 'x', horizon: null } if (manifestPath.endsWith('.gz')) writeFileSync(manifestPath, gzipSync(JSON.stringify(torn))) else writeFileSync(manifestPath, JSON.stringify(torn)) // Open MUST succeed (narrated discard + recovery re-derivation), and the // durable row must still serve (log-authority replay recovers it). brain = await open(dir) expect((await brain.get(id))!.data).toContain('survivor row') // Writes continue with a sane monotonic generation. await brain.add({ data: 'post-recovery', type: NounType.Document, metadata: { k: 2 } }) expect(Number.isSafeInteger(brain.generation())).toBe(true) }, 120000) it('a torn column segment quarantines at discovery; the field serves remaining segments degraded — never a raw throw', async () => { const dir = mkdtempSync(join(tmpdir(), 'brainy-torn-seg-')) dirs.push(dir) let brain = await open(dir) for (let i = 0; i < 6; i++) { await brain.add({ data: `row ${i}`, type: NounType.Document, metadata: { bucket: i % 2 } }) } await brain.flush() await brain.close() brains.pop() // Tear ONE column segment's bytes on disk (manifest keeps listing it) — // the QUERIED field's own segment, so the quarantine path provably // engages. Column segments live under the raw-blob root: // `/_blobs/_column_index//L-.bin`. const segDir = join(dir, '_blobs', '_column_index', 'bucket') let tornOne = false if (existsSync(segDir)) { for (const f of readdirSync(segDir, { withFileTypes: true })) { if (!f.isDirectory() && /^L\d+-.*\.bin$/.test(f.name)) { writeFileSync(join(segDir, f.name), Buffer.from([0x00, 0x01, 0x02])) // garbage tornOne = true break } } } expect(tornOne, 'found a segment file to tear (layout probe)').toBe(true) // Queries on the field MUST NOT throw — degraded-announced service. brain = await open(dir) const rows = await brain.find({ where: { bucket: 0 }, limit: 10 }) expect(Array.isArray(rows), 'query survives the torn segment').toBe(true) // Full completeness is NOT asserted (the torn segment's rows may be // absent — that is the documented degraded contract until heal). }, 120000) })