101 lines
4.1 KiB
TypeScript
101 lines
4.1 KiB
TypeScript
|
|
/**
|
||
|
|
* @module tests/integration/reserved-root-mint
|
||
|
|
* @description THE RESERVED-ROOT MINT EXEMPTION (the release's final fix):
|
||
|
|
* existing brains mint the VFS root (the all-zeros UUID) as int 0 by
|
||
|
|
* construction at genesis — the one legitimate zero in the id space. The
|
||
|
|
* adoption path must accept it (every real depot brain refused adoption
|
||
|
|
* over this); a zero mint for ANY OTHER id remains a corrupt-mint refusal.
|
||
|
|
*/
|
||
|
|
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 ROOT = '00000000-0000-0000-0000-000000000000'
|
||
|
|
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 MapperBox = {
|
||
|
|
metadataIndex: {
|
||
|
|
getIdMapper(): {
|
||
|
|
uuidToInt: Map<string, number>
|
||
|
|
intToUuid: Map<number, string>
|
||
|
|
dirty?: boolean
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('reserved-root mint exemption', () => {
|
||
|
|
it('adoption succeeds on a brain whose VFS root carries int 0 (the depot-brain shape)', async () => {
|
||
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-root0-'))
|
||
|
|
dirs.push(dir)
|
||
|
|
// Build the brain in 'defer' so we control the adoption moment.
|
||
|
|
const brain = new Brainy({
|
||
|
|
storage: { type: 'filesystem', path: dir },
|
||
|
|
requireSubtype: false,
|
||
|
|
logAuthority: 'defer'
|
||
|
|
})
|
||
|
|
await brain.init()
|
||
|
|
brains.push(brain)
|
||
|
|
await brain.add({ data: 'depot row', type: NounType.Document, metadata: { k: 1 } })
|
||
|
|
|
||
|
|
// The genesis-era shape: the root's mint is 0 (white-box — real depot
|
||
|
|
// brains carry this in their persisted mapper).
|
||
|
|
const mapper = (brain as unknown as MapperBox).metadataIndex.getIdMapper()
|
||
|
|
const currentInt = mapper.uuidToInt.get(ROOT)
|
||
|
|
if (currentInt !== undefined) mapper.intToUuid.delete(currentInt)
|
||
|
|
mapper.uuidToInt.set(ROOT, 0)
|
||
|
|
mapper.intToUuid.set(0, ROOT)
|
||
|
|
|
||
|
|
// THE PIN: adoption goes green — the backfill re-commits the root with
|
||
|
|
// its legitimate int 0 instead of refusing the whole brain.
|
||
|
|
const report = await brain.adoptLogAuthority()
|
||
|
|
expect(report.verdict).toBe('green')
|
||
|
|
expect(brain.logAuthority().authority).toBe('log')
|
||
|
|
// And the brain keeps serving + writing after the flip.
|
||
|
|
const fresh = await brain.add({ data: 'post-adopt', type: NounType.Document, metadata: { k: 2 } })
|
||
|
|
expect((await brain.get(fresh))!.data).toContain('post-adopt')
|
||
|
|
}, 120000)
|
||
|
|
|
||
|
|
it('a zero mint for a NON-root id still refuses at the mint seam, loudly and typed', async () => {
|
||
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-nonroot0-'))
|
||
|
|
dirs.push(dir)
|
||
|
|
const brain = new Brainy({
|
||
|
|
storage: { type: 'filesystem', path: dir },
|
||
|
|
requireSubtype: false,
|
||
|
|
logAuthority: 'defer'
|
||
|
|
})
|
||
|
|
await brain.init()
|
||
|
|
brains.push(brain)
|
||
|
|
const victim = await brain.add({ data: 'poisoned mint target', type: NounType.Document, metadata: {} })
|
||
|
|
|
||
|
|
// Corrupt shape: some OTHER id maps to 0. (A full update() SELF-HEALS
|
||
|
|
// this — the index cycle re-mints before the fact is written, which is
|
||
|
|
// the correct outcome — so the pin holds the guard at its real seam:
|
||
|
|
// the fact log's minter, which is what stands between a surviving zero
|
||
|
|
// and the wire.)
|
||
|
|
const mapper = (brain as unknown as MapperBox).metadataIndex.getIdMapper()
|
||
|
|
const currentInt = mapper.uuidToInt.get(victim)
|
||
|
|
if (currentInt !== undefined) mapper.intToUuid.delete(currentInt)
|
||
|
|
mapper.uuidToInt.set(victim, 0)
|
||
|
|
mapper.intToUuid.set(0, victim)
|
||
|
|
|
||
|
|
const factLog = (brain as unknown as {
|
||
|
|
generationStore: { getFactLog(): { intMinter(kind: string, id: string): bigint } }
|
||
|
|
}).generationStore.getFactLog()
|
||
|
|
expect(() => factLog.intMinter('noun', victim)).toThrow(
|
||
|
|
/reserved for the VFS root|minted ints are positive/
|
||
|
|
)
|
||
|
|
// And the reserved root itself passes the same seam with 0.
|
||
|
|
mapper.uuidToInt.set(ROOT, 0)
|
||
|
|
mapper.intToUuid.set(0, ROOT)
|
||
|
|
expect(factLog.intMinter('noun', ROOT)).toBe(0n)
|
||
|
|
}, 120000)
|
||
|
|
})
|