// Two corestores, one connection: whoever replicates FIRST owns the core's channel.
//
// bootMultiDevice replicates several corestores over each connection — the shared store plus, for a
// resynced or pre-cutover DID, that DID's own side store. Corestore keys hypercore channels by DISCOVERY
// KEY on a Protomux that is SHARED per stream (Protomux.from(stream) is cached on the stream), so when two
// of those stores hold the SAME core, the second attach is a duplicate and Protomux answers with null.
//
// The loser does not error, does not conflict, and reports a perfectly healthy local state — it simply
// stays at length 0 forever. That is the worst diagnostic shape there is, and it is indistinguishable from
// "the peer has nothing for us" without knowing to look here.
//
// For a DID whose base lives in a side store, the side store is the AUTHORITATIVE copy (the shared store's
// is the abandoned pre-resync one), so the side store must replicate FIRST. This pins that ordering, and
// pins the negative case so the bug cannot come back by reordering the handler.
//
// It also pins a boundary: a stale core merely ON DISK in the shared store does not STARVE the side
// store, so leftover files are not automatically fatal to the ordering this file is about.
//
// ⚠️ CORRECTED 2026-07-30. This header used to justify that with "corestore does not auto-open cores on
// remote interest". That is FALSE, and the third test never measured it — it asserts only that the SIDE
// store reached length 3, and its on-disk copy is the SAME history as the writer's, so an auto-open
// would have been invisible. corestore 7.11.0 DOES auto-open an on-disk core when a peer announces its
// discovery key (ondiscoverykey -> _attachMaybe -> _openCore, index.js:453-491). The claim was cited as
// evidence that the divergent 4-block copy in stortron's shared store was inert; the conflict watcher
// then caught that copy participating. See test/shared-store-autoopen.test.js, which measures the open
// directly and reproduces the production shape. Scope this test to channel PRIORITY only.
//
// Run: bare test/side-store-channel-priority.test.js
import '../lib/bare-globals.js'
import test from 'brittle'
import fs from 'bare-fs'
import Corestore from 'corestore'
const tmp = (p) => { const d = '/tmp/hpp-chan-' + p + '-' + Math.floor(Math.random() * 1e9); fs.mkdirSync(d, { recursive: true }); return d }
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
const BLOCKS = [Buffer.from('a'), Buffer.from('b'), Buffer.from('c')]
// A writer store holding one core with 3 blocks — the "incumbent" side of the connection.
async function writer (t) {
const store = new Corestore(tmp('writer'))
await store.ready()
const core = store.get({ name: 'the-base' })
await core.ready()
await core.append(BLOCKS)
t.teardown(async () => { try { await store.close() } catch {} })
return { store, key: core.key }
}
// Wire one connection replicated by both stores in the given order, and report what the SIDE store got.
async function syncOverOneConn (t, wStore, shared, side, { sideFirst }) {
const a = wStore.replicate(true)
const b = sideFirst ? side.replicate(false) : shared.replicate(false)
if (sideFirst) shared.replicate(b); else side.replicate(b)
a.pipe(b).pipe(a)
t.teardown(() => { try { a.destroy(); b.destroy() } catch {} })
await sleep(1500)
}
test('shared store FIRST starves a side store that holds the same core', async (t) => {
const w = await writer(t)
const shared = new Corestore(tmp('shared'))
const side = new Corestore(tmp('side'))
await shared.ready(); await side.ready()
t.teardown(async () => { try { await shared.close(); await side.close() } catch {} })
const sideCore = side.get({ key: w.key }); await sideCore.ready()
const sharedCore = shared.get({ key: w.key }); await sharedCore.ready() // the abandoned pre-resync copy
await syncOverOneConn(t, w.store, shared, side, { sideFirst: false })
t.is(sideCore.length, 0, 'the SIDE store is starved — stuck at 0, with no error and no conflict')
t.is(sharedCore.length, 3, 'because the shared store claimed the channel for that discovery key')
})
test('side store FIRST wins the channel — the authoritative copy syncs', async (t) => {
const w = await writer(t)
const shared = new Corestore(tmp('shared'))
const side = new Corestore(tmp('side'))
await shared.ready(); await side.ready()
t.teardown(async () => { try { await shared.close(); await side.close() } catch {} })
const sideCore = side.get({ key: w.key }); await sideCore.ready()
const sharedCore = shared.get({ key: w.key }); await sharedCore.ready()
await syncOverOneConn(t, w.store, shared, side, { sideFirst: true })
t.is(sideCore.length, 3, 'the SIDE store replicated — this is the ordering bootMultiDevice must use')
t.is(sharedCore.length, 0, 'and the abandoned shared-store copy is the one left behind, which is correct')
})
test('a stale core merely ON DISK in the shared store does not STARVE the side store', async (t) => {
// The boundary case for channel priority. NOTE what this does and does not show: the side store still
// syncs, so an unopened on-disk copy does not win the channel here. It does NOT show that the copy
// stays closed — corestore auto-opens it on remote interest (shared-store-autoopen.test.js), and
// because this copy is the SAME history as the writer's, an auto-open is invisible to this assertion.
const w = await writer(t)
const sharedDir = tmp('shared-ondisk')
// Put the core on disk in the shared store, then close it so nothing holds it open.
{
const s = new Corestore(sharedDir); await s.ready()
const c = s.get({ key: w.key }); await c.ready()
const a = w.store.replicate(true); const b = s.replicate(false); a.pipe(b).pipe(a)
await sleep(1200)
t.is(c.length, 3, 'precondition: the shared store has the core ON DISK')
try { a.destroy(); b.destroy() } catch {}
await sleep(200)
await s.close()
}
const shared = new Corestore(sharedDir); await shared.ready() // reopened, core NOT opened
const side = new Corestore(tmp('side3')); await side.ready()
t.teardown(async () => { try { await shared.close(); await side.close() } catch {} })
const sideCore = side.get({ key: w.key }); await sideCore.ready()
await syncOverOneConn(t, w.store, shared, side, { sideFirst: false })
t.is(sideCore.length, 3, 'the side store still replicates — an unopened on-disk copy does not claim the CHANNEL')
})