// repair-bytes — filling the byte gap the 0.3.36 create-gate left behind.
//
// The engine is fully injected (refs, store, fetch, verify), so every branch here runs with no network,
// no corestore and no daemon. What is under test is the POLICY, which is the part that can hurt:
//
// - only ABSENCES are filled — a record with bytes is never rewritten (this is what makes the repair
// safe to run against hpp's own canonical files)
// - a dry run touches NOTHING
// - unverifiable bytes are never written, however plausible they look
// - bytes that do not survive decode->encode are never written — that round trip is the 2026-07-30
// outage, and a repair that reintroduced it would be worse than the gap it closes
//
// Run: node test/repair-bytes.test.mjs
import { repairBytes } from '../lib/repair-bytes.js'
import * as dagCbor from '@ipld/dag-cbor'
const assert = (cond, msg) => { if (!cond) throw new Error('FAIL: ' + msg); console.log(' ok -', msg) }
const DID = 'did:plc:wj62ebbusln6gxo5azo6ogzo'
const COLL = 'app.bsky.feed.post'
// A canonical record: dag-cbor round-trips it byte-identically, which is what the real bytes do.
const canonical = { $type: COLL, text: 'from the peer', createdAt: '2026-08-03T10:00:00.000Z', langs: ['en'] }
const canonicalBytes = dagCbor.encode(canonical)
// A store where `have` already has bytes and everything else is a hole.
function fakeStore (have = {}) {
const written = {}
return {
written,
async getRaw (collection, rkey) {
const k = collection + '/' + rkey
if (written[k]) return { bytes: dagCbor.encode(written[k]) }
return have[k] ? { bytes: have[k] } : null
},
async put (collection, rkey, value) { written[collection + '/' + rkey] = value }
}
}
const refsFor = (rkeys) => async function * () { for (const rkey of rkeys) yield { did: DID, rkey, collection: COLL } }
const okFetch = async (p) => ({ bytes: canonicalBytes, commit: {}, identity: {}, pointer: p })
const okVerify = async () => true
console.log('# a DRY RUN finds the gap and touches nothing')
{
const store = fakeStore({ [COLL + '/has-bytes']: canonicalBytes })
const r = await repairBytes({
dids: [DID], listRefs: refsFor(['has-bytes', 'gap1', 'gap2']), openStore: async () => store,
fetchRecord: okFetch, verifyRecord: okVerify, write: false
})
assert(r.scanned === 3, 'scanned every indexed ref (3)')
assert(r.present === 1, 'one record already had bytes')
assert(r.missing === 2, 'two are indexed with NO bytes — the defect footprint')
assert(r.written === 0, 'a dry run writes nothing')
assert(Object.keys(store.written).length === 0, 'and the store was not touched at all')
assert(r.samples.length === 2 && r.samples[0].rkey === 'gap1', 'the gaps are named, so a dry run is actionable')
}
console.log('\n# --write fills ONLY the holes')
{
const store = fakeStore({ [COLL + '/has-bytes']: canonicalBytes })
const r = await repairBytes({
dids: [DID], listRefs: refsFor(['has-bytes', 'gap1', 'gap2']), openStore: async () => store,
fetchRecord: okFetch, verifyRecord: okVerify, write: true
})
assert(r.written === 2, 'both gaps were fetched, verified and written')
assert(store.written[COLL + '/gap1'].text === 'from the peer', 'the canonical record landed')
assert(store.written[COLL + '/has-bytes'] === undefined, 'the record that ALREADY had bytes was never rewritten')
}
console.log('\n# a record no peer can produce is counted, not invented')
{
const store = fakeStore()
const r = await repairBytes({
dids: [DID], listRefs: refsFor(['lost']), openStore: async () => store,
fetchRecord: async () => null, verifyRecord: okVerify, write: true
})
assert(r.unfetchable === 1 && r.written === 0, 'unfetchable — the 2026-07-03 blob case, reported not faked')
assert(Object.keys(store.written).length === 0, 'nothing written')
}
console.log('\n# ⛔ bytes that FAIL verification are never written')
{
const store = fakeStore()
const r = await repairBytes({
dids: [DID], listRefs: refsFor(['forged']), openStore: async () => store,
fetchRecord: okFetch, verifyRecord: async () => false, write: true
})
assert(r.unverified === 1 && r.written === 0, 'a failed proof is refused — the key comes from the DID doc, not the server')
assert(Object.keys(store.written).length === 0, 'and nothing reached the store')
}
console.log('\n# ⛔ bytes that do not survive decode->encode are refused (the 2026-07-30 shape)')
{
// Non-canonical CBOR for the same value: a map encoded with a longer length header than necessary.
// It decodes fine and re-encodes to something SHORTER — exactly the class of drift that made a
// converged pointer unresolvable. The engine must notice and refuse.
const nonCanonical = new Uint8Array([0xb9, 0x00, 0x01, 0x61, 0x61, 0x01]) // {"a":1} with a 2-byte map header
const store = fakeStore()
const r = await repairBytes({
dids: [DID], listRefs: refsFor(['noncanon']), openStore: async () => store,
fetchRecord: async () => ({ bytes: nonCanonical, commit: {}, identity: {} }), verifyRecord: okVerify, write: true
})
assert(r.reencodeRefused === 1 && r.written === 0, 'a re-encode that differs from the verified bytes is refused')
assert(Object.keys(store.written).length === 0, 'the store never sees bytes that would not match their CID')
}
console.log('\n# --limit caps the work')
{
const store = fakeStore()
const r = await repairBytes({
dids: [DID], listRefs: refsFor(['a', 'b', 'c', 'd']), openStore: async () => store,
fetchRecord: okFetch, verifyRecord: okVerify, write: true, limit: 2
})
assert(r.written === 2, 'stopped after 2 attempts — a big backlog can be drained in bounded passes')
}
console.log('\n# a ref with no collection cannot be located or asked for — counted, never guessed')
{
const store = fakeStore()
const listRefs = async function * () { yield { did: DID, rkey: 'old', collection: null } }
const r = await repairBytes({ dids: [DID], listRefs, openStore: async () => store, fetchRecord: okFetch, verifyRecord: okVerify, write: true })
assert(r.scanned === 1 && r.storeErrors === 1 && r.written === 0, 'an unlocatable ref is an error, not a silent skip')
}
console.log('\n# a store that will not open does not abort the whole run')
{
const good = fakeStore()
const r = await repairBytes({
dids: ['did:plc:broken', DID],
listRefs: refsFor(['gap1']),
openStore: async (did) => { if (did === 'did:plc:broken') throw new Error('locked'); return good },
fetchRecord: okFetch, verifyRecord: okVerify, write: true
})
assert(r.storeErrors === 1, 'the broken DID is reported')
assert(r.written === 1, 'and the healthy one is still repaired')
}
console.log('\n# --write demands the fetch/verify pair — a half-wired caller fails loudly')
{
let threw = false
try {
await repairBytes({ dids: [DID], listRefs: refsFor(['x']), openStore: async () => fakeStore(), write: true })
} catch { threw = true }
assert(threw, 'writing without a verifier is refused at the door')
}
console.log('\nall repair-bytes assertions passed')