OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer commits / 4b90f9f

0.3.130: the sign tick says what it swallowed, and when it signs labels
loser-club's elected signer (stortron, holdsSigner true, fixed atproto-room) never re-signed its two ver-less member labels, and a bare catch {} around the tick made the cause invisible. Log the failing step + error once per distinct message, and log labels: signed. Observability only. 176/176. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4b90f9ff730d653354e82b210d0571d4fc03348b
by plankatron <fleeky@gmail.com> · 2026-10-14T16:13:09.000Z

Changed files (2) +20 -4

lib/device-node.js +19 -3
……@@ -478,17 +478,33 @@ export async function bootSwarmDevice ({ storage, deviceMnemonic, did, signingKe
478478
479479 let ticking = false
480480 let tickAgain = false
481 // ⛔ A SWALLOWED TICK IS INVISIBLE. 2026-10-14: loser-club's elected signer (stortron, holdsSigner true,
482 // running the fixed atproto-room) never re-signed its two ver-less member labels, and nothing anywhere said
483 // why — this catch ate whatever sign() or the label tick threw. Log it (once per distinct message, so an
484 // event storm cannot flood the log), and log when the label room signs, so the next restart is evidence.
485 let lastTickError = null
481486 const tick = async () => {
482487 if (ticking) { tickAgain = true; return } // coalesce bursts; re-run once if one arrived mid-flight
483488 ticking = true
489 let step = 'admit'
484490 try {
485491 if (sb.base && !sb.base.writable) { try { await sb.ensureAdmitted() } catch {} }
486492 reconcile() // deliberately NOT awaited — byte convergence must not gate signing (or vice versa)
493 step = 'sign'
487494 await device.sign()
488 if (labelRoom) await labelRoom.tick()
495 if (labelRoom) {
496 step = 'labels'
497 const signed = await labelRoom.tick()
498 if (signed > 0) console.log(JSON.stringify({ msg: 'labels: signed', did: device.did, count: signed }))
499 }
500 step = 'project'
489501 if (membraneServing) { await membraneServing.sync(); await membraneServing.syncLabels() }
490 } catch {}
491 finally { ticking = false; if (tickAgain) { tickAgain = false; tick() } }
502 lastTickError = null
503 } catch (err) {
504 const m = step + ': ' + ((err && err.message) || String(err))
505 if (m !== lastTickError) console.error(JSON.stringify({ msg: 'tick failed', did: device.did, step, error: (err && err.message) || String(err) }))
506 lastTickError = m
507 } finally { ticking = false; if (tickAgain) { tickAgain = false; tick() } }
492508 }
493509 let unwatch = null
494510 if (signIntervalMs > 0) { // >0 = enable the (now event-driven) sign loop; 0 = disabled (tests drive sign() manually)
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "hyper-proto-peer",
3 "version": "0.3.129",
3 "version": "0.3.130",
44 "description": "Self-custody, P2P-native atproto peer \u2014 holds the user's key + content as Hypercores and authors+signs its own repo. The source of truth in the peer/bridge split (Model B); atproto-bridge projects it to bsky.",
55 "type": "module",
66 "main": "lib/peer.js",