@optimystic/db-p2p 0.24.2 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/{readme.md → README.md} +688 -668
  2. package/dist/src/cluster/block-transfer-service.d.ts +133 -10
  3. package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
  4. package/dist/src/cluster/block-transfer-service.js +155 -9
  5. package/dist/src/cluster/block-transfer-service.js.map +1 -1
  6. package/dist/src/cluster/block-transfer.d.ts +67 -7
  7. package/dist/src/cluster/block-transfer.d.ts.map +1 -1
  8. package/dist/src/cluster/block-transfer.js +127 -24
  9. package/dist/src/cluster/block-transfer.js.map +1 -1
  10. package/dist/src/cluster/certified-claims.d.ts +170 -0
  11. package/dist/src/cluster/certified-claims.d.ts.map +1 -0
  12. package/dist/src/cluster/certified-claims.js +200 -0
  13. package/dist/src/cluster/certified-claims.js.map +1 -0
  14. package/dist/src/cluster/client-signature-verifier.d.ts +23 -0
  15. package/dist/src/cluster/client-signature-verifier.d.ts.map +1 -0
  16. package/dist/src/cluster/client-signature-verifier.js +33 -0
  17. package/dist/src/cluster/client-signature-verifier.js.map +1 -0
  18. package/dist/src/cluster/cluster-policy.d.ts +9 -3
  19. package/dist/src/cluster/cluster-policy.d.ts.map +1 -1
  20. package/dist/src/cluster/cluster-policy.js +111 -27
  21. package/dist/src/cluster/cluster-policy.js.map +1 -1
  22. package/dist/src/cluster/cluster-repo.d.ts +140 -11
  23. package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
  24. package/dist/src/cluster/cluster-repo.js +485 -29
  25. package/dist/src/cluster/cluster-repo.js.map +1 -1
  26. package/dist/src/cluster/commit-proof.d.ts +134 -0
  27. package/dist/src/cluster/commit-proof.d.ts.map +1 -0
  28. package/dist/src/cluster/commit-proof.js +263 -0
  29. package/dist/src/cluster/commit-proof.js.map +1 -0
  30. package/dist/src/cluster/quorum-restore.d.ts +95 -8
  31. package/dist/src/cluster/quorum-restore.d.ts.map +1 -1
  32. package/dist/src/cluster/quorum-restore.js +113 -14
  33. package/dist/src/cluster/quorum-restore.js.map +1 -1
  34. package/dist/src/cluster/rebalance-monitor.d.ts +84 -0
  35. package/dist/src/cluster/rebalance-monitor.d.ts.map +1 -1
  36. package/dist/src/cluster/rebalance-monitor.js +207 -5
  37. package/dist/src/cluster/rebalance-monitor.js.map +1 -1
  38. package/dist/src/cluster/reconcile-block.d.ts +27 -7
  39. package/dist/src/cluster/reconcile-block.d.ts.map +1 -1
  40. package/dist/src/cluster/reconcile-block.js +179 -38
  41. package/dist/src/cluster/reconcile-block.js.map +1 -1
  42. package/dist/src/cluster/service.d.ts +13 -4
  43. package/dist/src/cluster/service.d.ts.map +1 -1
  44. package/dist/src/cluster/service.js +17 -18
  45. package/dist/src/cluster/service.js.map +1 -1
  46. package/dist/src/cluster/spread-on-churn.d.ts +8 -2
  47. package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
  48. package/dist/src/cluster/spread-on-churn.js +7 -7
  49. package/dist/src/cluster/spread-on-churn.js.map +1 -1
  50. package/dist/src/cohort-topic/host.d.ts.map +1 -1
  51. package/dist/src/cohort-topic/host.js +8 -7
  52. package/dist/src/cohort-topic/host.js.map +1 -1
  53. package/dist/src/cohort-topic/stream-util.d.ts +7 -6
  54. package/dist/src/cohort-topic/stream-util.d.ts.map +1 -1
  55. package/dist/src/cohort-topic/stream-util.js +14 -41
  56. package/dist/src/cohort-topic/stream-util.js.map +1 -1
  57. package/dist/src/dispute/cascade.d.ts +7 -8
  58. package/dist/src/dispute/cascade.d.ts.map +1 -1
  59. package/dist/src/dispute/cascade.js +24 -7
  60. package/dist/src/dispute/cascade.js.map +1 -1
  61. package/dist/src/dispute/dispute-service.d.ts +5 -0
  62. package/dist/src/dispute/dispute-service.d.ts.map +1 -1
  63. package/dist/src/dispute/dispute-service.js +13 -3
  64. package/dist/src/dispute/dispute-service.js.map +1 -1
  65. package/dist/src/dispute/invalidation.d.ts +33 -15
  66. package/dist/src/dispute/invalidation.d.ts.map +1 -1
  67. package/dist/src/dispute/invalidation.js +127 -34
  68. package/dist/src/dispute/invalidation.js.map +1 -1
  69. package/dist/src/dispute/service.d.ts.map +1 -1
  70. package/dist/src/dispute/service.js +2 -1
  71. package/dist/src/dispute/service.js.map +1 -1
  72. package/dist/src/index.d.ts +7 -0
  73. package/dist/src/index.d.ts.map +1 -1
  74. package/dist/src/index.js +7 -0
  75. package/dist/src/index.js.map +1 -1
  76. package/dist/src/libp2p-key-network.d.ts +14 -10
  77. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  78. package/dist/src/libp2p-key-network.js +28 -58
  79. package/dist/src/libp2p-key-network.js.map +1 -1
  80. package/dist/src/libp2p-node-base.d.ts +38 -7
  81. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  82. package/dist/src/libp2p-node-base.js +148 -63
  83. package/dist/src/libp2p-node-base.js.map +1 -1
  84. package/dist/src/network/open-protocol-stream.d.ts +56 -0
  85. package/dist/src/network/open-protocol-stream.d.ts.map +1 -0
  86. package/dist/src/network/open-protocol-stream.js +60 -0
  87. package/dist/src/network/open-protocol-stream.js.map +1 -0
  88. package/dist/src/network/register-protocol-handler.d.ts +66 -0
  89. package/dist/src/network/register-protocol-handler.d.ts.map +1 -0
  90. package/dist/src/network/register-protocol-handler.js +51 -0
  91. package/dist/src/network/register-protocol-handler.js.map +1 -0
  92. package/dist/src/peer-address-book.d.ts +60 -2
  93. package/dist/src/peer-address-book.d.ts.map +1 -1
  94. package/dist/src/peer-address-book.js +89 -1
  95. package/dist/src/peer-address-book.js.map +1 -1
  96. package/dist/src/pend-validation.d.ts +65 -0
  97. package/dist/src/pend-validation.d.ts.map +1 -0
  98. package/dist/src/pend-validation.js +69 -0
  99. package/dist/src/pend-validation.js.map +1 -0
  100. package/dist/src/reactivity/notify-transport.d.ts.map +1 -1
  101. package/dist/src/reactivity/notify-transport.js +2 -1
  102. package/dist/src/reactivity/notify-transport.js.map +1 -1
  103. package/dist/src/reactivity/push-state-gossip.d.ts.map +1 -1
  104. package/dist/src/reactivity/push-state-gossip.js +2 -1
  105. package/dist/src/reactivity/push-state-gossip.js.map +1 -1
  106. package/dist/src/repo/cluster-coordinator.d.ts +32 -6
  107. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
  108. package/dist/src/repo/cluster-coordinator.js +44 -10
  109. package/dist/src/repo/cluster-coordinator.js.map +1 -1
  110. package/dist/src/repo/coordinator-repo.d.ts +181 -25
  111. package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
  112. package/dist/src/repo/coordinator-repo.js +650 -62
  113. package/dist/src/repo/coordinator-repo.js.map +1 -1
  114. package/dist/src/repo/served-repo-proxy.d.ts +30 -0
  115. package/dist/src/repo/served-repo-proxy.d.ts.map +1 -0
  116. package/dist/src/repo/served-repo-proxy.js +50 -0
  117. package/dist/src/repo/served-repo-proxy.js.map +1 -0
  118. package/dist/src/repo/service.d.ts +16 -1
  119. package/dist/src/repo/service.d.ts.map +1 -1
  120. package/dist/src/repo/service.js +18 -16
  121. package/dist/src/repo/service.js.map +1 -1
  122. package/dist/src/reputation/types.d.ts +3 -1
  123. package/dist/src/reputation/types.d.ts.map +1 -1
  124. package/dist/src/reputation/types.js +3 -1
  125. package/dist/src/reputation/types.js.map +1 -1
  126. package/dist/src/rn.d.ts +24 -2
  127. package/dist/src/rn.d.ts.map +1 -1
  128. package/dist/src/rn.js +33 -4
  129. package/dist/src/rn.js.map +1 -1
  130. package/dist/src/storage/block-archive.d.ts +153 -0
  131. package/dist/src/storage/block-archive.d.ts.map +1 -0
  132. package/dist/src/storage/block-archive.js +194 -0
  133. package/dist/src/storage/block-archive.js.map +1 -0
  134. package/dist/src/storage/block-latch.d.ts +92 -0
  135. package/dist/src/storage/block-latch.d.ts.map +1 -0
  136. package/dist/src/storage/block-latch.js +132 -0
  137. package/dist/src/storage/block-latch.js.map +1 -0
  138. package/dist/src/storage/block-storage.d.ts +169 -12
  139. package/dist/src/storage/block-storage.d.ts.map +1 -1
  140. package/dist/src/storage/block-storage.js +415 -152
  141. package/dist/src/storage/block-storage.js.map +1 -1
  142. package/dist/src/storage/cached-raw-storage.d.ts +5 -1
  143. package/dist/src/storage/cached-raw-storage.d.ts.map +1 -1
  144. package/dist/src/storage/cached-raw-storage.js +16 -1
  145. package/dist/src/storage/cached-raw-storage.js.map +1 -1
  146. package/dist/src/storage/cached-store-driver.d.ts +14 -4
  147. package/dist/src/storage/cached-store-driver.d.ts.map +1 -1
  148. package/dist/src/storage/cached-store-driver.js +39 -5
  149. package/dist/src/storage/cached-store-driver.js.map +1 -1
  150. package/dist/src/storage/i-block-storage.d.ts +70 -19
  151. package/dist/src/storage/i-block-storage.d.ts.map +1 -1
  152. package/dist/src/storage/i-block-storage.js +21 -1
  153. package/dist/src/storage/i-block-storage.js.map +1 -1
  154. package/dist/src/storage/i-raw-storage.d.ts +38 -0
  155. package/dist/src/storage/i-raw-storage.d.ts.map +1 -1
  156. package/dist/src/storage/kv-raw-storage.d.ts +14 -8
  157. package/dist/src/storage/kv-raw-storage.d.ts.map +1 -1
  158. package/dist/src/storage/kv-raw-storage.js +29 -9
  159. package/dist/src/storage/kv-raw-storage.js.map +1 -1
  160. package/dist/src/storage/memory-store-driver.d.ts +4 -1
  161. package/dist/src/storage/memory-store-driver.d.ts.map +1 -1
  162. package/dist/src/storage/memory-store-driver.js +22 -2
  163. package/dist/src/storage/memory-store-driver.js.map +1 -1
  164. package/dist/src/storage/raw-store-codec.js +2 -2
  165. package/dist/src/storage/raw-store-driver.d.ts +44 -3
  166. package/dist/src/storage/raw-store-driver.d.ts.map +1 -1
  167. package/dist/src/storage/shared-cache-pool.d.ts +60 -3
  168. package/dist/src/storage/shared-cache-pool.d.ts.map +1 -1
  169. package/dist/src/storage/shared-cache-pool.js +68 -4
  170. package/dist/src/storage/shared-cache-pool.js.map +1 -1
  171. package/dist/src/storage/storage-repo.d.ts +204 -26
  172. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  173. package/dist/src/storage/storage-repo.js +422 -119
  174. package/dist/src/storage/storage-repo.js.map +1 -1
  175. package/dist/src/storage/store-identity.d.ts +21 -0
  176. package/dist/src/storage/store-identity.d.ts.map +1 -0
  177. package/dist/src/storage/store-identity.js +33 -0
  178. package/dist/src/storage/store-identity.js.map +1 -0
  179. package/dist/src/storage/struct.d.ts +15 -0
  180. package/dist/src/storage/struct.d.ts.map +1 -1
  181. package/dist/src/storage/with-read-cache.d.ts +92 -0
  182. package/dist/src/storage/with-read-cache.d.ts.map +1 -0
  183. package/dist/src/storage/with-read-cache.js +132 -0
  184. package/dist/src/storage/with-read-cache.js.map +1 -0
  185. package/dist/src/sync/service.d.ts +13 -3
  186. package/dist/src/sync/service.d.ts.map +1 -1
  187. package/dist/src/sync/service.js +7 -30
  188. package/dist/src/sync/service.js.map +1 -1
  189. package/dist/src/testing/mesh-harness.d.ts +75 -2
  190. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  191. package/dist/src/testing/mesh-harness.js +193 -81
  192. package/dist/src/testing/mesh-harness.js.map +1 -1
  193. package/dist/src/testing/raw-storage-conformance.d.ts +8 -0
  194. package/dist/src/testing/raw-storage-conformance.d.ts.map +1 -1
  195. package/dist/src/testing/raw-storage-conformance.js +97 -2
  196. package/dist/src/testing/raw-storage-conformance.js.map +1 -1
  197. package/package.json +5 -6
  198. package/src/cluster/block-transfer-service.ts +528 -312
  199. package/src/cluster/block-transfer.ts +547 -424
  200. package/src/cluster/certified-claims.ts +319 -0
  201. package/src/cluster/client-signature-verifier.ts +34 -0
  202. package/src/cluster/cluster-policy.ts +294 -203
  203. package/src/cluster/cluster-repo.ts +2501 -2034
  204. package/src/cluster/commit-proof.ts +344 -0
  205. package/src/cluster/quorum-restore.ts +348 -223
  206. package/src/cluster/rebalance-monitor.ts +539 -254
  207. package/src/cluster/reconcile-block.ts +404 -203
  208. package/src/cluster/service.ts +23 -20
  209. package/src/cluster/spread-on-churn.ts +352 -346
  210. package/src/cohort-topic/host.ts +8 -7
  211. package/src/cohort-topic/stream-util.ts +14 -43
  212. package/src/dispute/cascade.ts +31 -15
  213. package/src/dispute/dispute-service.ts +706 -696
  214. package/src/dispute/invalidation.ts +162 -52
  215. package/src/dispute/service.ts +126 -125
  216. package/src/index.ts +7 -0
  217. package/src/libp2p-key-network.ts +1204 -1235
  218. package/src/libp2p-node-base.ts +185 -70
  219. package/src/network/open-protocol-stream.ts +87 -0
  220. package/src/network/register-protocol-handler.ts +85 -0
  221. package/src/peer-address-book.ts +96 -2
  222. package/src/pend-validation.ts +89 -0
  223. package/src/reactivity/notify-transport.ts +2 -1
  224. package/src/reactivity/push-state-gossip.ts +2 -1
  225. package/src/repo/cluster-coordinator.ts +65 -11
  226. package/src/repo/coordinator-repo.ts +729 -71
  227. package/src/repo/served-repo-proxy.ts +55 -0
  228. package/src/repo/service.ts +25 -16
  229. package/src/reputation/types.ts +3 -1
  230. package/src/rn.ts +34 -4
  231. package/src/storage/block-archive.ts +242 -0
  232. package/src/storage/block-latch.ts +144 -0
  233. package/src/storage/block-storage.ts +787 -498
  234. package/src/storage/cached-raw-storage.ts +21 -1
  235. package/src/storage/cached-store-driver.ts +898 -859
  236. package/src/storage/i-block-storage.ts +172 -116
  237. package/src/storage/i-raw-storage.ts +40 -0
  238. package/src/storage/kv-raw-storage.ts +34 -9
  239. package/src/storage/memory-store-driver.ts +26 -2
  240. package/src/storage/raw-store-codec.ts +42 -42
  241. package/src/storage/raw-store-driver.ts +45 -3
  242. package/src/storage/shared-cache-pool.ts +516 -452
  243. package/src/storage/storage-repo.ts +1421 -1014
  244. package/src/storage/store-identity.ts +41 -0
  245. package/src/storage/struct.ts +52 -34
  246. package/src/storage/with-read-cache.ts +182 -0
  247. package/src/sync/service.ts +178 -198
  248. package/src/testing/mesh-harness.ts +524 -344
  249. package/src/testing/raw-storage-conformance.ts +114 -2
