OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-bridge commits / 5b8e6df

0.9.41: seq-guard lifted on CAUGHT-UP, not wedged — off-by-one runaway
decideLift lifted on `emitted <= cursor`. The `=` was deliberate and wrong, and the wrong reasoning was written into the test: "the relay asks for seq > cursor, so emitted === cursor can never advance it." That reads `emitted` as the NEXT seq. It is the LAST one — FleetRelay.length is `seqBase + seq.length`, documented in fleet-relay.js as "the latest EMITTED seq". At equality our next frame is `cursor + 1`, which the relay does request. Equality is the healthy fully-caught-up state, the terminal state of a working firehose. It was not a harmless extra lift. setSeqBase(cursor + 1) adds the whole internal length to emitted, so FleetRelay.subscribe's `cursor > seqBase ? cursor - seqBase : 0` clamps to 0 and the relay re-ingests every frame renumbered. Its cursor then climbs to the new emitted, and the guard fires again — self-sustaining. Live evidence, stortron, ONE 4-day process (uptime 4d10h): four lifts, every one with ourEmitted EXACTLY equal to relayCursor, never below. seqBase ladder 9855 -> 14714 -> 19576 -> 24439 -> 29303, each step ~4860 = the aggregate's internal length. relayCursor 14713 / ourEmitted 14713 -> 14714, emitted 19572 relayCursor 19575 / ourEmitted 19575 -> 19576, emitted 24437 relayCursor 24438 / ourEmitted 24438 -> 24439, emitted 29301 relayCursor 29302 / ourEmitted 29302 -> 29303, emitted 34166 Those same four lifts also settle hyper-social #25 root cause 3 ("the guard's interval may not fire under Bare"): three of them are interval passes in a single process, so the interval fires. Confirmed separately with an unref'd setInterval probe under bare 1.26.0 — 10/10 firings, including an async callback, with the loop held open. The wedge condition is strictly `emitted < cursor`. Reason string is now `at-or-ahead-of-cursor` (no other consumer). 64/64 tests, 241/241 asserts. NOT published or deployed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5b8e6df510050b4f40a5a2299d32cd3ae21ee889
by plankatron <fleeky@gmail.com> · 2026-08-05T13:56:10.000Z

Changed files (3) +48 -7

