// ensureLocal must VERIFY a local hit against the converged pointer, not just find one.
//
// The pointer design converges { $oid, size } in the shared autobase and keeps the bytes as
// content-addressed overlay files. ensureLocal returned any local file it found WITHOUT comparing it
// to the requested oid, so content-addressing was used to FETCH but never to VERIFY. A node holding a
// SUPERSEDED copy of a record resolved it happily, never re-fetched, and signed it as truth.
//
// Live on wj62 (2026-07-27): two co-owners, identical 139 converged pointers, both resolving all 139,
// yet different signed repos — differing on exactly one record, app.bsky.actor.profile/self, with two
// different avatar blob refs. The published profile therefore flipped avatar on every signer change.
//
// The repair must not destroy what we hold until the replacement is verified, so it fetches to a
// sibling temp path, re-asserts the hash, then renames into place.
//
// Run: brittle-node test/ensure-local-verify.test.js
import test from 'brittle'
import fs from 'fs'
import os from 'os'
import path from 'path'
import crypto from 'hypercore-crypto'
import { OverlayRepoStore } from '../lib/overlay-repo-store.js'
const tmp = () => fs.mkdtempSync(path.join(os.tmpdir(), 'els-'))
const POST = 'app.bsky.feed.post'
const PROFILE = 'app.bsky.actor.profile'
// A content-addressed transport. `net` is the set of bytes any peer can serve.
function mkOverlay (net, opts = {}) {
return {
registered: [],
async registerFile (overlayPath, diskPath, o = {}) {
const bytes = fs.readFileSync(diskPath)
const oid = crypto.data(bytes).toString('hex')
net.set(oid, bytes)
this.registered.push({ overlayPath, diskPath, oid })
return { contentHash: oid }
},
async fetchFile (oid, o = {}) {
if (opts.offline) return null
const bytes = net.get(oid)
if (!bytes) return null
fs.writeFileSync(o.destPath, opts.corrupt ? Buffer.concat([bytes, Buffer.from('x')]) : bytes)
if (o.reSeed !== false) this.registered.push({ reSeeded: o.destPath, oid })
return { destPath: o.destPath, local: false, size: bytes.length }
},
async hashFile (p) {
let bytes
try { bytes = fs.readFileSync(p) } catch { return null }
return { contentHash: crypto.data(bytes).toString('hex'), size: bytes.length }
}
}
}
const MINE = { $type: PROFILE, displayName: 'wj62', avatar: { ref: { $link: 'bafkreiAAA' }, size: 6533 } }
const THEIRS = { $type: PROFILE, displayName: 'wj62', avatar: { ref: { $link: 'bafkreiBBB' }, size: 5962 } }
// Author a record as the other peer would: seeds `net` and returns the converged pointer oid.
async function authorElsewhere (net, collection, rkey, record) {
const s = await new OverlayRepoStore(tmp(), { overlay: mkOverlay(net) }).ready()
const { oid } = await s.put(collection, rkey, record)
return oid
}
test('a local hit that does NOT match the pointer is replaced with the authoritative bytes', async (t) => {
const net = new Map()
const root = tmp()
const ov = mkOverlay(net)
const store = await new OverlayRepoStore(root, { overlay: ov, did: 'did:plc:x' }).ready()
const { oid: mineOid } = await store.put(PROFILE, 'self', MINE) // what we hold
const theirsOid = await authorElsewhere(net, PROFILE, 'self', THEIRS) // what converged
t.not(mineOid, theirsOid, 'precondition: the pointer names different bytes than we hold')
const got = await store.ensureLocal(PROFILE, 'self', theirsOid)
t.alike(got, THEIRS, 'resolves to the record the group agreed on, not our superseded copy')
const after = await store.localOid(PROFILE, 'self')
t.is(after.oid, theirsOid, 'the file on disk now hashes to the converged pointer')
t.alike(await store.get(PROFILE, 'self'), THEIRS, 'and reads back as the authoritative record')
t.absent(fs.existsSync(path.join(root, 'records', PROFILE, 'self.dagcbor.incoming-' + theirsOid.slice(0, 12))), 'no temp file left behind')
t.ok(ov.registered.some((r) => r.diskPath && r.diskPath.endsWith('self.dagcbor') && r.oid === theirsOid), 're-registered the FINAL path so this node now serves the correct bytes')
})
test('a matching local hit is returned without any fetch (the common path is untouched)', async (t) => {
const net = new Map()
const ov = mkOverlay(net)
const store = await new OverlayRepoStore(tmp(), { overlay: ov, did: 'did:plc:x' }).ready()
const { oid } = await store.put(POST, '3kaaa', { $type: POST, text: 'hi', createdAt: '2026-07-27T00:00:00.000Z' })
const before = ov.registered.length
const got = await store.ensureLocal(POST, '3kaaa', oid)
t.alike(got, { $type: POST, text: 'hi', createdAt: '2026-07-27T00:00:00.000Z' }, 'returns the local record')
t.is(ov.registered.length, before, 'and did not fetch or re-register anything')
})
test('with no oid to check against, a local hit is returned unchanged (legacy / no-overlay)', async (t) => {
const net = new Map()
const store = await new OverlayRepoStore(tmp(), { overlay: mkOverlay(net), did: 'did:plc:x' }).ready()
await store.put(POST, '3kbbb', { $type: POST, text: 'legacy', createdAt: '2026-07-27T00:00:00.000Z' })
const got = await store.ensureLocal(POST, '3kbbb', null)
t.alike(got, { $type: POST, text: 'legacy', createdAt: '2026-07-27T00:00:00.000Z' }, 'unchanged behaviour when there is nothing to verify against')
})
test('if the authoritative bytes cannot be fetched, the STALE file is preserved and the read is unresolved', async (t) => {
const net = new Map()
const root = tmp()
const store = await new OverlayRepoStore(root, { overlay: mkOverlay(net, { offline: true }), did: 'did:plc:x' }).ready()
const { oid: mineOid } = await store.put(PROFILE, 'self', MINE)
const theirsOid = await authorElsewhere(new Map(), PROFILE, 'self', THEIRS) // nobody reachable serves it
const got = await store.ensureLocal(PROFILE, 'self', theirsOid)
t.is(got, null, 'returns null — a node that cannot prove its bytes match the pointer must not sign them')
const still = await store.localOid(PROFILE, 'self')
t.is(still.oid, mineOid, 'the superseded file is PRESERVED, not destroyed, on a failed repair')
t.absent(fs.existsSync(path.join(root, 'records', PROFILE, 'self.dagcbor.incoming-' + theirsOid.slice(0, 12))), 'and no temp file is left behind')
})
test('bytes that arrive not matching the requested oid are rejected and the local file is kept', async (t) => {
const net = new Map()
const root = tmp()
const store = await new OverlayRepoStore(root, { overlay: mkOverlay(net, { corrupt: true }), did: 'did:plc:x' }).ready()
const { oid: mineOid } = await store.put(PROFILE, 'self', MINE)
const theirsOid = await authorElsewhere(net, PROFILE, 'self', THEIRS)
const got = await store.ensureLocal(PROFILE, 'self', theirsOid)
t.is(got, null, 'mismatched bytes are refused')
const still = await store.localOid(PROFILE, 'self')
t.is(still.oid, mineOid, 'the existing file is untouched — persistent state is never replaced by unverified bytes')
})
test('a pointer with no local bytes still fetches normally (the unchanged missing-bytes path)', async (t) => {
const net = new Map()
const root = tmp()
const store = await new OverlayRepoStore(root, { overlay: mkOverlay(net), did: 'did:plc:x' }).ready()
const oid = await authorElsewhere(net, POST, '3kccc', { $type: POST, text: 'pulled', createdAt: '2026-07-27T00:00:00.000Z' })
const got = await store.ensureLocal(POST, '3kccc', oid)
t.alike(got, { $type: POST, text: 'pulled', createdAt: '2026-07-27T00:00:00.000Z' }, 'fetched into place')
t.is((await store.localOid(POST, '3kccc')).oid, oid, 'and hashes to the pointer')
})