OverviewFilesCommitsIssuesDocsReleasesPeers

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

87 lines · javascript ref:
// SignerPresence (S1) — leak-free single-signer election from connection presence. Pure logic + injectable
// clock, so this runs anywhere (node/bare) with no swarm. Proves: lowest-key election, grace blip-tolerance,
// cascade failover, self-election, and — structurally — that it can never write to the append-only log.
// Run: `node test/signer-presence.test.mjs`
import { SignerPresence } from '../lib/signer-presence.js'

const assert = (c, m) => { if (!c) throw new Error('FAIL: ' + m); console.log('  ok -', m) }
let NOW = 1000
const clock = () => NOW
const A = 'aaaa', B = 'bbbb', C = 'cccc'

// 1. lowest-key co-owner is the signer
{
  NOW = 1000
  const sp = new SignerPresence({ self: B, graceMs: 15000, clock })
  sp.markPresent(A)
  assert(sp.currentSigner() === A, 'lowest-key co-owner (A) is elected signer')
  assert(sp.holds() === false, 'B (higher key) does not hold while A is present')
}

// 2 & 3. holder departs → grace keeps it → after grace, failover
{
  NOW = 1000
  const sp = new SignerPresence({ self: B, graceMs: 15000, clock })
  sp.markPresent(A)
  NOW = 5000; sp.markAbsent(A)
  NOW = 5000 + 14999
  assert(sp.currentSigner() === A, 'within grace, departed holder A stays elected (no premature failover)')
  assert(sp.holds() === false, 'B still does not hold within grace')
  NOW = 5000 + 15001
  assert(sp.currentSigner() === B, 'after grace elapses, failover to B')
  assert(sp.holds() === true, 'B now holds')
}

// 4. blip (depart + return within grace) does NOT thrash the signer
{
  NOW = 1000
  const sp = new SignerPresence({ self: B, graceMs: 15000, clock })
  sp.markPresent(A)
  NOW = 5000; sp.markAbsent(A)
  NOW = 12000; sp.markPresent(A) // returned within grace
  NOW = 5000 + 20000 // well past the original grace window
  assert(sp.currentSigner() === A, 'a blip (return within grace) does NOT fail the signer over')
  assert(sp.holds() === false, 'B never took over on the blip')
}

// 5. self is lowest → self holds
{
  NOW = 1000
  const sp = new SignerPresence({ self: A, graceMs: 15000, clock })
  sp.markPresent(B)
  assert(sp.holds() === true, 'self=A (lowest) holds')
}

// 6. all lower co-owners gone + grace → self holds
{
  NOW = 1000
  const sp = new SignerPresence({ self: B, graceMs: 15000, clock })
  sp.markPresent(A)
  NOW = 2000; sp.markAbsent(A)
  NOW = 2000 + 15001
  assert(sp.holds() === true, 'after the only lower co-owner departs+grace, self holds')
  assert(sp.currentSigner() === B, 'self is the sole effective signer')
}

// 7. three co-owners: cascade failover A→B→C
{
  NOW = 1000
  const sp = new SignerPresence({ self: C, graceMs: 10000, clock })
  sp.markPresent(A); sp.markPresent(B)
  assert(sp.currentSigner() === A, 'A (lowest of three) signs')
  NOW = 2000; sp.markAbsent(A); NOW = 2000 + 10001
  assert(sp.currentSigner() === B, 'A gone+grace → B signs')
  assert(sp.holds() === false, 'C still not holding while B present')
  NOW = 30000; sp.markAbsent(B); NOW = 30000 + 10001
  assert(sp.holds() === true, 'B gone+grace → C (self) holds')
}

// 8. structurally leak-free: no statebase, no append path
{
  const sp = new SignerPresence({ self: A })
  assert(sp.sb === undefined && typeof sp.set !== 'function' && typeof sp.append !== 'function',
    'SignerPresence has NO statebase/append path — zero log writes by construction')
}

console.log('\nSIGNER-PRESENCE OK: lowest-key election, grace blip-tolerance, cascade failover, zero log writes')