package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "atproto-bridge",
3 "version": "0.9.40",
3 "version": "0.9.41",
44 "description": "Stateless keyless atproto MEMBRANE \u2014 fronts self-custody hyper-proto-peers to bluesky over HTTP/WS, holds no keys and never signs. Bare-runnable. Deploy root / flat closure over the identity+repo+store+pds packages.",
55 "type": "module",
66 "main": "index.js",
pds/lib/seq-guard.js +18 -4
……@@ -27,9 +27,23 @@
2727// emitted — our current emitted seq (relay.length = seqBase + internal)
2828// cursor — the relay's stored cursor for our host (getHostStatus.seq)
2929//
30// Lift when `emitted <= cursor`: the relay will only ever ask for frames after `cursor`, and we cannot
31// produce a seq that high, so it is wedged by arithmetic regardless of what we sign. Lifting to
32// `cursor + margin` makes our next emitted frame land strictly above its cursor.
30// Lift when `emitted < cursor`: the relay will only ever ask for frames after `cursor`, and our next
31// frame can only be `emitted + 1`, so if that still lands at or below `cursor` we are wedged by
32// arithmetic regardless of what we sign. Lifting to `cursor + margin` makes our next emitted frame land
33// strictly above its cursor.
34//
35// ⛔ EQUALITY IS NOT WEDGED — corrected 2026-08-05 from live evidence. This originally lifted on
36// `emitted <= cursor`, justified as "the relay asks for seq > cursor, so emitted === cursor can never
37// advance it". That reads `emitted` as the NEXT seq; it is the LAST one (FleetRelay.length = seqBase +
38// internal). At equality our next frame is `cursor + 1`, which the relay does request — equality is the
39// healthy FULLY-CAUGHT-UP state, the terminal state of a working firehose.
40//
41// The cost of the off-by-one was a self-sustaining loop, not a no-op. setSeqBase(cursor + 1) adds the
42// whole internal length to emitted, so FleetRelay.subscribe's `cursor - seqBase` goes negative and clamps
43// to 0 — the relay re-ingests every frame renumbered, its cursor climbs to the new emitted, and the guard
44// fires again. Measured on stortron over one 4-day process: four lifts, all with ourEmitted EXACTLY equal
45// to relayCursor, never below; seqBase ladder 9855 -> 14714 -> 19576 -> 24439 -> 29303, each step ~4860 =
46// the aggregate's internal length. See hyper-social org issue #25.
3347//
3448// Deliberately NOT keyed on status === 'offline'. A relay can report active while still holding a cursor
3549// we can never reach (it reconnects, asks for >cursor, gets nothing, idles). The arithmetic is the real
……@@ -39,7 +53,7 @@ export function decideLift ({ emitted, cursor, margin = 1 } = {}) {
3953 const c = Number(cursor)
4054 if (!Number.isFinite(e) || !Number.isFinite(c)) return { lift: false, reason: 'unknown-seq' }
4155 if (c <= 0) return { lift: false, reason: 'relay-has-no-cursor' }
42 if (e > c) return { lift: false, reason: 'ahead-of-cursor' }
56 if (e >= c) return { lift: false, reason: 'at-or-ahead-of-cursor' }
4357 return { lift: true, to: c + Math.max(1, Number(margin) || 1), reason: 'behind-relay-cursor', emitted: e, cursor: c }
4458}
4559
pds/test/seq-guard.test.js +29 -2
……@@ -15,8 +15,35 @@ test('decideLift: the real outage numbers', (t) => {
1515
1616test('decideLift: no lift when we are ahead — the healthy steady state', (t) => {
1717 t.absent(decideLift({ emitted: 9900, cursor: 9834 }).lift, 'ahead of the cursor → nothing to do')
18 // Equality is NOT safe: the relay asks for seq > cursor, so emitted === cursor can never advance it.
19 t.ok(decideLift({ emitted: 9834, cursor: 9834 }).lift, 'equal is still wedged — the relay asks for > cursor')
18})
19
20// REGRESSION (2026-08-05). This asserted the OPPOSITE — "equal is still wedged, the relay asks for
21// > cursor" — which reads `emitted` as the NEXT seq. It is the LAST one (FleetRelay.length = seqBase +
22// internal), so at equality our next frame is cursor + 1 and the relay does request it. Equality is the
23// healthy fully-caught-up state.
24test('decideLift: equality is CAUGHT UP, not wedged', (t) => {
25 const d = decideLift({ emitted: 9834, cursor: 9834 })
26 t.absent(d.lift, 'emitted === cursor → the relay has read everything we emitted; our next frame is cursor + 1')
27 t.is(d.reason, 'at-or-ahead-of-cursor')
28})
29
30// The off-by-one was not a harmless extra lift: it was a self-sustaining loop. Lifting to cursor + 1 adds
31// the aggregate's whole internal length to emitted, so FleetRelay.subscribe's `cursor - seqBase` clamps to
32// 0 and the relay re-ingests every frame renumbered; its cursor then climbs to the new emitted and the
33// guard fires again. These are the four live lifts observed on stortron in one 4-day process — every one
34// of them at exact equality, never below. See hyper-social org issue #25.
35test('decideLift: the observed runaway ladder no longer lifts', (t) => {
36 for (const [emitted, cursor] of [[14713, 14713], [19575, 19575], [24438, 24438], [29302, 29302]]) {
37 t.absent(decideLift({ emitted, cursor }).lift, `emitted ${emitted} === cursor ${cursor} → caught up, no lift`)
38 }
39})
40
41// The wedge is strictly emitted < cursor — including one short, which is the tightest real case: our next
42// frame would be exactly `cursor`, and the relay only ever asks for > cursor.
43test('decideLift: one short of the cursor is still wedged', (t) => {
44 const d = decideLift({ emitted: 9833, cursor: 9834 })
45 t.ok(d.lift, 'next frame would be 9834, which the relay never asks for')
46 t.is(d.to, 9835)
2047})
2148
2249test('decideLift: refuses to act on nonsense rather than guessing', (t) => {