| … | … | @@ -1,6 +1,6 @@ |
| 1 | 1 | { |
| 2 | 2 | "name": "atproto-bridge", |
| 3 | "version": "0.9.40", | |
| 3 | "version": "0.9.41", | |
| 4 | 4 | "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.", |
| 5 | 5 | "type": "module", |
| 6 | 6 | "main": "index.js", |
| … | … | @@ -27,9 +27,23 @@ |
| 27 | 27 | // emitted — our current emitted seq (relay.length = seqBase + internal) |
| 28 | 28 | // cursor — the relay's stored cursor for our host (getHostStatus.seq) |
| 29 | 29 | // |
| 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. | |
| 33 | 47 | // |
| 34 | 48 | // Deliberately NOT keyed on status === 'offline'. A relay can report active while still holding a cursor |
| 35 | 49 | // 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 } = {}) { |
| 39 | 53 | const c = Number(cursor) |
| 40 | 54 | if (!Number.isFinite(e) || !Number.isFinite(c)) return { lift: false, reason: 'unknown-seq' } |
| 41 | 55 | 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' } | |
| 43 | 57 | return { lift: true, to: c + Math.max(1, Number(margin) || 1), reason: 'behind-relay-cursor', emitted: e, cursor: c } |
| 44 | 58 | } |
| 45 | 59 |
| … | … | @@ -15,8 +15,35 @@ test('decideLift: the real outage numbers', (t) => { |
| 15 | 15 | |
| 16 | 16 | test('decideLift: no lift when we are ahead — the healthy steady state', (t) => { |
| 17 | 17 | 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. | |
| 24 | test('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. | |
| 35 | test('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. | |
| 43 | test('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) | |
| 20 | 47 | }) |
| 21 | 48 | |
| 22 | 49 | test('decideLift: refuses to act on nonsense rather than guessing', (t) => { |