OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-room / test / label-room-presence.test.mjs

135 lines · javascript ref:
// LabelRoom on hpp's PRESENCE election (not its own Lease), with a CONTENT-keyed signed log.
//
// hyper-social #80 (member labels): hpp elects its signer by presence (SignerPresence) and retired the
// append-forever __lease__ heartbeat; LabelRoom's own Lease would be a second election that can disagree.
// And the signed log was keyed by index (pad(n)): two signers during a partition both wrote
// __label__\x00<0> with DIFFERENT labels, last-write-wins kept one, and a label was silently lost.
// Run: node test/label-room-presence.test.mjs
import { mkdtempSync, rmSync } from 'node:fs'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import Corestore from 'corestore'
import { keyFromPrivate } from 'atproto-identity/lib/atproto-identity.js'
import { verifyLabel, decodeLabel } from 'atproto-identity/lib/labels.js'
import { LabelRoom } from '../lib/label-room.js'

const assert = (c, m) => { if (!c) { console.error('FAIL:', m); process.exit(1) } console.log('  ok -', m) }
function mockSb (m = new Map()) {
  return {
    map: m,
    async set (k, v) { m.set(k, v) },
    async del (k) { m.delete(k) },
    async get (k) { return m.has(k) ? m.get(k) : null },
    async list (prefix) { const o = {}; for (const [k, v] of m) if (k.startsWith(prefix)) o[k] = v; return o }
  }
}
const labeler = keyFromPrivate(new Uint8Array(32).fill(44))
const SRC = 'did:plc:wqnwulql7ndcz6xmtvaovl6u'
const KP = { src: SRC, privateKey: labeler.privateKey }
const WJ = 'did:plc:wj62ebbusln6gxo5azo6ogzo'
const E2 = 'did:plc:e2jevhuurrhlm36ufk7fklpg'

// 1. presence-gated: only the holder signs; no lease is ever written
{
  const sb = mockSb()
  const holder = new LabelRoom(sb, { ...KP, holds: () => true })
  const other = new LabelRoom(sb, { ...KP, holds: () => false })
  await holder.label(WJ, 'loser-club-member', { cts: '2026-10-14T00:00:00.000Z' })
  assert(await other.tick() === 0, 'a non-holder signs nothing')
  assert(await holder.tick() === 1, 'the holder signs the intent')
  assert(![...sb.map.keys()].some((k) => k.startsWith('__lease__')), 'no __lease__ heartbeat is written in presence mode')
  const log = await holder.signedLog()
  assert(log.length === 1 && log[0].uri === WJ && verifyLabel(log[0], labeler.didKey), 'a DID-subject label, signed under the labeler key')
}

// 2. partition: two holders sign different labels into SEPARATE views; after the merge both survive
{
  const a = mockSb(); const b = mockSb()
  const ra = new LabelRoom(a, { ...KP, holds: () => true })
  const rb = new LabelRoom(b, { ...KP, holds: () => true })
  await ra.label(WJ, 'loser-club-member', { cts: '2026-10-14T00:00:00.000Z' })
  await rb.label(E2, 'loser-club-member', { cts: '2026-10-14T00:00:01.000Z' })
  await ra.tick(); await rb.tick()
  const merged = mockSb(new Map([...a.map, ...b.map])) // LWW merge, as the autobase view would converge
  const m = new LabelRoom(merged, { ...KP, holds: () => true })
  const log = await m.signedLog()
  assert(log.length === 2, 'both labels survive the merge (index keys collided on __label__\\x00<0> and lost one)')
  assert(new Set(log.map((l) => l.uri)).size === 2, 'one per member')
  assert(await m.tick() === 0, 'and nothing is re-signed after the merge')
}