@@ -9,6 +9,17 @@ export interface RebalanceEvent {
9
9
  lost: string[];
10
10
  /** Peers that are now closer for the lost blocks: blockId → peerId[] */
11
11
  newOwners: Map<string, string[]>;
12
+ /**
13
+ * Blocks this node KEEPS responsibility for whose cohort now contains peers it has not seen
14
+ * co-responsible before: blockId → the newly co-responsible peer ids (never self). This is the
15
+ * cohort-GROWTH arm: the founder case (a block committed while the deployment was one node) never
16
+ * appears in `lost` — the holder keeps the block — so without this arm nothing ever pushes the
17
+ * second copy and the block stays readable only by its sole holder. The reaction pushes each
18
+ * block to these peers (capped by the replication floor). A block can appear in both `gained`
19
+ * and `grown` (first observation after a restart/regain — the push then finds no local data and
20
+ * is a benign no-op); it can never appear in both `lost` and `grown` (lost ⇒ not responsible).
21
+ */
22
+ grown: Map<string, string[]>;
12
23
  /**
13
24
  * Replication floor `N` for this event — the cohort size FRET assembled at check time
14
25
  * ({@link RebalanceMonitor.getCohortSize}). The reaction gates release of a `lost` block on
@@ -19,6 +30,20 @@ export interface RebalanceEvent {
19
30
  /** Timestamp of the topology change that triggered this */
20
31
  triggeredAt: number;
21
32
  }
