// E2E proof for strict-bootstrap tracker semantics on mirrors.
//
// History: this test originally tried to validate a runtime "rebind"
// (close+reopen the autobase against a different root in the same
// corestore namespace). That approach crashes inside autobase's apply
// path because corestore's auto-derived local writer carries blocks
// from the old root and can't be reapplied under the new one. See
// stortron's 2026-05-05 outage for the production reproduction.
//
// The fix in 0.1.57 is the dodge: a mirror is constructed in
// `requireBootstrap` mode and refuses to lazy-open a tracker without
// a known bootstrap key. The sibling autobase that previously caused
// the divergence is never created in the first place. When the bundle
// or event log delivers the canonical key, the tracker opens cleanly
// against canonical from the very first call. No close+reopen, no
// orphan local-writer state, no apply crash.
//
// Phases:
// 1. Primary creates the canonical org tracker, writes one issue.
// 2. Strict-mode mirror (no bootstrap yet) calls getForOrg ⇒
// throws ETRACKER_NOT_READY. listOrgs is empty (no sibling).
// 3. Bundle/event-log delivers canonical key ⇒ bindOrgBootstrapKey.
// 4. Mirror's getForOrg now succeeds at canonical root.
// 5. Mirror reads primary's issue (read replication).
// 6. Mirror restart with same storage ⇒ boots cleanly, tracker still
// canonical, primary's issue still readable. This phase is the
// regression guard for the production crash.
import test from 'brittle'
import { mkdtempSync } from '#node:fs'
import { join } from '#node:path'
import { tmpdir } from '#node:os'
import b4a from 'b4a'
import createTestnet from '@hyperswarm/testnet'
import { startPearGit } from '../index.js'
import { IssueRegistry } from '../lib/issue-registry.js'
import Corestore from 'corestore'
let n = 0
function tmpStorage () {
return mkdtempSync(join(tmpdir(), 'pgv3-strict-' + (n++) + '-'))
}
function tmpSockPath () {
return join(mkdtempSync(join(tmpdir(), 'pgv3-strict-sock-' + (n++) + '-')), 'svc.sock')
}
async function waitFor (predicate, timeoutMs = 8000) {
const t0 = Date.now()
while (Date.now() - t0 < timeoutMs) {
try { if (await predicate()) return true } catch {}
await new Promise((r) => setTimeout(r, 50))
}
return false
}
test('strict mode: getForOrg without bootstrap throws ETRACKER_NOT_READY (no sibling autobase)', async (t) => {
// Pure unit test of the strict-mode contract: mirror IssueRegistry
// refuses to mint a tracker when no bootstrap is available.
const storage = tmpStorage()
const corestore = new Corestore(join(storage, 'store'))
await corestore.ready()
t.teardown(async () => { try { await corestore.close() } catch {} })
const registry = new IssueRegistry(corestore, {
indexPath: join(storage, 'issue-registry-index.json'),
requireBootstrap: true
})
let thrown = null
try { await registry.getForOrg('demo-org') } catch (err) { thrown = err }
t.ok(thrown, 'getForOrg without bootstrap throws')
t.is(thrown.code, 'ETRACKER_NOT_READY', 'error.code is ETRACKER_NOT_READY')
t.ok(/bootstrap key not yet known/.test(thrown.message), 'message names the missing input')
// Critical: no sibling autobase was created.
t.is(registry.listOrgs().length, 0, 'no tracker was opened (no sibling autobase)')
t.is(Object.keys(registry._index.orgs).length, 0, 'index file did not record a sibling root')
await registry.close()
})
test('strict mode: bind then getForOrg opens cleanly against canonical, survives restart', async (t) => {
t.timeout(90000)
const testnet = await createTestnet(3, t.teardown)
const topic = b4a.alloc(32, 'pgv3-strict-bootstrap')
// ── Phase 1: Primary, permissive mode ─────────────────────────
const nodeA = await startPearGit({
storage: tmpStorage(),
uds: tmpSockPath(),
http: { port: 0 },
swarm: { topic, swarm: { bootstrap: testnet.bootstrap } },
deploy: false,
sync: false
})
t.teardown(async () => { try { await nodeA.close() } catch {} })
const trackerA = await nodeA.issueRegistry.getForOrg('demo-org')
await trackerA.create({ title: 'first canonical', author: 'alice' })
const canonicalKey = trackerA.keyHex
t.ok(canonicalKey, 'primary owns a canonical tracker')
// ── Phase 2: Mirror in strict mode, no bootstrap delivered yet ─
// Mirror is mounted with `origin` set ⇒ requireBootstrap=true. Bundle
// is intentionally NOT carrying issueOrgs so the tracker key is
// unknown at startup. This is the production scenario where the
// OrgEventLog hasn't delivered the key yet.
const mirrorStorage = tmpStorage()
const nodeB1 = await startPearGit({
storage: mirrorStorage,
uds: tmpSockPath(),
http: { port: 0 },
swarm: { topic, swarm: { bootstrap: testnet.bootstrap } },
deploy: false,
sync: false,
origin: { serverKey: 'a'.repeat(64) } // any non-null origin ⇒ requireBootstrap=true
})
// No teardown for nodeB1 — closed mid-test for the restart phase.
let strictThrew = null
try { await nodeB1.issueRegistry.getForOrg('demo-org') } catch (err) { strictThrew = err }
t.ok(strictThrew, 'mirror getForOrg without bootstrap throws (no sibling created)')
t.is(strictThrew && strictThrew.code, 'ETRACKER_NOT_READY', 'error.code surfaces to caller')
t.is(nodeB1.issueRegistry.listOrgs().length, 0, 'no sibling tracker opened on mirror')
// ── Phase 3: Canonical key arrives (simulating event-log delivery) ─
const bound = nodeB1.issueRegistry.bindOrgBootstrapKey('demo-org', canonicalKey)
t.ok(bound, 'bindOrgBootstrapKey accepted the canonical key')
// ── Phase 4: First open succeeds at canonical root ────────────
const trackerB1 = await nodeB1.issueRegistry.getForOrg('demo-org')
t.is(trackerB1.keyHex, canonicalKey, 'mirror tracker opened at canonical root from the start')
// ── Phase 5: Read replication ─────────────────────────────────
const readReplicated = await waitFor(async () => {
const issues = await trackerB1.list()
return issues.some(i => i.title === 'first canonical')
}, 8000)
t.ok(readReplicated, "mirror reads primary's canonical issue")
// ── Phase 6 (CRITICAL): Restart with same storage ─────────────
// Boot picks up the bootstrap key from the persisted index (we just
// recorded canonicalKey in phase 4). Strict-mode + bundle-or-index
// delivery means tracker opens cleanly. Because no sibling was ever
// created in phase 2, the corestore namespace has no orphan blocks
// from a defunct root. Apply has nothing stale to choke on.
await nodeB1.close()
let nodeB2 = null
let bootError = null
try {
nodeB2 = await startPearGit({
storage: mirrorStorage, // SAME path
uds: tmpSockPath(),
http: { port: 0 },
swarm: { topic, swarm: { bootstrap: testnet.bootstrap } },
deploy: false,
sync: false,
origin: { serverKey: 'a'.repeat(64) }
})
} catch (err) {
bootError = err
}
t.absent(bootError, 'mirror restart boots cleanly (no autobase apply crash)')
if (nodeB2) {
t.teardown(async () => { try { await nodeB2.close() } catch {} })
const trackerB2 = await nodeB2.issueRegistry.getForOrg('demo-org')
t.is(trackerB2.keyHex, canonicalKey, 'restart preserves canonical root binding')
const stillReplicated = await waitFor(async () => {
const issues = await trackerB2.list()
return issues.some(i => i.title === 'first canonical')
}, 8000)
t.ok(stillReplicated, "post-restart mirror still reads primary's canonical issue")
}
})
test('permissive mode: primary still auto-derives a tracker root when no bootstrap given', async (t) => {
// Sanity check that strict mode is opt-in. A primary daemon (no
// origin / no mirror config) keeps the legacy behavior: getForOrg
// mints a fresh root if none is known. This is correct on a primary —
// the primary OWNS canonical roots.
const testnet = await createTestnet(3, t.teardown)
const topic = b4a.alloc(32, 'pgv3-permissive')
const node = await startPearGit({
storage: tmpStorage(),
uds: tmpSockPath(),
http: { port: 0 },
swarm: { topic, swarm: { bootstrap: testnet.bootstrap } },
deploy: false,
sync: false
})
t.teardown(async () => { try { await node.close() } catch {} })
const tracker = await node.issueRegistry.getForOrg('first-org')
t.ok(tracker.keyHex, 'primary auto-derived a fresh tracker root')
await tracker.create({ title: 'works', author: 'alice' })
t.is((await tracker.list()).length, 1, 'primary can write to its tracker')
})
test('strict mode: bindOrgBootstrapKey is a no-op when tracker is already open', async (t) => {
// Documents the deliberate non-behavior: at runtime, bind never
// close+reopens. If a tracker is already open at root A, binding
// root B is a no-op. The next boot picks up root B from the
// persisted index/bundle. This is the conservative choice that
// avoids the corestore-state crash; recovery for an already-corrupt
// mirror is `pgh device join` (re-pair), not an attempted runtime
// rebind.
const storage = tmpStorage()
const corestore = new Corestore(join(storage, 'store'))
await corestore.ready()
t.teardown(async () => { try { await corestore.close() } catch {} })
const registry = new IssueRegistry(corestore, {
indexPath: join(storage, 'issue-registry-index.json'),
requireBootstrap: false // permissive so we can open without a key
})
// Open with no bootstrap ⇒ auto-derived sibling (the legacy state).
const tracker = await registry.getForOrg('legacy-org')
const siblingRoot = tracker.keyHex
t.ok(siblingRoot, 'tracker opened with auto-derived root')
// Try to bind a different root.
const fakeCanonical = 'a'.repeat(64)
const result = registry.bindOrgBootstrapKey('legacy-org', fakeCanonical)
t.absent(result, 'bind returns false when tracker already open (no-op)')
const stillOpen = await registry.getForOrg('legacy-org')
t.is(stillOpen.keyHex, siblingRoot, 'tracker stays on its original root at runtime')
await registry.close()
})