diff --git a/tests/integration/fold-checkpoint-bound.test.ts b/tests/integration/fold-checkpoint-bound.test.ts index 2f21248b..a02d75e0 100644 --- a/tests/integration/fold-checkpoint-bound.test.ts +++ b/tests/integration/fold-checkpoint-bound.test.ts @@ -23,6 +23,7 @@ import { Brainy } from '../../src/brainy.js' import { NounType } from '../../src/types/graphTypes.js' import { abandonAsCrashed, + armCrash, dropCanonicalNoun, makeTempDir, openBrain, @@ -177,15 +178,33 @@ describe('fold-checkpoint bound — crash recovery folds (checkpoint, head], nev expect(founded, 'checkpoint founded at flip').toBe(committedOf(brain)) // First post-flip boot, unclean (the production first-restart shape): - // a post-flip write above the checkpoint is restored FROM ITS AT-ACK FACT - // (deliberately NOT flushed — a flush would barrier-sync it and advance - // the stamp over it, making its loss synthetic); the pre-flip row (its - // baseline fact ≤ checkpoint, its bytes barrier-synced at the flip) is - // OUTSIDE the fold — vaporizing it synthetically proves the bound. - const postFlip = await brain.add({ data: 'post-flip write', type: NounType.Document, metadata: { era: 'log' } }) + // a post-flip write above the checkpoint is restored FROM ITS AT-ACK FACT; + // the pre-flip row (its baseline fact ≤ checkpoint, its bytes barrier- + // synced at the flip) is OUTSIDE the fold — vaporizing it synthetically + // proves the bound. + // + // THE CRASH IS ARMED, NOT RACED. The post-flip write "dies" at exactly + // `singleop-after-fact-append`: its fact is in the log and at-ack synced, + // and NO pending flush was ever scheduled — so the checkpoint provably + // still reads the flip's stamp when the bytes are dropped. The earlier + // shape (`add()` then abandon) raced the store's 50ms pending-flush + // timer: on a loaded box the flush won, barrier-synced the row, advanced + // the stamp over it — and the fold, CORRECTLY bounded, did not restore + // bytes the test had synthetically destroyed after they were stamped + // durable. The plant lane caught it; the engine was right, the pin was + // timing-dependent. + const postFlip = `post-flip-${Date.now().toString(36)}-0000-4000-8000-000000000000` + const arm = armCrash(brain, 'singleop-after-fact-append') + await expect( + brain.add({ id: postFlip, data: 'post-flip write', type: NounType.Document, metadata: { era: 'log' } }) + ).rejects.toThrow('simulated process crash at singleop-after-fact-append') + expect(arm.fired).toContain('singleop-after-fact-append') + expect(readCheckpoint(dir), 'the stamp did not move — nothing flushed after the flip').toBe(founded) await abandonAsCrashed(liveBrains.pop()!) + // The post-flip row's canonical bytes lived only in the pending tier's + // RAM (written at flush, never reached) — the crash takes them for real; + // nothing to drop. Only the pre-flip row is vaporized synthetically. dropCanonicalNoun(dir, preFlip) - dropCanonicalNoun(dir, postFlip) const reopened = await openBrain(dir, { logAuthority: 'adopt' }) liveBrains.push(reopened)