// 3. projection: labels the core does not hold are appended, even if they sort before ones it has
{
  const sb = mockSb()
  const r = new LabelRoom(sb, { ...KP, holds: () => true })
  await r.label(E2, 'loser-club-member', { cts: '2026-10-14T00:00:05.000Z' })
  await r.tick()
  const dir = mkdtempSync(join(tmpdir(), 'lrp-'))
  const store = new Corestore(dir)
  const feed = store.get({ name: 'labels', valueEncoding: 'binary' })
  assert(await r.projectTo(feed) === 1, 'first projection appends the one label')
  await r.label(WJ, 'loser-club-member', { cts: '2026-10-14T00:00:01.000Z' }) // sorts EARLIER by cts
  await r.tick()
  assert(await r.projectTo(feed) === 1, 'a label sorting earlier is still appended (index projection skipped it)')
  assert(await r.projectTo(feed) === 0, 'idempotent')
  const uris = []; for (let i = 0; i < feed.length; i++) uris.push(decodeLabel(await feed.get(i)).uri)
  assert(uris.length === 2 && uris.includes(WJ) && uris.includes(E2), 'the feed holds both, each once')
  await feed.close(); try { await store.close() } catch {}; rmSync(dir, { recursive: true, force: true })
}
// ⛔ ON A REPO'S OWN STATEBASE, intents must not read as records. hpp hosts the labeler on the DID's
// StateBase, where RepoBase lists every key with a "/" and a non-"__" collection as a record — and an
// intent on a post URI ("label\x00at://did/app.bsky.feed.post/rkey\x00spam") has both. It would be signed
// into the repo as a record of collection "label\x00at:". `ns` moves intents under a reserved name.
{
  const { RepoBase } = await import('../lib/repo-base.js')
  const POST = 'at://' + WJ + '/app.bsky.feed.post/3mrhxnkbhv622'
  const shared = mockSb()
  const r = new LabelRoom(shared, { ...KP, holds: () => true, ns: '__labelintent__' })
  await r.ensure(POST, 'spam')
  await r.ensure(WJ, 'loser-club-member')
  await r.tick()
  const recs = await new RepoBase(shared, { did: SRC }).listRecords()
  assert(recs.length === 0, 'no label intent or signed label lists as a repo record (got ' + JSON.stringify(recs.map((x) => x.collection)) + ')')
  assert((await r.base.intents()).length === 2, 'the intents are still there, under the reserved name')
  assert((await r.signedLog()).length === 2, 'and both were signed')
}
// ⛔ A SIGNED LABEL WITHOUT `ver` IS NOT EMITTED. The label spec requires ver: 1 on every label that moves
// between services, and signs over it. Before atproto-identity 0.0.5 buildLabel omitted it, and loser-club's two
// member labels sit in the shared log in that shape — bsky's AppView never showed them. The tick must treat such
// an entry as not yet signed and re-sign it, under the same content key, so the log converges on valid labels.
{
  const { signLabel, encodeLabel } = await import('atproto-identity/lib/labels.js')
  const cts = '2026-10-14T15:09:59.328Z'
  const sb = mockSb()
  const r = new LabelRoom(sb, { ...KP, holds: () => true })
  await r.label(WJ, 'loser-club-member', { cts })
  const legacy = signLabel({ src: SRC, uri: WJ, val: 'loser-club-member', cts }, labeler.privateKey) // no ver
  const key = '__label__\x00' + cts + '\x00' + WJ + '\x00loser-club-member\x000'
  await sb.set(key, Buffer.from(encodeLabel(legacy)).toString('hex'))
  assert(await r.tick() === 1, 'a log entry without ver is re-signed')
  const log = await r.signedLog()
  assert(log.length === 1, 'under the SAME content key — the log holds one label, not two')
  assert(log[0].ver === 1 && verifyLabel(log[0], labeler.didKey), 'and it now carries ver: 1 and verifies')
  assert(await r.tick() === 0, 'a second tick re-signs nothing')
}
// ⛔ THE PROJECTION MUST BE OBSERVABLE. 2026-10-14: the re-signed (ver:1) member labels were in both co-owners'
// signed logs, yet the gateway still served the old ones, and nothing could say whether projectTo had run since
// boot or how long the served label core was. projectTo records its last run.
{
  const sb = mockSb()
  const r = new LabelRoom(sb, { ...KP, holds: () => true })
  assert(r.lastProjection === null, 'no projection before the first projectTo')
  await r.label(E2, 'loser-club-member', { cts: '2026-10-14T00:00:09.000Z' })
  await r.tick()
  const dir = mkdtempSync(join(tmpdir(), 'lrp2-'))
  const store = new Corestore(dir)
  const feed = store.get({ name: 'labels', valueEncoding: 'binary' })
  await r.projectTo(feed)
  const p = r.lastProjection
  assert(p && p.appended === 1 && p.coreLength === 1 && p.logLength === 1 && typeof p.at === 'number', 'lastProjection records appended / coreLength / logLength / at')
  await r.projectTo(feed)
  assert(r.lastProjection.appended === 0 && r.lastProjection.coreLength === 1, 'an idempotent run is recorded too')
  await feed.close(); try { await store.close() } catch {}; rmSync(dir, { recursive: true, force: true })
}
console.log('\nLABEL-ROOM PRESENCE OK')