// Byte-resolution failure diagnostics.
//
// `overlay.fetchFile` returns null for two ROOT-DISTINCT reasons, and the old log line asserted only
// one of them ("no connected peer served this oid"). That single misleading string cost days: a
// transport-level fault (the overlay channel never attached) read as a content fault (nobody holds the
// bytes), sending the investigation at the holder's index instead of at the wiring.
//
// It also deduped per-oid-per-PROCESS, so the line appeared once at boot and never again — a stale line
// was indistinguishable from a live failure, and could not be used to tell whether a repair had worked.
//
// These tests pin both properties, because this log line IS the diagnostic surface for a path that
// gates signing.
import test from 'brittle'
import { mkdtempSync, rmSync } from 'node:fs'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import { OverlayRepoStore } from '../lib/overlay-repo-store.js'
function tmp (t) { const d = mkdtempSync(join(tmpdir(), 'fmd-')); t.teardown(() => rmSync(d, { recursive: true, force: true })); return d }
// An overlay that always fails to fetch, with a settable peer count.
function mkOverlay (peerCount) {
return {
peerCount,
async registerFile () { return { contentHash: 'deadbeef' } },
async fetchFile () { return null } // the failure under test
}
}
// Capture console.error for the duration of a block.
async function capture (t, fn) {
const lines = []
const orig = console.error
console.error = (s) => lines.push(String(s))
t.teardown(() => { console.error = orig })
try { await fn() } finally { console.error = orig }
return lines.map((l) => { try { return JSON.parse(l) } catch { return { raw: l } } })
}
test('ZERO peers is reported as a transport/wiring fault, not a content fault', async (t) => {
const store = await new OverlayRepoStore(tmp(t), { overlay: mkOverlay(0), did: 'did:plc:x' }).ready()
const logs = await capture(t, async () => {
const r = await store.ensureLocal('app.bsky.feed.post', '3kaaa', 'abc123')
t.is(r, null, 'unresolvable record still returns null')
})
t.is(logs.length, 1, 'exactly one diagnostic emitted')
t.is(logs[0].overlayPeers, 0, 'the peer count is reported')
t.ok(/NO overlay peers attached/.test(logs[0].msg), 'classified as a transport/wiring fault')
t.absent(/none served this oid/.test(logs[0].msg), 'does NOT assert the content-fault cause')
})
test('peers attached but content missing is reported as a distribution fault', async (t) => {
const store = await new OverlayRepoStore(tmp(t), { overlay: mkOverlay(2), did: 'did:plc:x' }).ready()
const logs = await capture(t, async () => {
await store.ensureLocal('app.bsky.feed.post', '3kaaa', 'abc123')
})
t.is(logs.length, 1, 'exactly one diagnostic emitted')
t.is(logs[0].overlayPeers, 2, 'the peer count is reported')
t.ok(/none served this oid/.test(logs[0].msg), 'classified as a distribution fault')
})
test('dedup is keyed on peer count, so connectivity changes re-emit (staleness fix)', async (t) => {
const overlay = mkOverlay(0)
const store = await new OverlayRepoStore(tmp(t), { overlay, did: 'did:plc:x' }).ready()
const logs = await capture(t, async () => {
await store.ensureLocal('app.bsky.feed.post', '3kaaa', 'abc123')
await store.ensureLocal('app.bsky.feed.post', '3kaaa', 'abc123') // same oid, same peers → quiet
t.is(overlay.peerCount, 0, 'still no peers')
overlay.peerCount = 1 // a peer attaches
await store.ensureLocal('app.bsky.feed.post', '3kaaa', 'abc123') // → must re-emit
})
t.is(logs.length, 2, 'quiet on repeat, re-emits when the peer count changes')
t.is(logs[0].overlayPeers, 0, 'first line: no peers')
t.is(logs[1].overlayPeers, 1, 'second line: a peer attached and it STILL failed — the useful signal')
t.ok(/none served this oid/.test(logs[1].msg), 'and the classification flipped with the evidence')
})