33
+ /**
34
+ * What the growth reaction learned about ONE block reported `grown`. Fed back to
35
+ * {@link RebalanceMonitor.recordGrowthOutcome} so the seen set is confirmation-driven: a peer
36
+ * enters a block's seen set only once a replica is confirmed on it, or once the block has
37
+ * otherwise reached its floor. A block the reaction had NO information about (its confirm was
38
+ * deduped against one already in flight) gets no outcome at all — the monitor's state stays
39
+ * untouched and the next check re-detects.
40
+ */
41
+ export interface GrowthOutcome {
42
+ /** Newly co-responsible peers that may now be recorded as seen for this block. */
43
+ satisfiedPeers: string[];
44
+ /** True when nothing about this block is still owed a push. */
45
+ complete: boolean;
46
+ }
22
47
  export interface RebalanceMonitorConfig {
23
48
  /** Debounce window for topology changes (ms). Default: 5000 */
24
49
  debounceMs?: number;
@@ -26,6 +51,33 @@ export interface RebalanceMonitorConfig {
26
51
  minRebalanceIntervalMs?: number;
27
52
  /** Whether to suppress rebalancing during detected partitions. Default: true */
28
53
  suppressDuringPartition?: boolean;
54
+ /**
55
+ * Maximum blocks reported `grown` per check. Bounds the work a single peer join can trigger on a
56
+ * node with a large owned-block set — the primary bound is already the floor (a cohort is at most
57
+ * floor-sized, so each grown block pushes to ≤ floor−1 peers, and the reaction stops per block
58
+ * once the floor is met); this cap bounds the block COUNT per pass. A block dropped by the cap is
59
+ * NOT recorded as seen, so the next check re-detects the same growth — deferred, never lost.
60
+ * Default: 64
61
+ */
62
+ growthBlockBudget?: number;
63
+ /**
64
+ * How many incomplete growth outcomes ({@link GrowthOutcome} with `complete: false`) a block
65
+ * absorbs before its still-unsatisfied peers are moved to a per-block abandoned set and no longer
66
+ * pushed to. Without this bound a peer that permanently refuses would be re-pushed on every check
67
+ * forever, and its block would re-consume `growthBlockBudget` slots and starve genuinely-new
68
+ * growth. An abandoned peer that leaves the cohort and later rejoins is retried from scratch.
69
+ * Default: 5
70
+ */
71
+ growthMaxAttempts?: number;
72
+ /**
73
+ * Self-arming re-check timer for outstanding growth work (reported-but-unconfirmed peers, or
74
+ * blocks deferred by `growthBlockBudget`). Checks otherwise fire only on libp2p connection
75
+ * events, so a failed push on a then-quiet network would never be retried. Armed at the end of a
76
+ * check only while work is outstanding; fires `maybeRebalance()` so the existing
77
+ * `minRebalanceIntervalMs` throttle still bounds the push rate. `0` disables.
78
+ * Default: `minRebalanceIntervalMs`
79
+ */
80
+ growthRecheckIntervalMs?: number;
29
81
  }
30
82
  export interface RebalanceMonitorDeps {
31
83
  libp2p: Libp2p;
@@ -50,12 +102,17 @@ export declare class RebalanceMonitor implements Startable {
50
102
  private readonly responsibilitySnapshot;
51
103
  private readonly handlers;
52
104
  private debounceTimer;
105
+ private recheckTimer;
53
106
  private lastRebalanceAt;
54
107
  private pendingTopologyChange;
55
108
  private topologyChangeTimestamp;
109
+ private lastGrowthDeferred;
56
110
  private readonly debounceMs;
57
111
  private readonly minRebalanceIntervalMs;
58
112
  private readonly suppressDuringPartition;
113
+ private readonly growthBlockBudget;
114
+ private readonly growthMaxAttempts;
115
+ private readonly growthRecheckIntervalMs;
59
116
  private readonly onConnectionOpen;
60
117
  private readonly onConnectionClose;
61
118
  constructor(deps: RebalanceMonitorDeps, config?: RebalanceMonitorConfig);
@@ -66,6 +123,33 @@ export declare class RebalanceMonitor implements Startable {
66
123
  untrackBlock(blockId: string): void;
67
124
  getTrackedBlockCount(): number;
68
125
  checkNow(): Promise<RebalanceEvent | null>;
126
+ /**
127
+ * Feedback from the growth reaction for one block reported `grown`. `satisfiedPeers` enter the
128
+ * block's seen set; an incomplete outcome counts an attempt against `growthMaxAttempts`, and on
129
+ * reaching the bound the block's still-unsatisfied reported peers are abandoned (no longer
130
+ * pushed to until they leave the cohort and rejoin). Never called for a block the reaction had
131
+ * no information about (a confirm deduped against one already in flight) — a missing outcome
132
+ * leaves the block's state untouched so the next check retries.
133
+ */
134
+ recordGrowthOutcome(blockId: string, outcome: GrowthOutcome): void;
135
+ /**
136
+ * Growth-arm observability: how many tracked blocks still await confirmation on reported peers,
137
+ * how many (block, peer) pairs have been given up on, and whether the re-check timer is armed.
138
+ */
139
+ getGrowthDiagnostics(): {
140
+ blocksAwaitingConfirmation: number;
141
+ abandonedPairs: number;
142
+ recheckArmed: boolean;
143
+ };
144
+ /** Growth work is outstanding while any reported peer is unconfirmed or blocks were budget-deferred. */
145
+ private hasOutstandingGrowthWork;
146
+ /**
147
+ * Arm the growth re-check timer while work is outstanding; disarm it when there is none. The
148
+ * timer fires maybeRebalance(), so minRebalanceIntervalMs still bounds the push rate, and it
149
+ * re-arms itself after firing for as long as work remains. unref'd so it never holds the
150
+ * process open; stop() clears it.
151
+ */
152
+ private updateRecheckTimer;
69
153
  private handleTopologyChange;
70
154
  private maybeRebalance;
71
155
  private performRebalanceCheck;
@@ -1 +1 @@
1
- {"version":3,"file":"rebalance-monitor.d.ts","sourceRoot":"","sources":["../../../src/cluster/rebalance-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AAM/F,MAAM,WAAW,cAAc;IAC9B,wDAAwD;IACxD,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,sDAAsD;IACtD,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,wEAAwE;IACxE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IAChC;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qEAAqE;IACrE,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,gFAAgF;IAChF,uBAAuB,CAAC,EAAE,OAAO,CAAA;CACjC;AAED,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,WAAW,CAAA;IACjB,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,WAAW,EAAE,oBAAoB,CAAA;IACjC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAC3B;AAED,KAAK,gBAAgB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;AAEvD,qBAAa,gBAAiB,YAAW,SAAS;IAuBhD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAtBtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAa;IAM3C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA6B;IACpE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,eAAe,CAAI;IAC3B,OAAO,CAAC,qBAAqB,CAAQ;IACrC,OAAO,CAAC,uBAAuB,CAAI;IAEnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAQ;IAC/C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAS;IAEjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAY;gBAG5B,IAAI,EAAE,oBAAoB,EAC3C,MAAM,GAAE,sBAA2B;IAc9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAI5C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIjC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKnC,oBAAoB,IAAI,MAAM;IAIxB,QAAQ,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAIhD,OAAO,CAAC,oBAAoB;YAmBd,cAAc;YAgBd,qBAAqB;IA+CnC;;;;;OAKG;IACH,aAAa,IAAI,MAAM;IASvB,OAAO,CAAC,SAAS;IAUjB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,IAAI;CAGhD"}
1
+ {"version":3,"file":"rebalance-monitor.d.ts","sourceRoot":"","sources":["../../../src/cluster/rebalance-monitor.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,27 @@ import { hashKey } from 'p2p-fret';
2
2
  import { createLogger } from '../logger.js';
3
3
  const log = createLogger('rebalance-monitor');
4
4
  const textEncoder = new TextEncoder();
5
+ const emptyGrowthState = (responsible) => ({
6
+ responsible,
7
+ cohortPeers: new Set(),
8
+ pendingPeers: new Set(),
9
+ growthAttempts: 0,
10
+ abandonedPeers: new Set()
11
+ });
12
+ const intersect = (remembered, current) => new Set([...(remembered ?? [])].filter(id => current.has(id)));
13
+ /**
14
+ * Carry a still-responsible block's growth state into the next check, intersecting both remembered
15
+ * peer sets against the CURRENT cohort: a peer that left drops out of `cohortPeers` (so its return
16
+ * is re-detected — the departure self-heal) and out of `abandonedPeers` (so a rejoin is retried from
17
+ * scratch). `pendingPeers` is always rebuilt from this check's own report, never carried.
18
+ */
19
+ const carryGrowthState = (prior, currentPeers) => ({
20
+ responsible: true,
21
+ cohortPeers: intersect(prior?.cohortPeers, currentPeers),
22
+ pendingPeers: new Set(),
23
+ growthAttempts: prior?.growthAttempts ?? 0,
24
+ abandonedPeers: intersect(prior?.abandonedPeers, currentPeers)
25
+ });
5
26
  export class RebalanceMonitor {
6
27
  deps;
7
28
  running = false;
@@ -11,15 +32,28 @@ export class RebalanceMonitor {
11
32
  // responsibility-loss eviction going through untrackBlock — a snapshot entry for a since-removed
12
33
  // block may linger here. That is acceptable: performRebalanceCheck only iterates trackedBlocks, so
13
34
  // a lingering entry is inert; if the block is later re-fed, its responsibility is simply re-derived.
35
+ //
36
+ // `cohortPeers` is the growth arm's CONFIRMED-co-responsible memory. A MISSING entry is
37
+ // deliberately treated as "prior cohort = empty", so the first check after a topology event
38
+ // reports the whole non-self cohort as grown — that is what heals the founder case (A alone
39
+ // commits; B joins → first check pushes to B) and the restarted-holder case (snapshot memory is
40
+ // process-local, so a restarted holder re-pushes to everyone once). Peers enter the set only
41
+ // through recordGrowthOutcome — a reported-but-unconfirmed peer stays out, so a failed push is
42
+ // re-detected on the next check instead of being recorded as done.
14
43
  responsibilitySnapshot = new Map();
15
44
  handlers = [];
16
45
  debounceTimer = null;
46
+ recheckTimer = null;
17
47
  lastRebalanceAt = 0;
18
48
  pendingTopologyChange = false;
19
49
  topologyChangeTimestamp = 0;
50
+ lastGrowthDeferred = 0;
20
51
  debounceMs;
21
52
  minRebalanceIntervalMs;
22
53
  suppressDuringPartition;
54
+ growthBlockBudget;
55
+ growthMaxAttempts;
56
+ growthRecheckIntervalMs;
23
57
  onConnectionOpen;
24
58
  onConnectionClose;
25
59
  constructor(deps, config = {}) {
@@ -31,6 +65,9 @@ export class RebalanceMonitor {
31
65
  this.debounceMs = config.debounceMs ?? 5000;
32
66
  this.minRebalanceIntervalMs = config.minRebalanceIntervalMs ?? 60000;
33
67
  this.suppressDuringPartition = config.suppressDuringPartition ?? true;
68
+ this.growthBlockBudget = config.growthBlockBudget ?? 64;
69
+ this.growthMaxAttempts = config.growthMaxAttempts ?? 5;
70
+ this.growthRecheckIntervalMs = config.growthRecheckIntervalMs ?? this.minRebalanceIntervalMs;
34
71
  this.onConnectionOpen = () => this.handleTopologyChange();
35
72
  this.onConnectionClose = () => this.handleTopologyChange();
36
73
  }
@@ -52,6 +89,10 @@ export class RebalanceMonitor {
52
89
  clearTimeout(this.debounceTimer);
53
90
  this.debounceTimer = null;
54
91
  }
92
+ if (this.recheckTimer) {
93
+ clearTimeout(this.recheckTimer);
94
+ this.recheckTimer = null;
95
+ }
55
96
  this.pendingTopologyChange = false;
56
97
  log('stopped');
57
98
  }
@@ -71,6 +112,103 @@ export class RebalanceMonitor {
71
112
  async checkNow() {
72
113
  return this.performRebalanceCheck(Date.now());
73
114
  }
115
+ /**
116
+ * Feedback from the growth reaction for one block reported `grown`. `satisfiedPeers` enter the
117
+ * block's seen set; an incomplete outcome counts an attempt against `growthMaxAttempts`, and on
118
+ * reaching the bound the block's still-unsatisfied reported peers are abandoned (no longer
119
+ * pushed to until they leave the cohort and rejoin). Never called for a block the reaction had
120
+ * no information about (a confirm deduped against one already in flight) — a missing outcome
121
+ * leaves the block's state untouched so the next check retries.
122
+ */
123
+ recordGrowthOutcome(blockId, outcome) {
124
+ const state = this.responsibilitySnapshot.get(blockId);
125
+ // No state (untracked since) or responsibility lost since the report: the growth state was
126
+ // cleared, and recording into it would survive the clear and suppress the regain re-push.
127
+ if (!state || !state.responsible)
128
+ return;
129
+ for (const peerId of outcome.satisfiedPeers) {
130
+ state.cohortPeers.add(peerId);
131
+ state.pendingPeers.delete(peerId);
132
+ }
133
+ if (outcome.complete) {
134
+ state.growthAttempts = 0;
135
+ state.pendingPeers.clear();
136
+ }
137
+ else {
138
+ // NOTE: growthMaxAttempts is a floor on the retry count, not an exact one. `pendingPeers` is
139
+ // rebuilt from each check's own report, so two cases blunt the bound: a check that defers
140
+ // this block on growthBlockBudget clears pendingPeers, and a give-up landing right then
141
+ // abandons nobody while still resetting the counter; and two checks racing (the second
142
+ // re-reporting the same peer after the first's confirm left `inFlight` but before its outcome
143
+ // landed) double-count one attempt. Both are rare, both only change how many pushes a doomed
144
+ // peer absorbs. If a deployment ever tracks far more blocks than growthBlockBudget, deferral
145
+ // stops being rare — carry the report's peer list on GrowthOutcome and match it against
146
+ // pendingPeers instead of trusting the latest report.
147
+ state.growthAttempts++;
148
+ if (state.growthAttempts >= this.growthMaxAttempts) {
149
+ for (const peerId of state.pendingPeers) {
150
+ state.abandonedPeers.add(peerId);
151
+ }
152
+ log('growth give-up: block=%s abandoning %d unsatisfied peer(s) after %d attempts', blockId, state.pendingPeers.size, state.growthAttempts);
153
+ state.pendingPeers.clear();
154
+ state.growthAttempts = 0;
155
+ }
156
+ }
157
+ this.updateRecheckTimer();
158
+ }
159
+ /**
160
+ * Growth-arm observability: how many tracked blocks still await confirmation on reported peers,
161
+ * how many (block, peer) pairs have been given up on, and whether the re-check timer is armed.
162
+ */
163
+ getGrowthDiagnostics() {
164
+ let blocksAwaitingConfirmation = 0;
165
+ let abandonedPairs = 0;
166
+ for (const [blockId, state] of this.responsibilitySnapshot) {
167
+ if (!state.responsible || !this.trackedBlocks.has(blockId))
168
+ continue;
169
+ if (state.pendingPeers.size > 0)
170
+ blocksAwaitingConfirmation++;
171
+ abandonedPairs += state.abandonedPeers.size;
172
+ }
173
+ return { blocksAwaitingConfirmation, abandonedPairs, recheckArmed: this.recheckTimer !== null };
174
+ }
175
+ /** Growth work is outstanding while any reported peer is unconfirmed or blocks were budget-deferred. */
176
+ hasOutstandingGrowthWork() {
177
+ if (this.lastGrowthDeferred > 0)
178
+ return true;
179
+ for (const [blockId, state] of this.responsibilitySnapshot) {
180
+ if (state.responsible && state.pendingPeers.size > 0 && this.trackedBlocks.has(blockId)) {
181
+ return true;
182
+ }
183
+ }
184
+ return false;
185
+ }
186
+ /**
187
+ * Arm the growth re-check timer while work is outstanding; disarm it when there is none. The
188
+ * timer fires maybeRebalance(), so minRebalanceIntervalMs still bounds the push rate, and it
189
+ * re-arms itself after firing for as long as work remains. unref'd so it never holds the
190
+ * process open; stop() clears it.
191
+ */
192
+ updateRecheckTimer() {
193
+ if (this.growthRecheckIntervalMs <= 0)
194
+ return;
195
+ if (!this.running || !this.hasOutstandingGrowthWork()) {
196
+ if (this.recheckTimer) {
197
+ clearTimeout(this.recheckTimer);
198
+ this.recheckTimer = null;
199
+ }
200
+ return;
201
+ }
202
+ if (this.recheckTimer)
203
+ return; // already armed
204
+ this.recheckTimer = setTimeout(() => {
205
+ this.recheckTimer = null;
206
+ void this.maybeRebalance()
207
+ .catch(err => { log('recheck error: %O', err); })
208
+ .finally(() => this.updateRecheckTimer());
209
+ }, this.growthRecheckIntervalMs);
210
+ this.recheckTimer.unref?.();
211
+ }
74
212
  handleTopologyChange() {
75
213
  if (!this.running)
76
214
  return;
@@ -108,19 +246,27 @@ export class RebalanceMonitor {
108
246
  }
109
247
  if (this.trackedBlocks.size === 0) {
110
248
  this.lastRebalanceAt = Date.now();
249
+ // Nothing left to grow, so any prior deferral is moot — drop it and let the re-check timer
250
+ // disarm, rather than re-arming forever against blocks that were untracked out from under it.
251
+ this.lastGrowthDeferred = 0;
252
+ this.updateRecheckTimer();
111
253
  return null;
112
254
  }
113
255
  const selfId = this.deps.libp2p.peerId.toString();
114
256
  const gained = [];
115
257
  const lost = [];
116
258
  const newOwners = new Map();
259
+ const grown = new Map();
260
+ let growthDeferred = 0;
261
+ const growthCandidates = [];
117
262
  for (const blockId of this.trackedBlocks) {
118
263
  const key = textEncoder.encode(blockId);
119
264
  const coord = await hashKey(key);
120
265
  // Get the current cohort — assembleCohort returns peer IDs sorted by distance
121
266
  const cohort = this.deps.fret.assembleCohort(coord, this.getCohortSize());
122
267
  const isResponsible = cohort.includes(selfId);
123
- const wasResponsible = this.responsibilitySnapshot.get(blockId) ?? false;
268
+ const prior = this.responsibilitySnapshot.get(blockId);
269
+ const wasResponsible = prior?.responsible ?? false;
124
270
  if (isResponsible && !wasResponsible) {
125
271
  gained.push(blockId);
126
272
  }
@@ -129,14 +275,70 @@ export class RebalanceMonitor {
129
275
  // The cohort members are the new owners
130
276
  newOwners.set(blockId, cohort.filter(id => id !== selfId));
131
277
  }
132
- this.responsibilitySnapshot.set(blockId, isResponsible);
278
+ // Growth arm: while this node STAYS responsible, any cohort peer not yet CONFIRMED to hold
279
+ // the block (and not abandoned) gets it pushed (up to the floor). Runs on every responsible
280
+ // check — NOT gated on wasResponsible — so a first observation (no snapshot entry) treats
281
+ // the whole non-self cohort as new; see the responsibilitySnapshot comment for why that is
282
+ // load-bearing. Not responsible ⇒ arm skipped, so `lost` ∩ `grown` is impossible.
283
+ //
284
+ // Reporting a peer does NOT record it as seen — only recordGrowthOutcome does — so a push
285
+ // that fails (dial timeout, receiver refused to persist, partition mid-reaction, reaction
286
+ // threw) leaves the peer un-seen and the next check re-detects it.
287
+ let state;
288
+ if (isResponsible) {
289
+ const currentSet = new Set(cohort.filter(id => id !== selfId));
290
+ state = carryGrowthState(prior, currentSet);
291
+ const newPeers = [...currentSet].filter(id => !state.cohortPeers.has(id) && !state.abandonedPeers.has(id));
292
+ if (newPeers.length > 0) {
293
+ growthCandidates.push({ blockId, newPeers, state });
294
+ }
295
+ else {
296
+ // Nothing owed for this block. growthAttempts counts CONSECUTIVE incomplete outcomes
297
+ // against outstanding growth, so it must not carry across a quiet stretch — otherwise a
298
+ // block that failed a few times, then had that peer leave, would spend the leftovers on
299
+ // whichever peer joins next and abandon it early.
300
+ state.growthAttempts = 0;
301
+ }
302
+ }
303
+ else {
304
+ // Not responsible: clear ALL growth state (seen set, attempts, abandoned peers), so a
305
+ // later regain re-pushes to the whole cohort (benign when the local data is gone — the
306
+ // push finds nothing and no-ops).
307
+ state = emptyGrowthState(false);
308
+ }
309
+ this.responsibilitySnapshot.set(blockId, state);
133
310
  }
311
+ // Fill the growth budget in two passes: fresh growth (no failed attempts yet) first, retrying
312
+ // blocks with what remains — otherwise a stuck retry set at the front of the tracked-block
313
+ // insertion order would starve peers that just joined.
314
+ for (const candidate of [
315
+ ...growthCandidates.filter(c => c.state.growthAttempts === 0),
316
+ ...growthCandidates.filter(c => c.state.growthAttempts > 0)
317
+ ]) {
318
+ if (grown.size < this.growthBlockBudget) {
319
+ grown.set(candidate.blockId, candidate.newPeers);
320
+ candidate.state.pendingPeers = new Set(candidate.newPeers);
321
+ }
322
+ else {
323
+ // Budget-dropped: the seen set was not touched, so the next check re-detects the same
324
+ // growth — a deferral, not a loss.
325
+ growthDeferred++;
326
+ }
327
+ }
328
+ this.lastGrowthDeferred = growthDeferred;
134
329
  this.lastRebalanceAt = Date.now();
135
- if (gained.length === 0 && lost.length === 0) {
330
+ if (growthDeferred > 0) {
331
+ // Deferred blocks drain one budget-full per check. Checks fire on libp2p connection events
332
+ // AND — while growth work is outstanding — on the growthRecheckIntervalMs timer armed
333
+ // below, so a backlog drains even on a quiet network.
334
+ log('growth budget reached: %d blocks deferred to the next check (budget=%d)', growthDeferred, this.growthBlockBudget);
335
+ }
336
+ this.updateRecheckTimer();
337
+ if (gained.length === 0 && lost.length === 0 && grown.size === 0) {
136
338
  return null;
137
339
  }
138
- log('rebalance check: gained=%d lost=%d', gained.length, lost.length);
139
- return { gained, lost, newOwners, floor: this.getCohortSize(), triggeredAt };
340
+ log('rebalance check: gained=%d lost=%d grown=%d', gained.length, lost.length, grown.size);
341
+ return { gained, lost, newOwners, grown, floor: this.getCohortSize(), triggeredAt };
140
342
  }
141
343
  /**
142
344
  * The replication floor `N` — the cohort size FRET assembles for a block. Public so the ring-shift
@@ -1 +1 @@
1
- {"version":3,"file":"rebalance-monitor.js","sourceRoot":"","sources":["../../../src/cluster/rebalance-monitor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rebalance-monitor.js","sourceRoot":"","sources":["../../../src/cluster/rebalance-monitor.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,8 @@ import type { ActionRev, BlockId, IBlock } from "@optimystic/db-core";
2
2
  import type { BlockArchive } from "../storage/struct.js";
3
3
  import type { ReconcileBlockCallback } from "./cluster-repo.js";
4
4
  import type { IPeerReputation } from "../reputation/types.js";
5
+ import { type ProofAnchoring } from "./certified-claims.js";
6
+ import type { BlockCommitProof } from "./commit-proof.js";
5
7
  /**
6
8
  * Wall-clock bound on one whole reconcile pass (all cohort peers, both quorums, the persist).
7
9
  * Shared by both callers so a slow or unreachable cohort peer stalls neither the commit path
@@ -15,10 +17,18 @@ export interface ReconcileBlockDeps {
15
17
  selfPeerId: string;
16
18
  /** Fetch one cohort peer's archive for `blockId` — `undefined` when it is unreachable or holds nothing. */
17
19
  fetchArchive: (peerId: string, blockId: BlockId) => Promise<BlockArchive | undefined>;
18
- /** Persist the agreed content through the churn-replication funnel. */
19
- saveReplicatedBlock: (blockId: BlockId, block: IBlock, source: ActionRev) => Promise<void>;
20
+ /**
21
+ * Persist the agreed content through the churn-replication funnel. `verifiedProof` is passed
22
+ * ONLY when it was verified against these exact bytes (`certifyContent`'s digest check) — the
23
+ * receiver persists it as evidence, so an unverified proof must never reach this parameter.
24
+ */
25
+ saveReplicatedBlock: (blockId: BlockId, block: IBlock, source: ActionRev, verifiedProof?: BlockCommitProof) => Promise<void>;
20
26
  /** Proportional corroboration threshold; the cohort's `simpleMajorityThreshold`. */
21
27
  simpleMajorityThreshold: number;
28
+ /** Promise-round gate for proof verification; the cohort's `superMajorityThreshold`. */
29
+ superMajorityThreshold: number;
30
+ /** Optional layer-2 anchoring for accepted proofs — observational only, see `cluster/certified-claims.ts`. */
31
+ anchoring?: ProofAnchoring;
22
32
  /**
23
33
  * Yardstick the corroboration floor is measured against — the floor for
24
34
  * {@link corroboratorCapacity}. Required, not optional: unlike the membership admission gate there
@@ -40,9 +50,15 @@ export interface ReconcileBlockDeps {
40
50
  * corroboration rather than raw `Math.max` (a lone peer inflating its rev cannot steer
41
51
  * reconciliation), verifies the cohort agrees on the *content* at that revision, and persists it.
42
52
  *
43
- * Both quorums are capped by {@link corroboratorCapacity}: demanding two corroborators from a
44
- * cohort that contains exactly one other peer is a permanent deadlock, not a safety property
45
- * the node can never heal and stays unreadable forever.
53
+ * Peer-attached cohort commit proofs are verified first ({@link certifyCandidates}) and both gates
54
+ * weigh the verdicts: a claim and, separately, the bytes that a verified proof certifies is
55
+ * accepted with no second peer at any cohort size, and the proof that certified the bytes is
56
+ * persisted alongside them so the repaired replica serves it onward.
57
+ *
58
+ * Both quorums are capped by {@link corroboratorCapacity} for the claims that still need
59
+ * corroboration: demanding two corroborators from a cohort that contains exactly one other peer is
60
+ * a permanent deadlock, not a safety property — the node can never heal and stays unreadable
61
+ * forever.
46
62
  *
47
63
  * **Exposure at capacity 1 (documented, not accidental).** Block ids are random 256-bit strings
48
64
  * (`db-core` `structs.ts`), NOT content-addressed, so nothing on the receive path can re-derive
@@ -50,8 +66,12 @@ export interface ReconcileBlockDeps {
50
66
  * against `blockId`. A sole cohort peer's content is therefore believed on its word. That adds no
51
67
  * trust the cohort had not already extended — the same peer's `(rev, actionId)` claim is likewise
52
68
  * uncorroborable at that size (see `selectQuorumRev`'s capacity note), and a two-member cohort has
53
- * no honest majority to appeal to in the first place. Closing it needs commit-cert verification,
54
- * tracked by backlog `debt-read-repair-commit-cert-verification`.
69
+ * no honest majority to appeal to in the first place. It is closed for a candidate that carries a
70
+ * verified cohort commit proof — {@link certifyCandidates} binds the proof's declared digest to the
71
+ * served bytes, which is a check against the *cohort's own signatures* rather than against other
72
+ * peers, so a certified carrier wins the content gate outright and this exposure never applies to
73
+ * it. It remains open for a proof-less candidate, and for the residual that layer 1 proves only
74
+ * that the listed signers signed (`feat-cluster-membership-threshold-cert-anchoring`).
55
75
  *
56
76
  * Declines are cheap and retryable: nothing is persisted, nothing is marked, and the next commit
57
77
  * or churn/rebalance pass tries again.
@@ -1 +1 @@
1
- {"version":3,"file":"reconcile-block.d.ts","sourceRoot":"","sources":["../../../src/cluster/reconcile-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAU9D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAWzC,wGAAwG;AACxG,MAAM,WAAW,kBAAkB;IAClC,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IACtF,uEAAuE;IACvE,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3F,oFAAoF;IACpF,uBAAuB,EAAE,MAAM,CAAC;IAChC;;;;;;;;OAQG;IACH,8BAA8B,EAAE,MAAM,CAAC;IACvC,iFAAiF;IACjF,UAAU,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;CACjD;AAmFD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,sBAAsB,CA2CrF"}
1
+ {"version":3,"file":"reconcile-block.d.ts","sourceRoot":"","sources":["../../../src/cluster/reconcile-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,EACqE,KAAK,cAAc,EAC9F,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAK1D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AA6BzC,wGAAwG;AACxG,MAAM,WAAW,kBAAkB;IAClC,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IACtF;;;;OAIG;IACH,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7H,oFAAoF;IACpF,uBAAuB,EAAE,MAAM,CAAC;IAChC,wFAAwF;IACxF,sBAAsB,EAAE,MAAM,CAAC;IAC/B,8GAA8G;IAC9G,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;;;;;;OAQG;IACH,8BAA8B,EAAE,MAAM,CAAC;IACvC,iFAAiF;IACjF,UAAU,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;CACjD;AA4LD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,sBAAsB,CAgGrF"}