// mirror.test.js — hold the bytes of feeds you follow, before anyone asks to read them.
//
// ⛔ THE OUTAGE THIS CLOSES, measured 2026-09-08. tabertron held five pointers from ashatron and
// could read none of them: ashatron is a laptop, it went offline, and it was the only machine
// holding the bytes. Nothing was broken — bytes are fetched only when a reader asks, nobody had
// asked, so no second copy existed. The surface said so honestly: "the log arrived, the bytes did
// not."
//
// ★ AND THE FIX IS ONLY A TRIGGER. Two things already work and must not be rebuilt:
// - a fetch WRITES the record into this feed's working tree, so the copy is durable
// - hyper-overlay RE-SEEDS on fetch, so this node then serves those bytes to others
// So reading a record once already makes you a mirror of it. Nothing reads unprompted; that is all
// that is missing. See hyper-social/docs/HOLDING-AND-TELLING.md.
//
// ⛔ FOLLOWED FEEDS ONLY. `timeline` already excludes peeked feeds because putting them in "would
// make reading a stranger's page indistinguishable from following them". Mirroring a peek would be
// that same collapse with disk attached: every profile you glanced at becomes a permanent copy.
import test from 'brittle'
import { createMirror } from '../lib/mirror.js'
// A feed with pointers and a store that knows what is local. `pointers()` never fetches — that is
// the whole reason it exists, since list() and unresolved() both resolve every record.
function fakeFeed (names, { local = [], fail = [], onFetch = () => {} } = {}) {
const localSet = new Set(local)
return {
async pointers () {
return names.map((n) => ({ key: 'post/' + n, collection: 'post', name: n, pointer: { $oid: 'oid-' + n, size: 1 } }))
},
store: {
async get (_c, n) { return localSet.has(n) ? { body: n } : null },
async ensureLocal (_c, n) {
onFetch(n)
if (fail.includes(n)) throw new Error('no peer has ' + n)
localSet.add(n)
return { body: n }
}
}
}
}
// An autobee's writer cores. `w.core.on('append')` is the real signal that blocks landed —
// including replicated ones. autobee itself emits no view-advanced event.
function fakeBase () {
const h = []
const core = {
on: (_e, fn) => h.push(fn),
off: (_e, fn) => { const i = h.indexOf(fn); if (i >= 0) h.splice(i, 1) }
}
return { writers: [{ core }], emit: () => h.slice().forEach((fn) => fn()), listeners: () => h.length }
}
test('★★ it fetches records nobody asked to read', async (t) => {
const fetched = []
const feed = fakeFeed(['a', 'b', 'c'], { onFetch: (n) => fetched.push(n) })
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], log: () => {} })
await m.pass()
t.alike(fetched.sort(), ['a', 'b', 'c'], 'all three, with no reader involved')
})
test('★ a record already on disk is not fetched again', async (t) => {
const fetched = []
const feed = fakeFeed(['a', 'b'], { local: ['a'], onFetch: (n) => fetched.push(n) })
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], log: () => {} })
await m.pass()
t.alike(fetched, ['b'], 'only the missing one')
})
// ⚠ The layer below already bounds CHUNKS — the scheduler holds an RTT-scaled inflight window per
// peer. What is unbounded is the number of FILES, and a freshly followed feed is all of them.
test('★★ never more than `concurrency` fetches in flight', async (t) => {
let now = 0
let peak = 0
const names = Array.from({ length: 20 }, (_, i) => 'r' + i)
const feed = fakeFeed(names, { onFetch: () => {} })
// Wrap ensureLocal to hold the slot open across a tick so overlap is observable.
const inner = feed.store.ensureLocal
feed.store.ensureLocal = async (c, n) => {
now++; peak = Math.max(peak, now)
await new Promise((r) => setTimeout(r, 5))
now--
return inner.call(feed.store, c, n)
}
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], concurrency: 3, log: () => {} })
await m.pass()
t.is(peak, 3, 'the cap held')
t.absent(now, 'and everything drained')
})
test('⛔ one unfetchable record does not stop the rest', async (t) => {
const fetched = []
const feed = fakeFeed(['a', 'b', 'c'], { fail: ['b'], onFetch: (n) => fetched.push(n) })
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], log: () => {} })
await m.pass()
t.alike(fetched.sort(), ['a', 'b', 'c'], 'every one was attempted')
// b stays missing and will be retried on the next pass — a peer that is away is not a peer that
// is gone, and this is exactly the state the surface reports as unresolved.
})
test('★ it mirrors every followed feed, not just the first', async (t) => {
const one = []; const two = []
const m = createMirror({
feeds: () => [
{ key: 'f1', feed: fakeFeed(['a'], { onFetch: (n) => one.push(n) }) },
{ key: 'f2', feed: fakeFeed(['b'], { onFetch: (n) => two.push(n) }) }
],
log: () => {}
})
await m.pass()
t.alike(one, ['a'])
t.alike(two, ['b'])
})
test('★ stop() ends the pass, and a stopped mirror does nothing', async (t) => {
const fetched = []
const feed = fakeFeed(['a', 'b', 'c'], { onFetch: (n) => fetched.push(n) })
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], log: () => {} })
m.stop()
await m.pass()
t.is(fetched.length, 0, 'nothing after stop')
})
test('⛔ a feed that cannot be listed is skipped, not fatal', async (t) => {
const fetched = []
const bad = { async pointers () { throw new Error('view not ready') } }
const good = fakeFeed(['a'], { onFetch: (n) => fetched.push(n) })
const m = createMirror({ feeds: () => [{ key: 'bad', feed: bad }, { key: 'ok', feed: good }], log: () => {} })
await m.pass()
t.alike(fetched, ['a'], 'the healthy feed still mirrored')
})
// ⛔ THE BUG THE UNIT TESTS MISSED, found by an end-to-end run on two machines.
//
// The first version swept once at boot. At boot a followed feed's log has usually NOT replicated
// yet — the swarm connection is still forming — so the sweep ran, correctly found nothing, and
// never ran again. Measured: a record posted on ashatron was still absent on tabertron 2.5 minutes
// and one restart later, and appeared instantly the moment something READ it.
//
// Every fake above hands back its pointers immediately, so none of them could express "the log
// arrives later". This one does.
test('★★ a log that advances AFTER the boot pass still gets mirrored', async (t) => {
let names = []
const fetched = []
const feed = {
async pointers () {
return names.map((n) => ({ key: 'post/' + n, collection: 'post', name: n, pointer: { $oid: 'oid-' + n } }))
},
store: {
async get () { return null },
async ensureLocal (_c, n) { fetched.push(n); return { body: n } }
}
}
// ⛔ A WRITER CORE, not the autobee. autobee emits no view-advanced event — see mirror.js.
const base = fakeBase()
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], debounceMs: 10, log: () => {} })
m.watch(base)
await m.pass() // the boot pass: finds nothing, and attaches the append hooks
t.is(fetched.length, 0, 'boot pass finds nothing — the log has not arrived')
t.is(m.stats().hooked, 1, 'but it DID hook the writer core — the thing 0.0.42 silently did not')
names = ['late'] // the log replicates
base.emit() // autobee says the view advanced
await new Promise((r) => setTimeout(r, 60))
t.alike(fetched, ['late'], 'and it is mirrored without anyone reading it')
})
test('★ a burst of updates coalesces into one pass', async (t) => {
let passes = 0
const feed = {
async pointers () { passes++; return [] },
store: { async get () { return null }, async ensureLocal () { return null } }
}
const base = fakeBase()
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], debounceMs: 20, log: () => {} })
m.watch(base)
await m.pass() // ⛔ hooks attach during a PASS, not at watch() — writers do not exist yet at open
const after = passes
for (let i = 0; i < 10; i++) base.emit()
await new Promise((r) => setTimeout(r, 80))
t.is(passes - after, 1, 'ten appends, one sweep — a core appends far more often than records land')
})
test('★ stop() detaches the watcher', async (t) => {
let passes = 0
const feed = {
async pointers () { passes++; return [] },
store: { async get () { return null }, async ensureLocal () { return null } }
}
const base = fakeBase()
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], debounceMs: 10, log: () => {} })
m.watch(base)
m.stop()
base.emit()
await new Promise((r) => setTimeout(r, 40))
t.is(passes, 0, 'nothing sweeps after stop')
t.is(base.listeners(), 0, 'and the listener is gone')
})
// ⛔ The view only advances when apply runs, so replicated blocks can be sitting in the writer
// cores with `pointers()` still reporting the old set. A sweep that skipped the refresh would keep
// finding "nothing new" while the log had grown — which is indistinguishable from the 0.0.40 bug
// and would have been just as invisible.
test('★★ a sweep refreshes the view before reading pointers', async (t) => {
const order = []
let names = []
const feed = {
async update () { order.push('update'); names = ['fresh'] },
async pointers () {
order.push('pointers')
return names.map((n) => ({ key: 'post/' + n, collection: 'post', name: n, pointer: { $oid: 'o' } }))
},
store: { async get () { return null }, async ensureLocal (_c, n) { order.push('fetch:' + n); return { body: n } } }
}
await createMirror({ feeds: () => [{ key: 'f1', feed }], log: () => {} }).pass()
t.alike(order, ['update', 'pointers', 'fetch:fresh'], 'refresh, then read, then fetch')
})
// ⛔ A PEER COMING BACK IS AN EVENT, NOT AN ABSENCE. A record stays unresolved because nobody
// holding its bytes is online; their return is a swarm 'connection'. Re-checking that on a clock
// was polling for data — the part of the rule that IS absolute.
test('★★ a peer connecting retries what could not be fetched', async (t) => {
let peerHere = false
const fetched = []
const feed = {
async update () {},
async pointers () { return [{ key: 'post/a', collection: 'post', name: 'a', pointer: { $oid: 'o' } }] },
store: {
async get () { return null },
async ensureLocal (_c, n) { if (!peerHere) return null; fetched.push(n); return { body: n } }
}
}
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], debounceMs: 10, log: () => {} })
await m.pass()
t.is(fetched.length, 0, 'nobody has it yet')
peerHere = true
m.onPeer()
await new Promise((r) => setTimeout(r, 60))
t.alike(fetched, ['a'], 'fetched when the holder came back')
t.is(m.stats().connection, 1, 'and the connection trigger is what did it')
})
// ⛔ LEVEL 2. A record's own bytes are one oid in the log; the pictures and files it names are more
// oids, inside its markdown. Mirroring only the first leaves a post you can read with an image that
// will not load — the same failure as §0's outage, one level down. Following means holding what
// somebody published, and a picture is part of what they published.
//
// ⚠ Both levels are the SAME hyper-overlay: files.js says "There is NO blob store", and a record
// and an image are both registerFile/fetchFile by content hash. There is one store here, not two.
test('★★ it mirrors the files a record names, not just the record', async (t) => {
const gotOids = []
const body = 'look\n\n + ')\n\n' +
'[the pdf](favela://blob/' + 'b'.repeat(32) + ')\n'
const feed = {
async update () {},
async pointers () { return [{ key: 'post/p1', collection: 'post', name: 'p1', pointer: { $oid: 'rec' } }] },
store: {
async get () { return null },
async ensureLocal () { return { frontmatter: {}, body } }
}
}
const files = { async get (oid) { gotOids.push(oid); return { path: '/x', mimeType: 'image/png', size: 1 } } }
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], files, log: () => {} })
await m.pass()
t.alike(gotOids.sort(), ['a'.repeat(32), 'b'.repeat(32)], 'the image AND the linked file')
t.is(m.stats().files, 2, 'counted separately from records')
})
test('★ a record naming no files costs no extra fetches', async (t) => {
let calls = 0
const feed = {
async update () {},
async pointers () { return [{ key: 'post/p1', collection: 'post', name: 'p1', pointer: { $oid: 'r' } }] },
store: { async get () { return null }, async ensureLocal () { return { frontmatter: {}, body: 'just words' } } }
}
const m = createMirror({ feeds: () => [{ key: 'f1', feed }], files: { async get () { calls++; return null } }, log: () => {} })
await m.pass()
t.is(calls, 0)
})
// ⛔ A file we cannot fetch must not fail the record that named it. The record is already held and
// readable; the picture is simply missing, which is the honest UNRESOLVED state one level down.
test('⛔ an unfetchable file does not undo the record', async (t) => {
const feed = {
async update () {},
async pointers () { return [{ key: 'post/p1', collection: 'post', name: 'p1', pointer: { $oid: 'r' } }] },
store: {
async get () { return null },
async ensureLocal () { return { frontmatter: {}, body: ' + ')' } }
}
}
const m = createMirror({
feeds: () => [{ key: 'f1', feed }],
files: { async get () { throw new Error('no holder online') } },
log: () => {}
})
const r = await m.pass()
t.is(r.fetched, 1, 'the record still counts as mirrored')
t.is(m.stats().files, 0, 'and the file did not')
})