// 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')