OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-did-peer commits / 7a3ef09

0.2.14: an operator emit-sync re-announces even a head synced before
The relay dedupes frames by key and an automatic #sync is keyed (did, rev), so the operator's emit-sync for loser-club (2026-10-13) answered emitted:false: a #sync at 3mrfgnyiurk22 had been emitted on 2026-07-26, and the lever could never re-announce that head — the one case it exists for, while bsky's relay dropped every loser-club commit behind a newer July rev. _emitSync takes { force }; a forced key carries its time. The public emitSync (only the control verb calls it) forces; the automatic re-anchor path stays deduplicated. Test first: test/emit-sync.test.mjs red on the forced re-announce; npm test green (90 checks). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7a3ef09e7bcfc40839e6d8ec25f11fee9cc124c3
by plankatron <fleeky@gmail.com> · 2026-10-13T23:56:01.000Z

Changed files (3) +49 -7

lib/did-peer.js +12 -5
……@@ -1071,18 +1071,25 @@ export class DidPeerRouter {
10711071 })().catch(() => {})
10721072 }
10731073
1074 async _emitSync (did, front) {
1074 // `force`: the relay dedupes frames by key, and an automatic #sync is keyed by (did, rev) so a re-anchor
1075 // never re-emits the same head. An OPERATOR re-announce must not be deduplicated: on 2026-10-13 bsky's
1076 // relay held loser-club at a newer July rev and dropped every commit; the fix is one #sync at our head,
1077 // and the (did, rev) key — already used by a #sync on 2026-07-26 — made emit-sync a silent no-op. So a
1078 // forced emission's key carries its time: each operator request is its own announcement.
1079 async _emitSync (did, front, { force = false } = {}) {
10751080 if (!this.relay) return { did, emitted: false, reason: 'no relay' }
10761081 const signed = front.head && front.head.signed
10771082 if (!signed) return { did, emitted: false, reason: 'no commit' }
10781083 const time = new Date().toISOString()
10791084 const frameBytes = await syncFrame({ seq: 0, did, signedCommit: signed, time })
1080 const emitted = await this.relay.emit(`sync:${did}:${signed.rev}`, frameBytes)
1081 return { did, rev: signed.rev, emitted }
1085 const key = force ? `sync:${did}:${signed.rev}:${time}` : `sync:${did}:${signed.rev}`
1086 const emitted = await this.relay.emit(key, frameBytes)
1087 return { did, rev: signed.rev, emitted, forced: !!force }
10821088 }
10831089
1084 // Public control-plane trigger: force a #sync re-baseline for a fronted DID (from its freshest front).
1085 async emitSync (did) { const f = await this.front(did); return this._emitSync(did, f) }
1090 // Public control-plane trigger (the operator's `emit-sync`): FORCE a #sync re-baseline for a fronted DID
1091 // at its freshest front, even if that head was #synced before.
1092 async emitSync (did) { const f = await this.front(did); return this._emitSync(did, f, { force: true }) }
10861093
10871094 // Pull-only staleness ceiling + relay failover (owns-swarm/relay mode). NEVER destroys a connection —
10881095 // cores live-follow via the standing download; this just nudges a front that saw no 'append' for a window
package.json +2 -2
……@@ -1,6 +1,6 @@
11{
22 "name": "atproto-did-peer",
3 "version": "0.2.13",
3 "version": "0.2.14",
44 "description": "Keyless, direction-free P2P reader/seeder for an atproto DID's repo+firehose Hypercores: announce-push discovery + event-driven head reconciliation + a keyless read surface. The shared primitive beneath atproto-bridge, atproto-relay and favela (extracted from atproto-bridge did-peer.js).",
55 "type": "module",
66 "main": "index.js",
……@@ -8,7 +8,7 @@
88 ".": "./index.js"
99 },
1010 "scripts": {
11 "test": "node test/commitops.test.mjs && node test/router.test.mjs && node test/co-owned.test.mjs && node test/coowner-set.test.mjs && node test/evict.test.mjs && node test/fork.test.mjs && node test/rpc-candidates.test.mjs && node test/no-repo.test.mjs && node test/get-repo-since.test.mjs && node test/rpc-timeout.test.mjs",
11 "test": "node test/commitops.test.mjs && node test/router.test.mjs && node test/co-owned.test.mjs && node test/coowner-set.test.mjs && node test/evict.test.mjs && node test/fork.test.mjs && node test/rpc-candidates.test.mjs && node test/no-repo.test.mjs && node test/get-repo-since.test.mjs && node test/rpc-timeout.test.mjs && node test/emit-sync.test.mjs",
1212 "test:live": "node test/read-live.mjs"
1313 },
1414 "dependencies": {
test/emit-sync.test.mjs +35 -0
……@@ -0,0 +1,35 @@
1// emit-sync: an OPERATOR re-announce must reach the relay even for a rev that was #synced before.
2//
3// 2026-10-13: bsky's relay held loser-club at a July rev (3mrnruepxss22) newer than the head we serve
4// (3mrfgnyiurk22), so it dropped every commit. The fix is one #sync at our head — and `emit-sync` answered
5// emitted:false, because the relay dedupes frames by key `sync:<did>:<rev>` and a #sync for 3mrfgnyiurk22
6// had been emitted on 2026-07-26. The lever could never re-announce a head it had announced once, which is
7// precisely the case it exists for. Automatic emits stay deduplicated; an operator request is new each time.
8// Run: node test/emit-sync.test.mjs
9import { DidPeerRouter } from '../index.js'
10
11const assert = (c, m) => { if (!c) { console.error('FAIL:', m); process.exit(1) } console.log(' ok -', m) }
12
13// A relay that dedupes by key exactly as FleetRelay.emit does.
14function fakeRelay () {
15 const keys = new Set()
16 return { keys, async emit (key) { if (keys.has(key)) return false; keys.add(key); return true } }
17}
18const front = { head: { signed: { did: 'did:plc:lc', rev: '3mrfgnyiurk22', version: 3, sig: new Uint8Array(64) } } }
19
20const r = Object.create(DidPeerRouter.prototype)
21r.relay = fakeRelay()
22r.front = async () => front
23
24const auto1 = await r._emitSync('did:plc:lc', front)
25const auto2 = await r._emitSync('did:plc:lc', front)
26assert(auto1.emitted === true, 'the first automatic #sync for a head is emitted')
27assert(auto2.emitted === false, 'a second AUTOMATIC #sync for the same head is deduplicated (re-anchors do not spam the relay)')
28
29const op1 = await r.emitSync('did:plc:lc')
30assert(op1.emitted === true, '⛔ an OPERATOR emit-sync is emitted although that head was #synced before')
31assert(op1.rev === '3mrfgnyiurk22', 'at the served head')
32await new Promise((resolve) => setTimeout(resolve, 2))
33const op2 = await r.emitSync('did:plc:lc')
34assert(op2.emitted === true, 'and again on the next request — each operator request is its own announcement')
35console.log('emit-sync: all ok')