OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-store / test / overlay-repo-store.test.js

137 lines · javascript ref:
// Phase 1 determinism proof: the file-based OverlayRepoStore must derive a BYTE-IDENTICAL
// atproto repo (commit CID, MST root, CAR) to the append-only Hyperbee RepoStore, so it is a
// safe drop-in. If these pass, "records as deduped files + MST/commit derived on read" is proven
// equivalent to today's store — with O(current records) disk instead of O(operations-ever).

import test from 'brittle'
import { mkdtempSync, rmSync } from 'node:fs'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import b4a from 'b4a'
import { RepoStore } from '../lib/repo-store.js'
import { OverlayRepoStore } from '../lib/overlay-repo-store.js'
import { RepoManager } from '../lib/repo-manager.js'
import { getRepo } from '../lib/read-view.js'

const DID = 'did:plc:test123'
const KEY = (() => { const k = b4a.alloc(32); k[31] = 7; return k })() // fixed valid secp256k1 scalar (deterministic sig)
const REV = '3ktestrev00000'
const META = { did: DID, rev: REV, prev: null, privateKey: KEY }

const RECORDS = [
  { collection: 'app.bsky.actor.profile', rkey: 'self', record: { $type: 'app.bsky.actor.profile', displayName: 'Test' } },
  { collection: 'app.bsky.feed.post', rkey: '3kaaa', record: { $type: 'app.bsky.feed.post', text: 'hello', createdAt: '2026-01-01T00:00:00.000Z', langs: ['en'] } },
  { collection: 'app.bsky.feed.post', rkey: '3kbbb', record: { $type: 'app.bsky.feed.post', text: 'world', createdAt: '2026-01-02T00:00:00.000Z', langs: ['en'] } },
  { collection: 'app.bsky.graph.follow', rkey: '3kccc', record: { $type: 'app.bsky.graph.follow', subject: 'did:plc:other', createdAt: '2026-01-03T00:00:00.000Z' } }
]

async function fill (store) { for (const r of RECORDS) await store.put(r.collection, r.rkey, r.record); return store }
function tmp (t) { const d = mkdtempSync(join(tmpdir(), 'ors-')); t.teardown(() => rmSync(d, { recursive: true, force: true })); return d }

test('OverlayRepoStore derives byte-identical commit + MST + CAR as the Hyperbee RepoStore', async (t) => {
  const hb = await fill(await new RepoStore(tmp(t)).ready())
  const ov = await fill(await new OverlayRepoStore(tmp(t)).ready())

  const a = await getRepo(hb, META)
  const b = await getRepo(ov, META)

  t.is(b.commitCid.toString(), a.commitCid.toString(), 'commit CID identical')
  t.is(b.dataCid.toString(), a.dataCid.toString(), 'MST root (data CID) identical')
  t.ok(b4a.equals(b.carBytes, a.carBytes), 'CAR bytes byte-identical')

  await hb.close(); await ov.close()
})

test('records() order + getRaw bytes match Hyperbee exactly', async (t) => {
  const hb = await fill(await new RepoStore(tmp(t)).ready())
  const ov = await fill(await new OverlayRepoStore(tmp(t)).ready())

  const ra = await hb.records(); const rb = await ov.records()
  t.is(rb.length, ra.length, 'same record count')
  t.alike(rb.map((r) => r.key), ra.map((r) => r.key), 'same keys in same (byte) order')
  for (let i = 0; i < ra.length; i++) t.ok(b4a.equals(rb[i].bytes, ra[i].bytes), 'record bytes identical: ' + ra[i].key)

  const ga = await hb.getRaw('app.bsky.feed.post', '3kaaa')
  const gb = await ov.getRaw('app.bsky.feed.post', '3kaaa')
  t.ok(b4a.equals(gb.bytes, ga.bytes), 'getRaw bytes identical')
  t.alike(gb.record, ga.record, 'getRaw decoded record identical')

  await hb.close(); await ov.close()
})

