From 4176439ba3370206354c30139557e45fa9258653 Mon Sep 17 00:00:00 2001 From: David Snelling Date: Mon, 24 Aug 2026 09:58:45 -0700 Subject: [PATCH] test(fold-checkpoint): the ARM-AT-FLIP pin arms its crash instead of racing the pending-flush timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pin wrote a post-flip row, abandoned the brain as crashed, and then deleted the row's canonical bytes to prove the first post-flip boot folds BOUNDED above the flip's stamp. Between the write's ack and the abandon sat the store's 50ms pending-flush timer: on a loaded box (the plant lane) the flush won, barrier-synced the row and advanced the checkpoint over it — and the fold, correctly bounded, did not restore bytes the test had destroyed after they were stamped durable. Green locally, red on the plant: the engine was right, the pin was timing-dependent. The crash is now armed at exactly singleop-after-fact-append: the fact is appended and at-ack synced, no flush is ever scheduled, the stamp provably still reads the flip's value when the pre-flip bytes are dropped, and the post-flip row's bytes — which lived only in the pending tier's RAM — are lost for real, not synthetically. The reopen must re-materialize it from its fact and must not restore the pre-flip row. --- .../integration/fold-checkpoint-bound.test.ts | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) 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)