// SPIKE-AUTOBEE-DURABILITY — go/no-go: can an encrypted multi-writer Autobase be
// HiveRelay-pinned and re-served to a fresh never-writer node after ALL writers
// go offline, byte-identical? Gates N5 / PAY1 / PAY6 / NOSTR1.
//
// VERDICT: GREEN ✅
// 1. Encrypted multi-writer Autobase converges (writer promotion works).
// 2. After ALL writers go offline, a fresh never-writer node re-serves the
// converged view BYTE-IDENTICAL from a replica.
// 3. The replica can be BLIND — it holds the opaque encrypted cores with NO
// encryption key; only the keyed reader decrypts.
// 4. KEY LESSON: the durable artifact is the AUTOBASE (re-derived from the
// op-log cores a replica holds), NOT the standalone view core — opening the
// view core directly with the master key fails (Autobase derives per-core
// keys internally). So a consumer re-opens the manager + replicates; it does
// not pin/serve the view core in isolation.
//
// Offline, Node-only, deterministic. Uses the production encrypted-autobase
// helper as the consumer template.
import test from 'node:test'
import assert from 'node:assert/strict'
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import Corestore from 'corestore'
import Hyperbee from 'hyperbee'
import b4a from 'b4a'
import helperMod from '../backend/encrypted-autobase-helper.cjs'
const { createEncryptedAutobaseManager } = helperMod
const ENC = b4a.alloc(32, 0x9)
const tmps = []
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
function wire (a, b) {
const s1 = a.replicate(true); const s2 = b.replicate(false)
s1.on('error', () => {}); s2.on('error', () => {})
s1.pipe(s2).pipe(s1)
return () => { try { s1.destroy() } catch {} try { s2.destroy() } catch {} }
}
async function until (label, pred, ms = 8000) {
const t0 = Date.now()
while (Date.now() - t0 < ms) { if (await pred()) return true; await sleep(120) }
throw new Error('timeout: ' + label)
}
const applyOp = async (op, view) => {
const h = await view.get('meta!count').catch(() => null)
const c = h && Number.isFinite(h.value) ? h.value : 0
await view.put('item!' + String(c).padStart(6, '0'), op)
await view.put('meta!count', c + 1)
}
async function items (mgr) {
await mgr.update()
const out = []
for await (const e of mgr.view.createReadStream({ gte: 'item!', lt: 'item!~' })) out.push(e.value)
return out
}
async function newStore () {
const dir = await mkdtemp(join(tmpdir(), 'spike-dur-')); tmps.push(dir)
const store = new Corestore(dir); await store.ready()
return { store, dir }
}
test('encrypted multi-writer Autobase converges (writer promotion)', async () => {
const a = await newStore(); const b = await newStore()
const A = await createEncryptedAutobaseManager(a.store, { applyOp, encryptionKey: ENC, namespace: 'd' }).ready()
await A.append({ n: 'a1' })
const B = await createEncryptedAutobaseManager(b.store, { applyOp, bootstrap: A.key, encryptionKey: ENC, namespace: 'd' }).ready()
const unwire = wire(a.store, b.store)
try {
await until('B replicates a1', async () => (await items(B)).some((x) => x.n === 'a1'))
assert.equal(B.writable, false)
await A.addWriter(B.localKey)
await until('B writable', async () => { await B.update(); return B.writable })
await B.append({ n: 'b1' })
await until('converge', async () => {
const ai = (await items(A)).map((x) => x.n).sort()
const bi = (await items(B)).map((x) => x.n).sort()
return ai.length === 2 && JSON.stringify(ai) === JSON.stringify(bi)
})
assert.deepEqual((await items(A)).map((x) => x.n).sort(), ['a1', 'b1'])
} finally { unwire(); await A.close(); await B.close(); await a.store.close(); await b.store.close() }
})
test('DURABILITY: a fresh never-writer node re-serves byte-identical after all writers go offline', async () => {
const a = await newStore(); const p = await newStore(); const c = await newStore()
const A = await createEncryptedAutobaseManager(a.store, { applyOp, encryptionKey: ENC, namespace: 'd' }).ready()
await A.append({ n: 1 }); await A.append({ n: 2 }); await A.append({ n: 3 })
const golden = (await items(A)).map((x) => x.n)
// replica P (key-holding) mirrors A
const P = await createEncryptedAutobaseManager(p.store, { applyOp, bootstrap: A.key, encryptionKey: ENC, namespace: 'd' }).ready()
const uw1 = wire(a.store, p.store)
await until('P mirrors A', async () => (await items(P)).length === 3)
// the ONLY writer goes offline
uw1(); await A.close(); await a.store.close()
// fresh never-writer C re-serves from P
const C = await createEncryptedAutobaseManager(c.store, { applyOp, bootstrap: A.key, encryptionKey: ENC, namespace: 'd' }).ready()
const uw2 = wire(p.store, c.store)
try {
await until('C re-serves', async () => (await items(C)).length === 3)
assert.deepEqual((await items(C)).map((x) => x.n), golden) // byte-identical view
} finally { uw2(); await P.close(); await C.close(); await p.store.close(); await c.store.close() }
})
test('BLIND PIN: a relay holds the encrypted cores with NO key; a keyed reader re-serves through it', async () => {
const a = await newStore(); const p = await newStore(); const c = await newStore()
const A = await createEncryptedAutobaseManager(a.store, { applyOp, encryptionKey: ENC, namespace: 'd' }).ready()
await A.append({ n: 1 }); await A.append({ n: 2 })
// blind relay P: opens by bootstrap with NO encryption key. It can't decrypt to
// materialize a view (its view stays empty), but it REPLICATES + holds the
// opaque encrypted cores at the corestore level — that's the blind pin.
const Pblind = await createEncryptedAutobaseManager(p.store, { applyOp, bootstrap: A.key, encryptionKey: null, namespace: 'd' }).ready()
const uw1 = wire(a.store, p.store)
for (let i = 0; i < 25; i++) { await Pblind.update().catch(() => {}); await sleep(120) } // hold the encrypted bytes
uw1(); await A.close(); await a.store.close()
const C = await createEncryptedAutobaseManager(c.store, { applyOp, bootstrap: A.key, encryptionKey: ENC, namespace: 'd' }).ready()
const uw2 = wire(p.store, c.store)
try {
await until('C re-serves via blind relay', async () => (await items(C)).length === 2)
assert.deepEqual((await items(C)).map((x) => x.n), [1, 2])
} finally { uw2(); await Pblind.close(); await C.close(); await p.store.close(); await c.store.close() }
})
test('LESSON: the view core cannot be re-served standalone with the master key (must re-derive)', async () => {
const a = await newStore(); const c = await newStore()
const A = await createEncryptedAutobaseManager(a.store, { applyOp, encryptionKey: ENC, namespace: 'd' }).ready()
await A.append({ n: 1 }); await A.append({ n: 2 }); await A.update()
const vcore = A.view.core || A.view.feed
const viewKey = b4a.from(b4a.toString(vcore.key, 'hex'), 'hex')
const uw = wire(a.store, c.store)
// open the view core DIRECTLY (bypassing Autobase) with the master enc key
let standaloneItems = null
try {
const cCore = c.store.get({ key: viewKey, encryptionKey: ENC })
await cCore.ready()
await Promise.race([cCore.update({ wait: true }), sleep(1500)]).catch(() => {})
const bee = new Hyperbee(cCore, { keyEncoding: 'utf-8', valueEncoding: 'json' })
await bee.ready()
standaloneItems = []
for await (const e of bee.createReadStream({ gte: 'item!', lt: 'item!~' })) standaloneItems.push(e.value)
} catch (_) { standaloneItems = 'threw' } // Autobase per-core key derivation → decode error
// either it threw, or it did NOT reproduce the view — standalone view-core pinning is NOT the path
assert.notDeepEqual(standaloneItems, [{ n: 1 }, { n: 2 }])
uw(); await A.close(); await a.store.close(); await c.store.close()
})
test.after(async () => {
for (const dir of tmps) { try { await rm(dir, { recursive: true, force: true }) } catch {} }
})