fix(adoption): the reserved-root mint exemption — int 0 is legitimate for exactly one id
All checks were successful
CI / Node 22 (push) Successful in 12m23s
CI / Node 24 (push) Successful in 12m9s
CI / Bun (latest) (push) Successful in 12m20s

The release-holding finding from the joint gate's six real depot brains:
the adoption path's positive-int mint check false-flagged the reserved
VFS-root sentinel (the all-zeros UUID, minted int 0 BY CONSTRUCTION at
genesis on existing brains) as a corrupt mint — so every existing brain
refused log-authority adoption and stayed on the old lossy-under-power-cut
durability, defeating the release's headline crash-safety exactly where
it matters most.

The exemption, at both mint seams (the host's minter thunk and the fact
log's encoder guard): int 0 is legal iff the id is the reserved root;
zero for ANY other id remains a corrupt-mint refusal naming the reserved
exception. The codec's u64 layer already tolerated 0 — only the guards
over-refused.

Pins: adoption goes green on a brain whose VFS root carries int 0 (the
depot-brain shape, previously refused) · a non-root zero still refuses
typed at the mint seam — held at the seam itself because a full write
SELF-HEALS a poisoned zero (the index cycle re-mints before the fact is
written, which is the correct outcome and was verified in the pinning).

Gates: unit 2065/2065 · integration 830 · conformance 31/31.
This commit is contained in:
David Snelling 2026-08-12 08:55:12 -07:00
parent 0e3facf4a8
commit 2abe8b3806
3 changed files with 118 additions and 4 deletions

View file

@ -1306,10 +1306,18 @@ export class Brainy<T = any> implements BrainyInterface<T> {
}
const minted = mapper.getOrAssign(id, undefined)
const asBigint = typeof minted === 'bigint' ? minted : BigInt(minted)
if (asBigint <= 0n) {
// THE RESERVED-ROOT EXEMPTION: the VFS root (the all-zeros UUID) is
// minted int 0 BY CONSTRUCTION at genesis on existing brains — the
// one legitimate zero in the id space. Zero for ANY other id is a
// corrupt mint and refuses. (Without this, every existing brain's
// adoption oracle false-flagged its own root and refused the flip.)
const isReservedRoot =
asBigint === 0n && id === '00000000-0000-0000-0000-000000000000'
if (asBigint < 0n || (asBigint === 0n && !isReservedRoot)) {
throw new Error(
`fact log v2: the id mapper minted ${asBigint} for ${kind} ${id}` +
`minted ints are positive; refusing to write`
`minted ints are positive (int 0 is reserved for the VFS root alone); ` +
`refusing to write`
)
}
return asBigint

View file

@ -1325,10 +1325,16 @@ export class FactLog {
)
}
const minted = this.intMinter(kind, id)
if (typeof minted !== 'bigint' || minted <= 0n) {
// Reserved-root exemption: int 0 is legitimate for exactly one id —
// the all-zeros VFS root, minted 0 by construction at genesis on
// existing brains. Zero anywhere else is a corrupt mint.
const isReservedRoot =
minted === 0n && id === '00000000-0000-0000-0000-000000000000'
if (typeof minted !== 'bigint' || minted < 0n || (minted === 0n && !isReservedRoot)) {
throw new Error(
`fact log v2: the int minter returned ${String(minted)} for ${kind} ${id}` +
`minted ints are positive bigints; refusing to write`
`minted ints are positive bigints (int 0 reserved for the VFS root alone); ` +
`refusing to write`
)
}
return minted

View file

@ -0,0 +1,100 @@
/**
* @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)
})