test('delete removes the file and shifts the derived MST (O(current state), matches a fresh repo)', async (t) => {
  const ov = await fill(await new OverlayRepoStore(tmp(t)).ready())
  const before = await getRepo(ov, META)
  await ov.del('app.bsky.feed.post', '3kbbb')
  t.is(await ov.get('app.bsky.feed.post', '3kbbb'), null, 'record gone after delete')
  const after = await getRepo(ov, META)
  t.not(after.dataCid.toString(), before.dataCid.toString(), 'MST root changed after delete')

  // an equivalent FRESH repo (built without the deleted record) derives the SAME root — proof the
  // post-delete state is O(current), not "old record still lingering in an append-only log".
  const hb = await new RepoStore(tmp(t)).ready()
  for (const r of RECORDS) if (r.rkey !== '3kbbb') await hb.put(r.collection, r.rkey, r.record)
  const fresh = await getRepo(hb, META)
  t.is(after.dataCid.toString(), fresh.dataCid.toString(), 'post-delete MST root == equivalent fresh repo')

  await ov.close(); await hb.close()
})

test('head persists across reopen (rev restored, not re-minted) + records survive', async (t) => {
  const dir = tmp(t)
  const ov = await fill(await new OverlayRepoStore(dir).ready())
  await ov.saveHead({ rev: REV, commitCid: 'bafyCommit', dataCid: 'bafyData' })
  await ov.close()

  const re = await new OverlayRepoStore(dir).ready()
  const h = await re.loadHead()
  t.is(h.rev, REV, 'rev restored from head.json')
  t.is(h.commitCid, 'bafyCommit', 'commitCid restored')
  t.is((await re.records()).length, RECORDS.length, 'records survive reopen')
  await re.close()
})

test('update overwrites in place (one file, not an append) and re-derives correctly', async (t) => {
  const ov = await fill(await new OverlayRepoStore(tmp(t)).ready())
  await ov.put('app.bsky.feed.post', '3kaaa', { $type: 'app.bsky.feed.post', text: 'edited', createdAt: '2026-01-01T00:00:00.000Z', langs: ['en'] })
  const got = await ov.get('app.bsky.feed.post', '3kaaa')
  t.is(got.text, 'edited', 'record overwritten in place')
  t.is((await ov.records()).length, RECORDS.length, 'still exactly one file per record (no append)')
  await ov.close()
})

test('RepoManager.applyWrite drives OverlayRepoStore identically to Hyperbee (write path + firehose proofs)', async (t) => {
  const ov = await new OverlayRepoStore(tmp(t)).ready()
  const hb = await new RepoStore(tmp(t)).ready()
  const mo = await new RepoManager(ov, { did: DID, privateKey: KEY }).init()
  const mh = await new RepoManager(hb, { did: DID, privateKey: KEY }).init()

  // create x2 -> update -> delete: exercises the incremental MST-inversion covering proof on files.
  const ops = [
    { action: 'create', collection: 'app.bsky.feed.post', rkey: '3kaaa', record: { $type: 'app.bsky.feed.post', text: 'hello', createdAt: '2026-01-01T00:00:00.000Z' } },
    { action: 'create', collection: 'app.bsky.feed.post', rkey: '3kbbb', record: { $type: 'app.bsky.feed.post', text: 'world', createdAt: '2026-01-02T00:00:00.000Z' } },
    { action: 'update', collection: 'app.bsky.feed.post', rkey: '3kaaa', record: { $type: 'app.bsky.feed.post', text: 'edited', createdAt: '2026-01-01T00:00:00.000Z' } },
    { action: 'delete', collection: 'app.bsky.feed.post', rkey: '3kbbb' }
  ]
  for (const op of ops) {
    // applyWrite asserts its own covering-proof invariants internally (proof.dataCid==signed data,
    // proof.oldRoot==prevData) — so a non-throw here PROVES the firehose #commit proof is valid on files.
    const ro = await mo.applyWrite(op)
    const rh = await mh.applyWrite(op)
    t.ok(ro.newBlocks && ro.newBlocks.length > 0, `overlay #commit carries proof blocks (${op.action} ${op.rkey})`)
    t.is(ro.dataCid.toString(), rh.dataCid.toString(), `MST root matches Hyperbee after ${op.action} ${op.rkey}`)
  }

  t.is((await ov.loadHead()).rev, mo.rev, 'overlay head persisted (loadHead rev == manager rev)')

  // final derived repo byte-identical at a fixed rev — the write sequence left both stores in the same state
  const a = await getRepo(hb, META); const b = await getRepo(ov, META)
  t.is(b.commitCid.toString(), a.commitCid.toString(), 'final commit CID identical after write sequence')
  t.ok(b4a.equals(b.carBytes, a.carBytes), 'final CAR byte-identical')

  // O(current state): after create x2 + delete x1 the deleted record's file is GONE (not a tombstone)
  t.is((await ov.records()).length, 1, 'only current records remain on disk')

  await ov.close(); await hb.close()
})