@origintrail-official/dkg-agent 10.0.19 → 10.0.21

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 (733) hide show
  1. package/dist/approved-private-replica.d.ts +54 -0
  2. package/dist/approved-private-replica.d.ts.map +1 -0
  3. package/dist/approved-private-replica.js +148 -0
  4. package/dist/approved-private-replica.js.map +1 -0
  5. package/dist/bounded-operation.d.ts +2 -0
  6. package/dist/bounded-operation.d.ts.map +1 -1
  7. package/dist/bounded-operation.js +5 -0
  8. package/dist/bounded-operation.js.map +1 -1
  9. package/dist/chain-finality-confirmations-v1.d.ts +7 -0
  10. package/dist/chain-finality-confirmations-v1.d.ts.map +1 -0
  11. package/dist/chain-finality-confirmations-v1.js +9 -0
  12. package/dist/chain-finality-confirmations-v1.js.map +1 -0
  13. package/dist/chain-reconciler.d.ts +23 -0
  14. package/dist/chain-reconciler.d.ts.map +1 -1
  15. package/dist/chain-reconciler.js +35 -0
  16. package/dist/chain-reconciler.js.map +1 -1
  17. package/dist/confirmed-graph-scoped-vm-resolver.d.ts +7 -1
  18. package/dist/confirmed-graph-scoped-vm-resolver.d.ts.map +1 -1
  19. package/dist/confirmed-graph-scoped-vm-resolver.js +5 -3
  20. package/dist/confirmed-graph-scoped-vm-resolver.js.map +1 -1
  21. package/dist/context-graph-authority-dependency.d.ts +11 -0
  22. package/dist/context-graph-authority-dependency.d.ts.map +1 -0
  23. package/dist/context-graph-authority-dependency.js +50 -0
  24. package/dist/context-graph-authority-dependency.js.map +1 -0
  25. package/dist/context-graph-binding-state.d.ts +6 -0
  26. package/dist/context-graph-binding-state.d.ts.map +1 -1
  27. package/dist/context-graph-binding-state.js +17 -10
  28. package/dist/context-graph-binding-state.js.map +1 -1
  29. package/dist/context-graph-claim-proof.d.ts +74 -0
  30. package/dist/context-graph-claim-proof.d.ts.map +1 -0
  31. package/dist/context-graph-claim-proof.js +137 -0
  32. package/dist/context-graph-claim-proof.js.map +1 -0
  33. package/dist/context-graph-member-proof.d.ts +33 -0
  34. package/dist/context-graph-member-proof.d.ts.map +1 -0
  35. package/dist/context-graph-member-proof.js +142 -0
  36. package/dist/context-graph-member-proof.js.map +1 -0
  37. package/dist/context-graph-membership-persist-scheduler.d.ts +7 -23
  38. package/dist/context-graph-membership-persist-scheduler.d.ts.map +1 -1
  39. package/dist/context-graph-membership-persist-scheduler.js +12 -88
  40. package/dist/context-graph-membership-persist-scheduler.js.map +1 -1
  41. package/dist/context-graph-meta-confirmation.d.ts +22 -2
  42. package/dist/context-graph-meta-confirmation.d.ts.map +1 -1
  43. package/dist/context-graph-meta-confirmation.js +54 -23
  44. package/dist/context-graph-meta-confirmation.js.map +1 -1
  45. package/dist/context-graph-meta-projection.d.ts +13 -2
  46. package/dist/context-graph-meta-projection.d.ts.map +1 -1
  47. package/dist/context-graph-meta-projection.js +61 -24
  48. package/dist/context-graph-meta-projection.js.map +1 -1
  49. package/dist/context-graph-metadata-relocation.d.ts +18 -30
  50. package/dist/context-graph-metadata-relocation.d.ts.map +1 -1
  51. package/dist/context-graph-metadata-relocation.js +32 -2
  52. package/dist/context-graph-metadata-relocation.js.map +1 -1
  53. package/dist/context-graph-private-meta-proof.d.ts +8 -9
  54. package/dist/context-graph-private-meta-proof.d.ts.map +1 -1
  55. package/dist/context-graph-private-meta-proof.js +25 -89
  56. package/dist/context-graph-private-meta-proof.js.map +1 -1
  57. package/dist/context-graph-public-meta-proof.d.ts +11 -1
  58. package/dist/context-graph-public-meta-proof.d.ts.map +1 -1
  59. package/dist/context-graph-public-meta-proof.js +23 -3
  60. package/dist/context-graph-public-meta-proof.js.map +1 -1
  61. package/dist/context-graph-read-authority.d.ts +30 -3
  62. package/dist/context-graph-read-authority.d.ts.map +1 -1
  63. package/dist/context-graph-read-authority.js +62 -18
  64. package/dist/context-graph-read-authority.js.map +1 -1
  65. package/dist/context-graph-storage-discovery.d.ts +14 -4
  66. package/dist/context-graph-storage-discovery.d.ts.map +1 -1
  67. package/dist/context-graph-storage-discovery.js +27 -7
  68. package/dist/context-graph-storage-discovery.js.map +1 -1
  69. package/dist/context-graph-subscription-authority-recovery.d.ts +7 -0
  70. package/dist/context-graph-subscription-authority-recovery.d.ts.map +1 -1
  71. package/dist/context-graph-subscription-authority-recovery.js +1 -0
  72. package/dist/context-graph-subscription-authority-recovery.js.map +1 -1
  73. package/dist/context-graph-subscription-persist-scheduler.d.ts +52 -0
  74. package/dist/context-graph-subscription-persist-scheduler.d.ts.map +1 -0
  75. package/dist/context-graph-subscription-persist-scheduler.js +78 -0
  76. package/dist/context-graph-subscription-persist-scheduler.js.map +1 -0
  77. package/dist/curator-dial-address.d.ts +16 -0
  78. package/dist/curator-dial-address.d.ts.map +1 -0
  79. package/dist/curator-dial-address.js +58 -0
  80. package/dist/curator-dial-address.js.map +1 -0
  81. package/dist/curator-meta-refresh.d.ts +18 -4
  82. package/dist/curator-meta-refresh.d.ts.map +1 -1
  83. package/dist/curator-meta-refresh.js +61 -58
  84. package/dist/curator-meta-refresh.js.map +1 -1
  85. package/dist/curator-peer-connection.d.ts +21 -0
  86. package/dist/curator-peer-connection.d.ts.map +1 -0
  87. package/dist/curator-peer-connection.js +41 -0
  88. package/dist/curator-peer-connection.js.map +1 -0
  89. package/dist/dkg-agent-agents-phonebook.d.ts +41 -0
  90. package/dist/dkg-agent-agents-phonebook.d.ts.map +1 -0
  91. package/dist/dkg-agent-agents-phonebook.js +155 -0
  92. package/dist/dkg-agent-agents-phonebook.js.map +1 -0
  93. package/dist/dkg-agent-base.d.ts +162 -24
  94. package/dist/dkg-agent-base.d.ts.map +1 -1
  95. package/dist/dkg-agent-base.js +175 -147
  96. package/dist/dkg-agent-base.js.map +1 -1
  97. package/dist/dkg-agent-cg-chain-observation.d.ts +6 -1
  98. package/dist/dkg-agent-cg-chain-observation.d.ts.map +1 -1
  99. package/dist/dkg-agent-cg-chain-observation.js +20 -5
  100. package/dist/dkg-agent-cg-chain-observation.js.map +1 -1
  101. package/dist/dkg-agent-cg-name-resolution.d.ts +38 -2
  102. package/dist/dkg-agent-cg-name-resolution.d.ts.map +1 -1
  103. package/dist/dkg-agent-cg-name-resolution.js +100 -8
  104. package/dist/dkg-agent-cg-name-resolution.js.map +1 -1
  105. package/dist/dkg-agent-cg-registry.d.ts +43 -3
  106. package/dist/dkg-agent-cg-registry.d.ts.map +1 -1
  107. package/dist/dkg-agent-cg-registry.js +267 -129
  108. package/dist/dkg-agent-cg-registry.js.map +1 -1
  109. package/dist/dkg-agent-cg-resolve.d.ts +6 -4
  110. package/dist/dkg-agent-cg-resolve.d.ts.map +1 -1
  111. package/dist/dkg-agent-cg-resolve.js +40 -18
  112. package/dist/dkg-agent-cg-resolve.js.map +1 -1
  113. package/dist/dkg-agent-constants.d.ts +10 -2
  114. package/dist/dkg-agent-constants.d.ts.map +1 -1
  115. package/dist/dkg-agent-constants.js +10 -2
  116. package/dist/dkg-agent-constants.js.map +1 -1
  117. package/dist/dkg-agent-context-graph.d.ts.map +1 -1
  118. package/dist/dkg-agent-context-graph.js +1 -5
  119. package/dist/dkg-agent-context-graph.js.map +1 -1
  120. package/dist/dkg-agent-crypto.d.ts +128 -21
  121. package/dist/dkg-agent-crypto.d.ts.map +1 -1
  122. package/dist/dkg-agent-crypto.js +824 -176
  123. package/dist/dkg-agent-crypto.js.map +1 -1
  124. package/dist/dkg-agent-diagnostics.d.ts.map +1 -1
  125. package/dist/dkg-agent-diagnostics.js +4 -3
  126. package/dist/dkg-agent-diagnostics.js.map +1 -1
  127. package/dist/dkg-agent-helpers.d.ts +2 -2
  128. package/dist/dkg-agent-helpers.d.ts.map +1 -1
  129. package/dist/dkg-agent-helpers.js +3 -3
  130. package/dist/dkg-agent-helpers.js.map +1 -1
  131. package/dist/dkg-agent-join.d.ts +12 -1
  132. package/dist/dkg-agent-join.d.ts.map +1 -1
  133. package/dist/dkg-agent-join.js +80 -92
  134. package/dist/dkg-agent-join.js.map +1 -1
  135. package/dist/dkg-agent-lifecycle.d.ts +129 -22
  136. package/dist/dkg-agent-lifecycle.d.ts.map +1 -1
  137. package/dist/dkg-agent-lifecycle.js +690 -211
  138. package/dist/dkg-agent-lifecycle.js.map +1 -1
  139. package/dist/dkg-agent-publish.d.ts +33 -40
  140. package/dist/dkg-agent-publish.d.ts.map +1 -1
  141. package/dist/dkg-agent-publish.js +194 -281
  142. package/dist/dkg-agent-publish.js.map +1 -1
  143. package/dist/dkg-agent-query.d.ts +7 -0
  144. package/dist/dkg-agent-query.d.ts.map +1 -1
  145. package/dist/dkg-agent-query.js +102 -86
  146. package/dist/dkg-agent-query.js.map +1 -1
  147. package/dist/dkg-agent-registered-private-empty-vm.d.ts +70 -0
  148. package/dist/dkg-agent-registered-private-empty-vm.d.ts.map +1 -0
  149. package/dist/dkg-agent-registered-private-empty-vm.js +133 -0
  150. package/dist/dkg-agent-registered-private-empty-vm.js.map +1 -0
  151. package/dist/dkg-agent-rfc64-catalog-auto-publish.d.ts +8 -3
  152. package/dist/dkg-agent-rfc64-catalog-auto-publish.d.ts.map +1 -1
  153. package/dist/dkg-agent-rfc64-catalog-auto-publish.js +45 -51
  154. package/dist/dkg-agent-rfc64-catalog-auto-publish.js.map +1 -1
  155. package/dist/dkg-agent-rfc64-catalog.d.ts +87 -80
  156. package/dist/dkg-agent-rfc64-catalog.d.ts.map +1 -1
  157. package/dist/dkg-agent-rfc64-catalog.js +726 -476
  158. package/dist/dkg-agent-rfc64-catalog.js.map +1 -1
  159. package/dist/dkg-agent-rfc64-meta-bootstrap.d.ts +6 -1
  160. package/dist/dkg-agent-rfc64-meta-bootstrap.d.ts.map +1 -1
  161. package/dist/dkg-agent-rfc64-meta-bootstrap.js +29 -13
  162. package/dist/dkg-agent-rfc64-meta-bootstrap.js.map +1 -1
  163. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.d.ts +8 -0
  164. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.d.ts.map +1 -1
  165. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.js +249 -40
  166. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.js.map +1 -1
  167. package/dist/dkg-agent-rfc64-swm-catalog-projection.d.ts.map +1 -1
  168. package/dist/dkg-agent-rfc64-swm-catalog-projection.js +3 -2
  169. package/dist/dkg-agent-rfc64-swm-catalog-projection.js.map +1 -1
  170. package/dist/dkg-agent-swm-host.d.ts +217 -52
  171. package/dist/dkg-agent-swm-host.d.ts.map +1 -1
  172. package/dist/dkg-agent-swm-host.js +1305 -858
  173. package/dist/dkg-agent-swm-host.js.map +1 -1
  174. package/dist/dkg-agent-swm-state.d.ts +15 -0
  175. package/dist/dkg-agent-swm-state.d.ts.map +1 -1
  176. package/dist/dkg-agent-swm-state.js +43 -0
  177. package/dist/dkg-agent-swm-state.js.map +1 -1
  178. package/dist/dkg-agent-swm-substrate.d.ts +49 -8
  179. package/dist/dkg-agent-swm-substrate.d.ts.map +1 -1
  180. package/dist/dkg-agent-swm-substrate.js +219 -46
  181. package/dist/dkg-agent-swm-substrate.js.map +1 -1
  182. package/dist/dkg-agent-types.d.ts +86 -27
  183. package/dist/dkg-agent-types.d.ts.map +1 -1
  184. package/dist/dkg-agent-types.js.map +1 -1
  185. package/dist/dkg-agent-vm-promotion.d.ts +4 -0
  186. package/dist/dkg-agent-vm-promotion.d.ts.map +1 -1
  187. package/dist/dkg-agent-vm-promotion.js +40 -5
  188. package/dist/dkg-agent-vm-promotion.js.map +1 -1
  189. package/dist/dkg-agent-vm-reconcile-scheduling.d.ts +7 -0
  190. package/dist/dkg-agent-vm-reconcile-scheduling.d.ts.map +1 -1
  191. package/dist/dkg-agent-vm-reconcile-scheduling.js +18 -0
  192. package/dist/dkg-agent-vm-reconcile-scheduling.js.map +1 -1
  193. package/dist/dkg-agent.d.ts +31 -2
  194. package/dist/dkg-agent.d.ts.map +1 -1
  195. package/dist/dkg-agent.js +188 -72
  196. package/dist/dkg-agent.js.map +1 -1
  197. package/dist/exact-graph-content-verifier.d.ts.map +1 -1
  198. package/dist/exact-graph-content-verifier.js +3 -2
  199. package/dist/exact-graph-content-verifier.js.map +1 -1
  200. package/dist/finalization-handler.d.ts +26 -211
  201. package/dist/finalization-handler.d.ts.map +1 -1
  202. package/dist/finalization-handler.js +94 -1652
  203. package/dist/finalization-handler.js.map +1 -1
  204. package/dist/finalization-recovery-sqlite-displacement.d.ts +37 -0
  205. package/dist/finalization-recovery-sqlite-displacement.d.ts.map +1 -0
  206. package/dist/finalization-recovery-sqlite-displacement.js +102 -0
  207. package/dist/finalization-recovery-sqlite-displacement.js.map +1 -0
  208. package/dist/finalization-recovery-sqlite-policy.d.ts +20 -4
  209. package/dist/finalization-recovery-sqlite-policy.d.ts.map +1 -1
  210. package/dist/finalization-recovery-sqlite-policy.js +21 -5
  211. package/dist/finalization-recovery-sqlite-policy.js.map +1 -1
  212. package/dist/finalization-recovery-sqlite-rows.d.ts +53 -0
  213. package/dist/finalization-recovery-sqlite-rows.d.ts.map +1 -0
  214. package/dist/finalization-recovery-sqlite-rows.js +77 -0
  215. package/dist/finalization-recovery-sqlite-rows.js.map +1 -0
  216. package/dist/finalization-recovery-sqlite-store.d.ts +10 -4
  217. package/dist/finalization-recovery-sqlite-store.d.ts.map +1 -1
  218. package/dist/finalization-recovery-sqlite-store.js +49 -50
  219. package/dist/finalization-recovery-sqlite-store.js.map +1 -1
  220. package/dist/finalization-recovery-store.d.ts +18 -0
  221. package/dist/finalization-recovery-store.d.ts.map +1 -1
  222. package/dist/finalization-recovery-store.js +24 -0
  223. package/dist/finalization-recovery-store.js.map +1 -1
  224. package/dist/finalization-recovery-worker.js +1 -1
  225. package/dist/finalization-recovery-worker.js.map +1 -1
  226. package/dist/finalization-recovery.d.ts +2 -3
  227. package/dist/finalization-recovery.d.ts.map +1 -1
  228. package/dist/finalization-recovery.js +12 -9
  229. package/dist/finalization-recovery.js.map +1 -1
  230. package/dist/finalized-authority-cold-resolution.d.ts +6 -1
  231. package/dist/finalized-authority-cold-resolution.d.ts.map +1 -1
  232. package/dist/finalized-authority-cold-resolution.js +22 -3
  233. package/dist/finalized-authority-cold-resolution.js.map +1 -1
  234. package/dist/gossip-publish-handler.d.ts.map +1 -1
  235. package/dist/gossip-publish-handler.js +4 -2
  236. package/dist/gossip-publish-handler.js.map +1 -1
  237. package/dist/gossip-session.d.ts +29 -0
  238. package/dist/gossip-session.d.ts.map +1 -0
  239. package/dist/gossip-session.js +48 -0
  240. package/dist/gossip-session.js.map +1 -0
  241. package/dist/index.d.ts +4 -1
  242. package/dist/index.d.ts.map +1 -1
  243. package/dist/index.js +4 -0
  244. package/dist/index.js.map +1 -1
  245. package/dist/internal/context-graph-authority/approved-member-acceptance.d.ts +61 -0
  246. package/dist/internal/context-graph-authority/approved-member-acceptance.d.ts.map +1 -0
  247. package/dist/internal/context-graph-authority/approved-member-acceptance.js +75 -0
  248. package/dist/internal/context-graph-authority/approved-member-acceptance.js.map +1 -0
  249. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.d.ts +5 -5
  250. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.d.ts.map +1 -1
  251. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.js +59 -49
  252. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.js.map +1 -1
  253. package/dist/internal/context-graph-authority/context-graph-authority.d.ts +1 -0
  254. package/dist/internal/context-graph-authority/context-graph-authority.d.ts.map +1 -1
  255. package/dist/internal/context-graph-authority/context-graph-authority.js +25 -0
  256. package/dist/internal/context-graph-authority/context-graph-authority.js.map +1 -1
  257. package/dist/internal/context-graph-authority/finalized-target-projection.d.ts +17 -0
  258. package/dist/internal/context-graph-authority/finalized-target-projection.d.ts.map +1 -0
  259. package/dist/internal/context-graph-authority/finalized-target-projection.js +36 -0
  260. package/dist/internal/context-graph-authority/finalized-target-projection.js.map +1 -0
  261. package/dist/internal/context-graph-authority/swm-transport-authority.d.ts +84 -0
  262. package/dist/internal/context-graph-authority/swm-transport-authority.d.ts.map +1 -0
  263. package/dist/internal/context-graph-authority/swm-transport-authority.js +175 -0
  264. package/dist/internal/context-graph-authority/swm-transport-authority.js.map +1 -0
  265. package/dist/internal/context-graph-binding-abort.d.ts +3 -0
  266. package/dist/internal/context-graph-binding-abort.d.ts.map +1 -0
  267. package/dist/internal/context-graph-binding-abort.js +32 -0
  268. package/dist/internal/context-graph-binding-abort.js.map +1 -0
  269. package/dist/internal/context-graph-cache-invalidating-store.d.ts +3 -0
  270. package/dist/internal/context-graph-cache-invalidating-store.d.ts.map +1 -0
  271. package/dist/internal/context-graph-cache-invalidating-store.js +167 -0
  272. package/dist/internal/context-graph-cache-invalidating-store.js.map +1 -0
  273. package/dist/internal/context-graph-meta-record-copy.d.ts +3 -0
  274. package/dist/internal/context-graph-meta-record-copy.d.ts.map +1 -0
  275. package/dist/internal/context-graph-meta-record-copy.js +21 -0
  276. package/dist/internal/context-graph-meta-record-copy.js.map +1 -0
  277. package/dist/internal/gossip/host-mode-handler.d.ts +11 -0
  278. package/dist/internal/gossip/host-mode-handler.d.ts.map +1 -0
  279. package/dist/internal/gossip/host-mode-handler.js +41 -0
  280. package/dist/internal/gossip/host-mode-handler.js.map +1 -0
  281. package/dist/internal/join-encryption-key-bundle.d.ts +10 -0
  282. package/dist/internal/join-encryption-key-bundle.d.ts.map +1 -0
  283. package/dist/internal/join-encryption-key-bundle.js +72 -0
  284. package/dist/internal/join-encryption-key-bundle.js.map +1 -0
  285. package/dist/internal/knowledge-asset-vm-publish-request.d.ts +31 -0
  286. package/dist/internal/knowledge-asset-vm-publish-request.d.ts.map +1 -0
  287. package/dist/internal/knowledge-asset-vm-publish-request.js +91 -0
  288. package/dist/internal/knowledge-asset-vm-publish-request.js.map +1 -0
  289. package/dist/internal/lifecycle-sync-policy.d.ts +5 -0
  290. package/dist/internal/lifecycle-sync-policy.d.ts.map +1 -0
  291. package/dist/internal/lifecycle-sync-policy.js +12 -0
  292. package/dist/internal/lifecycle-sync-policy.js.map +1 -0
  293. package/dist/internal/local-private-member.d.ts +14 -0
  294. package/dist/internal/local-private-member.d.ts.map +1 -0
  295. package/dist/internal/local-private-member.js +21 -0
  296. package/dist/internal/local-private-member.js.map +1 -0
  297. package/dist/internal/promote/assertion-promote-precommit.d.ts +41 -1
  298. package/dist/internal/promote/assertion-promote-precommit.d.ts.map +1 -1
  299. package/dist/internal/promote/assertion-promote-precommit.js +79 -22
  300. package/dist/internal/promote/assertion-promote-precommit.js.map +1 -1
  301. package/dist/internal/storage-ack-owned-request.d.ts +16 -0
  302. package/dist/internal/storage-ack-owned-request.d.ts.map +1 -0
  303. package/dist/internal/storage-ack-owned-request.js +16 -0
  304. package/dist/internal/storage-ack-owned-request.js.map +1 -0
  305. package/dist/internal/vm-reconcile-local-admission-wait.d.ts +96 -0
  306. package/dist/internal/vm-reconcile-local-admission-wait.d.ts.map +1 -0
  307. package/dist/internal/vm-reconcile-local-admission-wait.js +226 -0
  308. package/dist/internal/vm-reconcile-local-admission-wait.js.map +1 -0
  309. package/dist/internal/vm-reconcile-read-authority.d.ts +27 -0
  310. package/dist/internal/vm-reconcile-read-authority.d.ts.map +1 -0
  311. package/dist/internal/vm-reconcile-read-authority.js +33 -0
  312. package/dist/internal/vm-reconcile-read-authority.js.map +1 -0
  313. package/dist/internal/vm-reconcile-sweep-admission.d.ts +2 -0
  314. package/dist/internal/vm-reconcile-sweep-admission.d.ts.map +1 -1
  315. package/dist/internal/vm-reconcile-sweep.d.ts +16 -4
  316. package/dist/internal/vm-reconcile-sweep.d.ts.map +1 -1
  317. package/dist/internal/vm-reconcile-sweep.js +91 -50
  318. package/dist/internal/vm-reconcile-sweep.js.map +1 -1
  319. package/dist/internal/workspace-projected-delegatees.d.ts +3 -0
  320. package/dist/internal/workspace-projected-delegatees.d.ts.map +1 -0
  321. package/dist/internal/workspace-projected-delegatees.js +34 -0
  322. package/dist/internal/workspace-projected-delegatees.js.map +1 -0
  323. package/dist/join-approval-restart-projection.d.ts +14 -0
  324. package/dist/join-approval-restart-projection.d.ts.map +1 -0
  325. package/dist/join-approval-restart-projection.js +32 -0
  326. package/dist/join-approval-restart-projection.js.map +1 -0
  327. package/dist/keyed-persist-scheduler.d.ts +72 -0
  328. package/dist/keyed-persist-scheduler.d.ts.map +1 -0
  329. package/dist/keyed-persist-scheduler.js +140 -0
  330. package/dist/keyed-persist-scheduler.js.map +1 -0
  331. package/dist/map-with-concurrency.d.ts +7 -0
  332. package/dist/map-with-concurrency.d.ts.map +1 -1
  333. package/dist/map-with-concurrency.js +36 -0
  334. package/dist/map-with-concurrency.js.map +1 -1
  335. package/dist/p2p/network-admission-coordinator.d.ts +15 -0
  336. package/dist/p2p/network-admission-coordinator.d.ts.map +1 -1
  337. package/dist/p2p/network-admission-coordinator.js +20 -2
  338. package/dist/p2p/network-admission-coordinator.js.map +1 -1
  339. package/dist/p2p/peer-connect.d.ts +10 -1
  340. package/dist/p2p/peer-connect.d.ts.map +1 -1
  341. package/dist/p2p/peer-connect.js +11 -2
  342. package/dist/p2p/peer-connect.js.map +1 -1
  343. package/dist/p2p/peer-selection.d.ts +8 -0
  344. package/dist/p2p/peer-selection.d.ts.map +1 -1
  345. package/dist/p2p/peer-selection.js +21 -12
  346. package/dist/p2p/peer-selection.js.map +1 -1
  347. package/dist/p2p/protocol-readiness.d.ts +3 -3
  348. package/dist/p2p/protocol-readiness.d.ts.map +1 -1
  349. package/dist/p2p/protocol-readiness.js +4 -3
  350. package/dist/p2p/protocol-readiness.js.map +1 -1
  351. package/dist/prepare-unscoped-context-graph-read-checks.d.ts.map +1 -1
  352. package/dist/prepare-unscoped-context-graph-read-checks.js +12 -0
  353. package/dist/prepare-unscoped-context-graph-read-checks.js.map +1 -1
  354. package/dist/registered-context-graph-authority.d.ts +19 -0
  355. package/dist/registered-context-graph-authority.d.ts.map +1 -1
  356. package/dist/registered-private-empty-vm-attempt-v1.d.ts +34 -0
  357. package/dist/registered-private-empty-vm-attempt-v1.d.ts.map +1 -0
  358. package/dist/registered-private-empty-vm-attempt-v1.js +120 -0
  359. package/dist/registered-private-empty-vm-attempt-v1.js.map +1 -0
  360. package/dist/reserved-ka-id-allocation.d.ts +12 -0
  361. package/dist/reserved-ka-id-allocation.d.ts.map +1 -0
  362. package/dist/reserved-ka-id-allocation.js +25 -0
  363. package/dist/reserved-ka-id-allocation.js.map +1 -0
  364. package/dist/rfc64/applied-catalog-authority-transition-v1.d.ts.map +1 -1
  365. package/dist/rfc64/applied-catalog-authority-transition-v1.js +15 -17
  366. package/dist/rfc64/applied-catalog-authority-transition-v1.js.map +1 -1
  367. package/dist/rfc64/authority-rpc-circuit-breaker-v1.d.ts +5 -3
  368. package/dist/rfc64/authority-rpc-circuit-breaker-v1.d.ts.map +1 -1
  369. package/dist/rfc64/authority-rpc-circuit-breaker-v1.js +9 -0
  370. package/dist/rfc64/authority-rpc-circuit-breaker-v1.js.map +1 -1
  371. package/dist/rfc64/catalog-completion-evidence-v1.d.ts +38 -0
  372. package/dist/rfc64/catalog-completion-evidence-v1.d.ts.map +1 -0
  373. package/dist/rfc64/catalog-completion-evidence-v1.js +49 -0
  374. package/dist/rfc64/catalog-completion-evidence-v1.js.map +1 -0
  375. package/dist/rfc64/catalog-operational-applied-heads-v1.d.ts +12 -13
  376. package/dist/rfc64/catalog-operational-applied-heads-v1.d.ts.map +1 -1
  377. package/dist/rfc64/catalog-operational-applied-heads-v1.js +17 -52
  378. package/dist/rfc64/catalog-operational-applied-heads-v1.js.map +1 -1
  379. package/dist/rfc64/catalog-operational-reads-v1.d.ts +13 -0
  380. package/dist/rfc64/catalog-operational-reads-v1.d.ts.map +1 -0
  381. package/dist/rfc64/catalog-operational-reads-v1.js +56 -0
  382. package/dist/rfc64/catalog-operational-reads-v1.js.map +1 -0
  383. package/dist/rfc64/catalog-operational-targets-v1.d.ts +55 -0
  384. package/dist/rfc64/catalog-operational-targets-v1.d.ts.map +1 -0
  385. package/dist/rfc64/catalog-operational-targets-v1.js +379 -0
  386. package/dist/rfc64/catalog-operational-targets-v1.js.map +1 -0
  387. package/dist/rfc64/catalog-repair-diagnostics-v1.d.ts +28 -0
  388. package/dist/rfc64/catalog-repair-diagnostics-v1.d.ts.map +1 -0
  389. package/dist/rfc64/catalog-repair-diagnostics-v1.js +93 -0
  390. package/dist/rfc64/catalog-repair-diagnostics-v1.js.map +1 -0
  391. package/dist/rfc64/catalog-repair-retry-v1.d.ts +13 -0
  392. package/dist/rfc64/catalog-repair-retry-v1.d.ts.map +1 -0
  393. package/dist/rfc64/catalog-repair-retry-v1.js +39 -0
  394. package/dist/rfc64/catalog-repair-retry-v1.js.map +1 -0
  395. package/dist/rfc64/catalog-replay-recovery-runtime-v1.d.ts +52 -0
  396. package/dist/rfc64/catalog-replay-recovery-runtime-v1.d.ts.map +1 -1
  397. package/dist/rfc64/catalog-replay-recovery-runtime-v1.js +188 -32
  398. package/dist/rfc64/catalog-replay-recovery-runtime-v1.js.map +1 -1
  399. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.d.ts +2 -8
  400. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.d.ts.map +1 -1
  401. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.js +10 -37
  402. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.js.map +1 -1
  403. package/dist/rfc64/catalog-rollout-authority-v1.d.ts +13 -0
  404. package/dist/rfc64/catalog-rollout-authority-v1.d.ts.map +1 -1
  405. package/dist/rfc64/catalog-rollout-authority-v1.js +11 -0
  406. package/dist/rfc64/catalog-rollout-authority-v1.js.map +1 -1
  407. package/dist/rfc64/catalog-row-authorship.d.ts +12 -0
  408. package/dist/rfc64/catalog-row-authorship.d.ts.map +1 -1
  409. package/dist/rfc64/catalog-row-authorship.js +110 -57
  410. package/dist/rfc64/catalog-row-authorship.js.map +1 -1
  411. package/dist/rfc64/inventory-v1/candidate.d.ts +31 -10
  412. package/dist/rfc64/inventory-v1/candidate.d.ts.map +1 -1
  413. package/dist/rfc64/inventory-v1/candidate.js +51 -16
  414. package/dist/rfc64/inventory-v1/candidate.js.map +1 -1
  415. package/dist/rfc64/inventory-v1/index.d.ts +1 -1
  416. package/dist/rfc64/inventory-v1/index.d.ts.map +1 -1
  417. package/dist/rfc64/inventory-v1/index.js +1 -1
  418. package/dist/rfc64/inventory-v1/index.js.map +1 -1
  419. package/dist/rfc64/inventory-v1/open.d.ts.map +1 -1
  420. package/dist/rfc64/inventory-v1/open.js +7 -4
  421. package/dist/rfc64/inventory-v1/open.js.map +1 -1
  422. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.d.ts +3 -1
  423. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.d.ts.map +1 -1
  424. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.js +15 -0
  425. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.js.map +1 -1
  426. package/dist/rfc64/legacy-swm-boundary-codec-v1.d.ts +25 -0
  427. package/dist/rfc64/legacy-swm-boundary-codec-v1.d.ts.map +1 -0
  428. package/dist/rfc64/legacy-swm-boundary-codec-v1.js +127 -0
  429. package/dist/rfc64/legacy-swm-boundary-codec-v1.js.map +1 -0
  430. package/dist/rfc64/legacy-swm-boundary-v1.d.ts +12 -0
  431. package/dist/rfc64/legacy-swm-boundary-v1.d.ts.map +1 -1
  432. package/dist/rfc64/legacy-swm-boundary-v1.js +83 -144
  433. package/dist/rfc64/legacy-swm-boundary-v1.js.map +1 -1
  434. package/dist/rfc64/private-catalog-subscription-readiness-v1.d.ts +33 -0
  435. package/dist/rfc64/private-catalog-subscription-readiness-v1.d.ts.map +1 -0
  436. package/dist/rfc64/private-catalog-subscription-readiness-v1.js +97 -0
  437. package/dist/rfc64/private-catalog-subscription-readiness-v1.js.map +1 -0
  438. package/dist/rfc64/private-read-roster-v1.d.ts +14 -0
  439. package/dist/rfc64/private-read-roster-v1.d.ts.map +1 -0
  440. package/dist/rfc64/private-read-roster-v1.js +57 -0
  441. package/dist/rfc64/private-read-roster-v1.js.map +1 -0
  442. package/dist/rfc64/public-catalog-native-receiver-v1.d.ts.map +1 -1
  443. package/dist/rfc64/public-catalog-native-receiver-v1.js +26 -21
  444. package/dist/rfc64/public-catalog-native-receiver-v1.js.map +1 -1
  445. package/dist/rfc64/public-catalog-native-reconciler-v1.d.ts +17 -11
  446. package/dist/rfc64/public-catalog-native-reconciler-v1.d.ts.map +1 -1
  447. package/dist/rfc64/public-catalog-native-reconciler-v1.js +10 -8
  448. package/dist/rfc64/public-catalog-native-reconciler-v1.js.map +1 -1
  449. package/dist/rfc64/public-catalog-receiver-v1.d.ts +9 -0
  450. package/dist/rfc64/public-catalog-receiver-v1.d.ts.map +1 -1
  451. package/dist/rfc64/public-catalog-receiver-v1.js +11 -2
  452. package/dist/rfc64/public-catalog-receiver-v1.js.map +1 -1
  453. package/dist/rfc64/public-catalog-service-v1.d.ts.map +1 -1
  454. package/dist/rfc64/public-catalog-service-v1.js +21 -22
  455. package/dist/rfc64/public-catalog-service-v1.js.map +1 -1
  456. package/dist/rfc64/public-catalog-successor-producer-v1.d.ts.map +1 -1
  457. package/dist/rfc64/public-catalog-successor-producer-v1.js +5 -4
  458. package/dist/rfc64/public-catalog-successor-producer-v1.js.map +1 -1
  459. package/dist/rfc64/registered-private-empty-vm-proof-v1.d.ts +20 -0
  460. package/dist/rfc64/registered-private-empty-vm-proof-v1.d.ts.map +1 -0
  461. package/dist/rfc64/registered-private-empty-vm-proof-v1.js +26 -0
  462. package/dist/rfc64/registered-private-empty-vm-proof-v1.js.map +1 -0
  463. package/dist/rfc64/swm-catalog-durable-asset-resolver-v1.d.ts.map +1 -1
  464. package/dist/rfc64/swm-catalog-durable-asset-resolver-v1.js +60 -53
  465. package/dist/rfc64/swm-catalog-durable-asset-resolver-v1.js.map +1 -1
  466. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.d.ts +2 -1
  467. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.d.ts.map +1 -1
  468. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.js +44 -4
  469. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.js.map +1 -1
  470. package/dist/rfc64/swm-inventory-shadow-runtime-v1.d.ts +3 -1
  471. package/dist/rfc64/swm-inventory-shadow-runtime-v1.d.ts.map +1 -1
  472. package/dist/rfc64/swm-inventory-shadow-runtime-v1.js +34 -0
  473. package/dist/rfc64/swm-inventory-shadow-runtime-v1.js.map +1 -1
  474. package/dist/sync/auth/pipe-request-tail.d.ts +5 -1
  475. package/dist/sync/auth/pipe-request-tail.d.ts.map +1 -1
  476. package/dist/sync/auth/pipe-request-tail.js +13 -3
  477. package/dist/sync/auth/pipe-request-tail.js.map +1 -1
  478. package/dist/sync/auth/request-build.d.ts +3 -0
  479. package/dist/sync/auth/request-build.d.ts.map +1 -1
  480. package/dist/sync/auth/request-build.js +11 -2
  481. package/dist/sync/auth/request-build.js.map +1 -1
  482. package/dist/sync/backpressure.d.ts +27 -16
  483. package/dist/sync/backpressure.d.ts.map +1 -1
  484. package/dist/sync/backpressure.js +66 -40
  485. package/dist/sync/backpressure.js.map +1 -1
  486. package/dist/sync/catchup-policy.d.ts +2 -0
  487. package/dist/sync/catchup-policy.d.ts.map +1 -1
  488. package/dist/sync/catchup-policy.js +2 -0
  489. package/dist/sync/catchup-policy.js.map +1 -1
  490. package/dist/sync/exact-asset-fetch.d.ts +22 -0
  491. package/dist/sync/exact-asset-fetch.d.ts.map +1 -1
  492. package/dist/sync/exact-asset-fetch.js +30 -3
  493. package/dist/sync/exact-asset-fetch.js.map +1 -1
  494. package/dist/sync/exact-assets.d.ts +7 -5
  495. package/dist/sync/exact-assets.d.ts.map +1 -1
  496. package/dist/sync/exact-assets.js +13 -8
  497. package/dist/sync/exact-assets.js.map +1 -1
  498. package/dist/sync/exact-batch-observation.d.ts +3 -0
  499. package/dist/sync/exact-batch-observation.d.ts.map +1 -0
  500. package/dist/sync/exact-batch-observation.js +13 -0
  501. package/dist/sync/exact-batch-observation.js.map +1 -0
  502. package/dist/sync/exact-batch-stream-capability.d.ts +24 -0
  503. package/dist/sync/exact-batch-stream-capability.d.ts.map +1 -0
  504. package/dist/sync/exact-batch-stream-capability.js +88 -0
  505. package/dist/sync/exact-batch-stream-capability.js.map +1 -0
  506. package/dist/sync/exact-batch-stream-contract.d.ts +78 -0
  507. package/dist/sync/exact-batch-stream-contract.d.ts.map +1 -0
  508. package/dist/sync/exact-batch-stream-contract.js +206 -0
  509. package/dist/sync/exact-batch-stream-contract.js.map +1 -0
  510. package/dist/sync/on-connect/sync-on-connect.d.ts +1 -1
  511. package/dist/sync/on-connect/sync-on-connect.d.ts.map +1 -1
  512. package/dist/sync/on-connect/sync-on-connect.js +3 -3
  513. package/dist/sync/on-connect/sync-on-connect.js.map +1 -1
  514. package/dist/sync/on-demand-agents-phonebook.d.ts +162 -0
  515. package/dist/sync/on-demand-agents-phonebook.d.ts.map +1 -0
  516. package/dist/sync/on-demand-agents-phonebook.js +571 -0
  517. package/dist/sync/on-demand-agents-phonebook.js.map +1 -0
  518. package/dist/sync/peer-connection.d.ts.map +1 -1
  519. package/dist/sync/peer-connection.js +11 -2
  520. package/dist/sync/peer-connection.js.map +1 -1
  521. package/dist/sync/priority-admission-queue.d.ts +17 -0
  522. package/dist/sync/priority-admission-queue.d.ts.map +1 -1
  523. package/dist/sync/priority-admission-queue.js +58 -37
  524. package/dist/sync/priority-admission-queue.js.map +1 -1
  525. package/dist/sync/requester/admission-boundary.d.ts +12 -0
  526. package/dist/sync/requester/admission-boundary.d.ts.map +1 -0
  527. package/dist/sync/requester/admission-boundary.js +22 -0
  528. package/dist/sync/requester/admission-boundary.js.map +1 -0
  529. package/dist/sync/requester/durable-sync.d.ts +2 -1
  530. package/dist/sync/requester/durable-sync.d.ts.map +1 -1
  531. package/dist/sync/requester/durable-sync.js +3 -188
  532. package/dist/sync/requester/durable-sync.js.map +1 -1
  533. package/dist/sync/requester/exact-batch-stream-driver.d.ts +83 -0
  534. package/dist/sync/requester/exact-batch-stream-driver.d.ts.map +1 -0
  535. package/dist/sync/requester/exact-batch-stream-driver.js +299 -0
  536. package/dist/sync/requester/exact-batch-stream-driver.js.map +1 -0
  537. package/dist/sync/requester/exact-batch-stream.d.ts +72 -0
  538. package/dist/sync/requester/exact-batch-stream.d.ts.map +1 -0
  539. package/dist/sync/requester/exact-batch-stream.js +267 -0
  540. package/dist/sync/requester/exact-batch-stream.js.map +1 -0
  541. package/dist/sync/requester/exact-recovery-transport.d.ts +19 -0
  542. package/dist/sync/requester/exact-recovery-transport.d.ts.map +1 -0
  543. package/dist/sync/requester/exact-recovery-transport.js +3 -0
  544. package/dist/sync/requester/exact-recovery-transport.js.map +1 -0
  545. package/dist/sync/requester/finalized-swm-twin-reconciliation.js +12 -3
  546. package/dist/sync/requester/finalized-swm-twin-reconciliation.js.map +1 -1
  547. package/dist/sync/requester/graph-scoped-materialization.d.ts.map +1 -1
  548. package/dist/sync/requester/graph-scoped-materialization.js +61 -27
  549. package/dist/sync/requester/graph-scoped-materialization.js.map +1 -1
  550. package/dist/sync/requester/page-fetch.d.ts +7 -0
  551. package/dist/sync/requester/page-fetch.d.ts.map +1 -1
  552. package/dist/sync/requester/page-fetch.js +103 -49
  553. package/dist/sync/requester/page-fetch.js.map +1 -1
  554. package/dist/sync/requester/shared-memory-sync.d.ts +10 -5
  555. package/dist/sync/requester/shared-memory-sync.d.ts.map +1 -1
  556. package/dist/sync/requester/shared-memory-sync.js +149 -150
  557. package/dist/sync/requester/shared-memory-sync.js.map +1 -1
  558. package/dist/sync/requester/swm-materialization-memo.d.ts +12 -0
  559. package/dist/sync/requester/swm-materialization-memo.d.ts.map +1 -0
  560. package/dist/sync/requester/swm-materialization-memo.js +54 -0
  561. package/dist/sync/requester/swm-materialization-memo.js.map +1 -0
  562. package/dist/sync/requester/swm-recovery.d.ts +3 -29
  563. package/dist/sync/requester/swm-recovery.d.ts.map +1 -1
  564. package/dist/sync/requester/swm-recovery.js +11 -10
  565. package/dist/sync/requester/swm-recovery.js.map +1 -1
  566. package/dist/sync/requester/swm-snapshot-materializer.d.ts.map +1 -1
  567. package/dist/sync/requester/swm-snapshot-materializer.js +18 -0
  568. package/dist/sync/requester/swm-snapshot-materializer.js.map +1 -1
  569. package/dist/sync/requester/swm-target-executor.d.ts +6 -0
  570. package/dist/sync/requester/swm-target-executor.d.ts.map +1 -1
  571. package/dist/sync/requester/swm-target-executor.js +24 -3
  572. package/dist/sync/requester/swm-target-executor.js.map +1 -1
  573. package/dist/sync/requester/verified-asset-preparation.d.ts +9 -0
  574. package/dist/sync/requester/verified-asset-preparation.d.ts.map +1 -0
  575. package/dist/sync/requester/verified-asset-preparation.js +190 -0
  576. package/dist/sync/requester/verified-asset-preparation.js.map +1 -0
  577. package/dist/sync/responder/asset-metadata.d.ts +18 -0
  578. package/dist/sync/responder/asset-metadata.d.ts.map +1 -0
  579. package/dist/sync/responder/asset-metadata.js +27 -0
  580. package/dist/sync/responder/asset-metadata.js.map +1 -0
  581. package/dist/sync/responder/durable-data-request-policy.d.ts +2 -16
  582. package/dist/sync/responder/durable-data-request-policy.d.ts.map +1 -1
  583. package/dist/sync/responder/durable-data-request-policy.js +1 -31
  584. package/dist/sync/responder/durable-data-request-policy.js.map +1 -1
  585. package/dist/sync/responder/exact-asset-export-cache.d.ts +89 -0
  586. package/dist/sync/responder/exact-asset-export-cache.d.ts.map +1 -0
  587. package/dist/sync/responder/exact-asset-export-cache.js +550 -0
  588. package/dist/sync/responder/exact-asset-export-cache.js.map +1 -0
  589. package/dist/sync/responder/exact-batch-stream.d.ts +47 -0
  590. package/dist/sync/responder/exact-batch-stream.d.ts.map +1 -0
  591. package/dist/sync/responder/exact-batch-stream.js +151 -0
  592. package/dist/sync/responder/exact-batch-stream.js.map +1 -0
  593. package/dist/sync/responder/exact-data-session.d.ts +67 -0
  594. package/dist/sync/responder/exact-data-session.d.ts.map +1 -0
  595. package/dist/sync/responder/exact-data-session.js +130 -0
  596. package/dist/sync/responder/exact-data-session.js.map +1 -0
  597. package/dist/sync/responder/exact-graph-cursor-filter.d.ts +9 -0
  598. package/dist/sync/responder/exact-graph-cursor-filter.d.ts.map +1 -0
  599. package/dist/sync/responder/exact-graph-cursor-filter.js +101 -0
  600. package/dist/sync/responder/exact-graph-cursor-filter.js.map +1 -0
  601. package/dist/sync/responder/exact-graph-reader.d.ts +95 -0
  602. package/dist/sync/responder/exact-graph-reader.d.ts.map +1 -0
  603. package/dist/sync/responder/exact-graph-reader.js +623 -0
  604. package/dist/sync/responder/exact-graph-reader.js.map +1 -0
  605. package/dist/sync/responder/exact-page-reader.d.ts +37 -0
  606. package/dist/sync/responder/exact-page-reader.d.ts.map +1 -0
  607. package/dist/sync/responder/exact-page-reader.js +130 -0
  608. package/dist/sync/responder/exact-page-reader.js.map +1 -0
  609. package/dist/sync/responder/graph-plan.d.ts +19 -85
  610. package/dist/sync/responder/graph-plan.d.ts.map +1 -1
  611. package/dist/sync/responder/graph-plan.js +51 -988
  612. package/dist/sync/responder/graph-plan.js.map +1 -1
  613. package/dist/sync/responder/page-framing-policy.d.ts +31 -0
  614. package/dist/sync/responder/page-framing-policy.d.ts.map +1 -0
  615. package/dist/sync/responder/page-framing-policy.js +41 -0
  616. package/dist/sync/responder/page-framing-policy.js.map +1 -0
  617. package/dist/sync/responder/responder-row-page.d.ts +85 -0
  618. package/dist/sync/responder/responder-row-page.d.ts.map +1 -0
  619. package/dist/sync/responder/responder-row-page.js +181 -0
  620. package/dist/sync/responder/responder-row-page.js.map +1 -0
  621. package/dist/sync/responder/row-serialization.d.ts +34 -0
  622. package/dist/sync/responder/row-serialization.d.ts.map +1 -0
  623. package/dist/sync/responder/row-serialization.js +69 -0
  624. package/dist/sync/responder/row-serialization.js.map +1 -0
  625. package/dist/sync/responder/session-plan-memo.d.ts +20 -0
  626. package/dist/sync/responder/session-plan-memo.d.ts.map +1 -0
  627. package/dist/sync/responder/session-plan-memo.js +135 -0
  628. package/dist/sync/responder/session-plan-memo.js.map +1 -0
  629. package/dist/sync/responder/sync-handler.d.ts +26 -1
  630. package/dist/sync/responder/sync-handler.d.ts.map +1 -1
  631. package/dist/sync/responder/sync-handler.js +107 -58
  632. package/dist/sync/responder/sync-handler.js.map +1 -1
  633. package/dist/sync/shared-memory-completion.d.ts +30 -0
  634. package/dist/sync/shared-memory-completion.d.ts.map +1 -1
  635. package/dist/sync/shared-memory-completion.js +13 -0
  636. package/dist/sync/shared-memory-completion.js.map +1 -1
  637. package/dist/sync/system-context-graph-policy.d.ts +10 -0
  638. package/dist/sync/system-context-graph-policy.d.ts.map +1 -1
  639. package/dist/sync/system-context-graph-policy.js +11 -0
  640. package/dist/sync/system-context-graph-policy.js.map +1 -1
  641. package/dist/sync/wire-compression.d.ts +47 -0
  642. package/dist/sync/wire-compression.d.ts.map +1 -0
  643. package/dist/sync/wire-compression.js +111 -0
  644. package/dist/sync/wire-compression.js.map +1 -0
  645. package/dist/unscoped-query-consistency.d.ts +12 -0
  646. package/dist/unscoped-query-consistency.d.ts.map +1 -1
  647. package/dist/unscoped-query-consistency.js +17 -1
  648. package/dist/unscoped-query-consistency.js.map +1 -1
  649. package/dist/vm-promotion-audit.d.ts +2 -2
  650. package/dist/vm-promotion-audit.d.ts.map +1 -1
  651. package/dist/vm-promotion-audit.js +26 -9
  652. package/dist/vm-promotion-audit.js.map +1 -1
  653. package/dist/vm-publish-snapshot-preflight.d.ts +13 -0
  654. package/dist/vm-publish-snapshot-preflight.d.ts.map +1 -0
  655. package/dist/vm-publish-snapshot-preflight.js +94 -0
  656. package/dist/vm-publish-snapshot-preflight.js.map +1 -0
  657. package/dist/vm-reconcile-dispatcher.d.ts +42 -1
  658. package/dist/vm-reconcile-dispatcher.d.ts.map +1 -1
  659. package/dist/vm-reconcile-dispatcher.js +103 -4
  660. package/dist/vm-reconcile-dispatcher.js.map +1 -1
  661. package/dist/vm-reconcile-peer-topology.d.ts +7 -9
  662. package/dist/vm-reconcile-peer-topology.d.ts.map +1 -1
  663. package/dist/vm-reconcile-peer-topology.js +1 -37
  664. package/dist/vm-reconcile-peer-topology.js.map +1 -1
  665. package/dist/vm-recovery-candidate-order.d.ts +16 -0
  666. package/dist/vm-recovery-candidate-order.d.ts.map +1 -0
  667. package/dist/vm-recovery-candidate-order.js +24 -0
  668. package/dist/vm-recovery-candidate-order.js.map +1 -0
  669. package/dist/vm-recovery-core-transport-preference.d.ts +69 -0
  670. package/dist/vm-recovery-core-transport-preference.d.ts.map +1 -0
  671. package/dist/vm-recovery-core-transport-preference.js +131 -0
  672. package/dist/vm-recovery-core-transport-preference.js.map +1 -0
  673. package/dist/vm-recovery-experiment-policy.d.ts +24 -0
  674. package/dist/vm-recovery-experiment-policy.d.ts.map +1 -0
  675. package/dist/vm-recovery-experiment-policy.js +18 -0
  676. package/dist/vm-recovery-experiment-policy.js.map +1 -0
  677. package/dist/vm-recovery-footprint.d.ts +54 -0
  678. package/dist/vm-recovery-footprint.d.ts.map +1 -1
  679. package/dist/vm-recovery-footprint.js +88 -24
  680. package/dist/vm-recovery-footprint.js.map +1 -1
  681. package/dist/vm-recovery-microbatch.d.ts +2 -0
  682. package/dist/vm-recovery-microbatch.d.ts.map +1 -1
  683. package/dist/vm-recovery-microbatch.js +7 -3
  684. package/dist/vm-recovery-microbatch.js.map +1 -1
  685. package/dist/vm-recovery-pass-authority.d.ts +84 -0
  686. package/dist/vm-recovery-pass-authority.d.ts.map +1 -0
  687. package/dist/vm-recovery-pass-authority.js +126 -0
  688. package/dist/vm-recovery-pass-authority.js.map +1 -0
  689. package/dist/vm-recovery-phase-timing.d.ts +75 -0
  690. package/dist/vm-recovery-phase-timing.d.ts.map +1 -0
  691. package/dist/vm-recovery-phase-timing.js +236 -0
  692. package/dist/vm-recovery-phase-timing.js.map +1 -0
  693. package/dist/vm-recovery-preparation.d.ts +143 -0
  694. package/dist/vm-recovery-preparation.d.ts.map +1 -0
  695. package/dist/vm-recovery-preparation.js +433 -0
  696. package/dist/vm-recovery-preparation.js.map +1 -0
  697. package/dist/vm-recovery-provider-policy.d.ts +13 -1
  698. package/dist/vm-recovery-provider-policy.d.ts.map +1 -1
  699. package/dist/vm-recovery-provider-policy.js +37 -5
  700. package/dist/vm-recovery-provider-policy.js.map +1 -1
  701. package/dist/vm-recovery-stream-profile.d.ts +15 -0
  702. package/dist/vm-recovery-stream-profile.d.ts.map +1 -0
  703. package/dist/vm-recovery-stream-profile.js +53 -0
  704. package/dist/vm-recovery-stream-profile.js.map +1 -0
  705. package/dist/vm-recovery-stream-setback-policy.d.ts +54 -0
  706. package/dist/vm-recovery-stream-setback-policy.d.ts.map +1 -0
  707. package/dist/vm-recovery-stream-setback-policy.js +85 -0
  708. package/dist/vm-recovery-stream-setback-policy.js.map +1 -0
  709. package/dist/vm-recovery-timing-observer.d.ts +27 -0
  710. package/dist/vm-recovery-timing-observer.d.ts.map +1 -0
  711. package/dist/vm-recovery-timing-observer.js +49 -0
  712. package/dist/vm-recovery-timing-observer.js.map +1 -0
  713. package/dist/vm-recovery-transport-budget-policy.d.ts +32 -0
  714. package/dist/vm-recovery-transport-budget-policy.d.ts.map +1 -0
  715. package/dist/vm-recovery-transport-budget-policy.js +55 -0
  716. package/dist/vm-recovery-transport-budget-policy.js.map +1 -0
  717. package/dist/vm-recovery-transport-plan.d.ts +83 -0
  718. package/dist/vm-recovery-transport-plan.d.ts.map +1 -0
  719. package/dist/vm-recovery-transport-plan.js +117 -0
  720. package/dist/vm-recovery-transport-plan.js.map +1 -0
  721. package/dist/vm-refresh.d.ts +138 -0
  722. package/dist/vm-refresh.d.ts.map +1 -0
  723. package/dist/vm-refresh.js +201 -0
  724. package/dist/vm-refresh.js.map +1 -0
  725. package/package.json +19 -9
  726. package/dist/finalization-annotations.d.ts +0 -5
  727. package/dist/finalization-annotations.d.ts.map +0 -1
  728. package/dist/finalization-annotations.js +0 -6
  729. package/dist/finalization-annotations.js.map +0 -1
  730. package/dist/swm-ka-bound.d.ts +0 -21
  731. package/dist/swm-ka-bound.d.ts.map +0 -1
  732. package/dist/swm-ka-bound.js +0 -36
  733. package/dist/swm-ka-bound.js.map +0 -1
@@ -1,3 +1,6 @@
1
+ import { syncReconcilerEnabled, syncOnConnectEnabled, durableSyncEnabled } from './internal/lifecycle-sync-policy.js';
2
+ import { emptySwmRecoveryResult } from './sync/shared-memory-completion.js';
3
+ import { DurableSyncAdmissionBoundary } from './sync/requester/admission-boundary.js';
1
4
  import { createRandomSamplingEligibilityResolver } from './random-sampling-eligibility.js';
2
5
  import { RandomSamplingRuntime } from './random-sampling-runtime.js';
3
6
  import { startAuthorityIndexSnapshotRuntime } from './authority-index-snapshot-runtime.js';
@@ -12,10 +15,11 @@ import { startAuthorityIndexSnapshotRuntime } from './authority-index-snapshot-r
12
15
  import { traverseBoundedCuratorRoster, curatorRosterResolution, } from './bounded-curator-roster-traversal.js';
13
16
  import { setTimeout as waitForPeerEventTurn } from 'node:timers/promises';
14
17
  import { PeerSyncSession } from './sync/peer-sync-session.js';
18
+ import { captureExactBatchStreamRefusalScope } from './sync/exact-batch-stream-capability.js';
15
19
  import { createStorageACKRegistrationPlan } from './p2p/storage-ack-registrar.js';
16
20
  import { syncOpenedPeerConnection } from './sync/peer-connection.js';
17
21
  import { isLegacySyncGraphCandidateV1 } from './sync/legacy-sync-graph-candidate.js';
18
- import { ProtocolRouter, GossipSubManager, DKGEvent, LibP2PNetwork, PeerResolver, StubNetworkStateRegistry, PROTOCOL_ACCESS, PROTOCOL_PUBLISH, PROTOCOL_SYNC, PROTOCOL_SYNC_POOLED, PROTOCOL_SYNC_CHANGELOG, PROTOCOL_QUERY_REMOTE, PROTOCOL_GET_CIPHERTEXT_CHUNK, PROTOCOL_VERIFY_PROPOSAL, PROTOCOL_JOIN_REQUEST, PROTOCOL_NETWORK_IDENTITY, PROTOCOL_SWM_SENDER_KEY, PROTOCOL_SWM_UPDATE, PROTOCOL_SWM_SHARE_ACK, PROTOCOL_SWM_HOST_CATCHUP, PROTOCOL_MESSAGE, contextGraphDataGraphUri, contextGraphMetaGraphUri, contextGraphWorkspaceMetaGraphUri, contextGraphMetaUri, deriveCuratorDidFromCgId, SYSTEM_CONTEXT_GRAPHS, DKG_ONTOLOGY, GRAPH_KA_CONTENT_SCOPE_VERSION, validateSubGraphName, createOperationContext, isSafeIri, InMemoryMessageIdempotencyStore, InMemoryProtocolOutboxStore, assertBoundedProtocolOutboxStore, tripleContentV10, withRetry, } from '@origintrail-official/dkg-core';
22
+ import { ProtocolRouter, GossipSubManager, DKGEvent, registerExperimentalExactBatchResponder, LibP2PNetwork, PeerResolver, StubNetworkStateRegistry, PROTOCOL_ACCESS, PROTOCOL_PUBLISH, PROTOCOL_SYNC, PROTOCOL_SYNC_POOLED, PROTOCOL_SYNC_CHANGELOG, PROTOCOL_QUERY_REMOTE, PROTOCOL_GET_CIPHERTEXT_CHUNK, PROTOCOL_VERIFY_PROPOSAL, PROTOCOL_JOIN_REQUEST, PROTOCOL_NETWORK_IDENTITY, advertisesSyncProtocol, PROTOCOL_SWM_SENDER_KEY, PROTOCOL_SWM_UPDATE, PROTOCOL_SWM_SHARE_ACK, PROTOCOL_SWM_HOST_CATCHUP, PROTOCOL_MESSAGE, contextGraphDataGraphUri, contextGraphMetaGraphUri, contextGraphWorkspaceMetaGraphUri, contextGraphMetaUri, deriveCuratorDidFromCgId, SYSTEM_CONTEXT_GRAPHS, DKG_ONTOLOGY, GRAPH_KA_CONTENT_SCOPE_VERSION, validateSubGraphName, createOperationContext, isSafeIri, QuietRetryableHandlerError, InMemoryMessageIdempotencyStore, InMemoryProtocolOutboxStore, assertBoundedProtocolOutboxStore, tripleContentV10, withRetry, } from '@origintrail-official/dkg-core';
19
23
  import { GraphManager, asChangelogReader } from '@origintrail-official/dkg-storage';
20
24
  import { readChangelogDeltaPage } from './sync/responder/graph-plan.js';
21
25
  import { decodeChangelogRequest, encodeChangelogResponse } from './sync/changelog/wire.js';
@@ -28,9 +32,11 @@ import { PublishHandler, ChainEventPoller, AccessHandler, PublishJournal, Verify
28
32
  import { ethers } from 'ethers';
29
33
  import { QueryHandler, } from '@origintrail-official/dkg-query';
30
34
  import { repairCreatorPublicMetaProjections } from './context-graph-public-meta-repair.js';
35
+ import { METADATA_RELOCATION_STARTUP_BUDGET_MS } from './context-graph-metadata-relocation.js';
31
36
  import { startRandomSamplingExactRepair, } from './sync/recovery/random-sampling-exact-repair.js';
32
37
  import { reconcileConfiguredContextGraphMetadataV1, } from './configured-context-graph-metadata-reconciliation.js';
33
- import { confirmContextGraphMetadataV1 } from './context-graph-meta-confirmation.js';
38
+ import { confirmContextGraphMetadataV1, } from './context-graph-meta-confirmation.js';
39
+ import { resolveApprovedMemberAcceptanceDecision, } from './internal/context-graph-authority/approved-member-acceptance.js';
34
40
  import { MessageHandler } from './messaging.js';
35
41
  import { ed25519ToX25519Private } from './encryption.js';
36
42
  import { SyncVerifyWorker, } from './sync-verify-worker.js';
@@ -52,6 +58,7 @@ import { deleteSyncPageCheckpoint, fetchSyncPages, SyncPageSizeProfileCache, } f
52
58
  import { composeSyncWorkAdmission, createSyncFetchSharingIdentity, } from './sync/work-admission.js';
53
59
  import { createChallengePinnedExactAssetSelection, createUalOnlyExactAssetSelection, exactAssetUalsForSelection, exactAssetFilterKey, exactSyncPhaseAccumulationLimits, requireExactAssetSelection, } from './sync/exact-assets.js';
54
60
  import { runOversizeSweep } from './sync/oversize-sweep.js';
61
+ import { EXACT_SYNC_GZIP_ENCODING, resolveExactSyncGzipProfile } from './sync/wire-compression.js';
55
62
  import { MemorySyncCheckpointStore, } from './sync/checkpoint/state.js';
56
63
  import { DurableRecoveryRunner, } from './sync/durable-recovery-runner.js';
57
64
  import { createDurableSyncBudget, createDurableSyncFetchTimeoutMs, DURABLE_SYNC_SETTLEMENT_HEADROOM_MS, EXACT_RECOVERY_DURABLE_TRANSFER_TIMEOUT_MS, normalizeDurableSyncTimeoutMs, } from './sync/requester/durable-sync-budget.js';
@@ -61,25 +68,28 @@ import { mergeExactAssetResponderCapability, mergeExactDurableFetchDisposition,
61
68
  import { resolveSyncAgentsMeta, shouldWithholdAgentsDurableMeta } from './sync/agents-meta-policy.js';
62
69
  import { createSelectedSwmMetaRetentionBudget, } from './sync/selected-swm-meta-budget.js';
63
70
  import { sharedMemoryOwnershipKeyFromGraph, } from './sync/requester/shared-memory-sync.js';
64
- import { emptySharedMemorySyncResult as createEmptySharedMemorySyncResult, mergeFleetSharedMemoryDiagnostics, mergeSamePeerSharedMemoryDiagnostics, recordSharedMemoryPhaseFailure, } from './sync/shared-memory-diagnostics.js';
71
+ import { emptySharedMemorySyncResult, mergeSamePeerSharedMemoryDiagnostics, mergeFleetSharedMemoryDiagnostics, recordSharedMemoryPhaseFailure, } from './sync/shared-memory-diagnostics.js';
65
72
  import { createSelectedSwmMetaFetcher, } from './sync/selected-swm-meta-fetcher.js';
66
73
  import { runOrderedContextGraphSyncs, } from './sync/requester/ordered-sync.js';
67
74
  import { registerSyncHandler, resolveSyncResponderSnapshotPolicy, } from './sync/responder/sync-handler.js';
75
+ import { createExactBatchResponderBinding } from './sync/responder/exact-batch-stream.js';
76
+ import { exactBatchTransportOptions } from './sync/requester/exact-batch-stream.js';
77
+ import { runExactBatchStreamDriver } from './sync/requester/exact-batch-stream-driver.js';
68
78
  import { runSelectedSharedMemoryRetry, runRegistrySyncOnConnect, SyncOnConnectPostSyncError, } from './sync/on-connect/sync-on-connect.js';
69
79
  import { captureSyncOnConnectAttempt, } from './sync/on-connect/attempt-accounting.js';
70
80
  import { ReconciledSyncOnConnectPeerJobRunner } from './sync/on-connect/peer-job-runner.js';
71
81
  import { formatPrivateRecoverySkip, planPrivateRecoverySource, } from './sync/private-recovery-source-planner.js';
72
82
  import { mapWithConcurrency } from './map-with-concurrency.js';
73
83
  import { CATCHUP_MAX_CONCURRENT_PEER_SYNCS } from './sync/catchup-concurrency.js';
74
- import { FOREGROUND_CATCHUP_SYNC_PRIORITY, catchupAdmissionSource, runCatchupPlaneWithPolicy, runCatchupPlanesWithPolicy, } from './sync/catchup-policy.js';
84
+ import { FOREGROUND_CATCHUP_SYNC_PRIORITY, VM_RECOVERY_SYNC_PRIORITY, catchupAdmissionSource, runCatchupPlaneWithPolicy, runCatchupPlanesWithPolicy, } from './sync/catchup-policy.js';
75
85
  import { SwmCatchupPassTracker, catchupPassNowMs, resolveSwmCatchupPassConfig, runSwmCatchupContinuations, } from './sync/catchup-pass-policy.js';
76
86
  import { runSelectedSwmContinuations, } from './sync/selected-swm-continuation.js';
77
87
  import { projectRfc64SelectedSwmGraphSyncStatus, } from './sync/selected-swm-graph-sync-status.js';
78
88
  import { applySelectedSwmFreshnessResolution, } from './sync/shared-memory-freshness.js';
79
89
  import { classifyDurableProgress, createDurableSyncAccumulator, createFailedPeerDurableSyncResult, createIncompleteDurableSyncResult, durableSyncAccumulatorHasPeerTransportFailure, durableSyncAccumulatorHasTerminalBoundary, durableSyncAccumulatorFromResult, finalizeDurableSyncCompletion, markDurableTerminalBoundary, mergeDurableSyncAccumulatorInto, mergeDurableSyncResultIntoAccumulator, recordDurableSyncDiagnostics, } from './sync/durable-progress.js';
80
- import { getSyncBackpressureSnapshot, getSyncBackpressureBusyError, resolveBooleanSwitch, resolveSyncReconcilerEnabled, resolveSyncGlobalBackpressure, withGlobalSyncBackpressure, } from './sync/backpressure.js';
90
+ import { getSyncBackpressureSnapshot, getSyncBackpressureBusyError, resolveExactBatchStreamEnabled, resolveSyncGlobalBackpressure, syncAdmissionWouldBeRefused, withGlobalSyncBackpressure, } from './sync/backpressure.js';
81
91
  import { contextGraphPriority, countSyncPriorityClasses, normalizeSyncAdmissionSource, orderContextGraphIdsByPriority, syncPriorityClass, } from './sync/policy.js';
82
- import { automaticDurableSyncContextGraphs } from './sync/system-context-graph-policy.js';
92
+ import { automaticDurableSyncContextGraphs, systemContextGraphSyncOptionsOf, } from './sync/system-context-graph-policy.js';
83
93
  import { activeSyncAdmissionSource, monotonicNowMs, recordSyncAttempt, recordSyncAttemptRequestBytes, recordSyncAttemptResponseBytes, recordSyncOperationDuration, recordSyncOperationRejected, recordSyncSingleFlightJoin, syncAttemptAttributes, syncOperationRejectionReason, withSyncAdmissionSource, } from './sync/attempt-telemetry.js';
84
94
  // rc.9 PR-10: JoinApprovalRetryQueue removed — substrate outbox
85
95
  // (durable, SQLite-backed) replaces it. We keep a minimal local
@@ -96,6 +106,66 @@ const DEFAULT_MAX_REHYDRATED_SUBSCRIPTIONS = 64;
96
106
  const REHYDRATE_THROTTLE_BATCH = 8;
97
107
  /** Retry interval for a persisted-subscription activation that is waiting for a slot. */
98
108
  const REHYDRATION_ROLLING_RETRY_MS = 30_000;
109
+ /**
110
+ * How long startup rehydration waits on persisted rows' read authority before
111
+ * leaving the rest to background authority recovery (#2815). Override via
112
+ * `DKGAgentConfig.contextGraphSubscriptionRehydrationAuthorityBudgetMs` (0
113
+ * removes the budget).
114
+ */
115
+ const DEFAULT_REHYDRATION_STARTUP_AUTHORITY_BUDGET_MS = 10_000;
116
+ /** Longest delay a Node timer honours; a longer one fires after 1 ms. */
117
+ const MAX_REHYDRATION_AUTHORITY_BUDGET_MS = 2_147_483_647;
118
+ /** Stands in for an authority decision the startup budget stopped waiting for. */
119
+ const REHYDRATION_AUTHORITY_DEFERRED = Symbol('rehydration-authority-deferred');
120
+ /**
121
+ * Delays between attempts of a restarted join approval's metadata recovery
122
+ * after a transient failure; the last one repeats while the row stays
123
+ * restricted. One attempt is a single curator metadata fetch.
124
+ */
125
+ const JOIN_APPROVAL_METADATA_RECOVERY_RETRY_MS = Object.freeze([15_000, 30_000, 60_000, 120_000, 300_000]);
126
+ /**
127
+ * Wait `ms` unless the node stops first; resolves whether the wait completed.
128
+ * The listener is removed either way, so nothing stays attached to the
129
+ * node-lifetime signal.
130
+ */
131
+ function waitUnlessStopped(ms, stopSignal) {
132
+ return new Promise((resolve) => {
133
+ if (stopSignal?.aborted === true) {
134
+ resolve(false);
135
+ return;
136
+ }
137
+ const onStop = () => {
138
+ clearTimeout(timer);
139
+ resolve(false);
140
+ };
141
+ const timer = setTimeout(() => {
142
+ stopSignal?.removeEventListener('abort', onStop);
143
+ resolve(true);
144
+ }, ms);
145
+ timer.unref?.();
146
+ stopSignal?.addEventListener('abort', onStop, { once: true });
147
+ });
148
+ }
149
+ function startRehydrationAuthorityBudget(budgetMs) {
150
+ if (budgetMs === 0) {
151
+ return { spent: () => false, race: (decision) => decision, dispose: () => { } };
152
+ }
153
+ let spent = false;
154
+ let expire = () => { };
155
+ const expired = new Promise((resolve) => {
156
+ expire = () => resolve(REHYDRATION_AUTHORITY_DEFERRED);
157
+ });
158
+ const timer = setTimeout(() => {
159
+ spent = true;
160
+ expire();
161
+ }, budgetMs);
162
+ timer.unref?.();
163
+ return {
164
+ spent: () => spent,
165
+ race: (decision) => Promise.race([decision, expired]),
166
+ dispose: () => clearTimeout(timer),
167
+ };
168
+ }
99
169
  function rehydratedSubscriptionReachedSafeState(subscription) {
100
170
  return subscription.synced === true
101
171
  && subscription.metaSynced !== false
@@ -116,6 +186,7 @@ import { stripLiteral, } from './dkg-agent-utils.js';
116
186
  import { SYNC_BYTE_BUDGET_MAX_ROWS, SYNC_PAGE_SIZE, SYNC_REQUEST_PAGE_SIZE, SYNC_PAGE_RETRY_ATTEMPTS, SYNC_TOTAL_TIMEOUT_MS, SYNC_MIN_GRAPH_BUDGET_MS, SYNC_PAGE_TIMEOUT_MS, SYNC_ROUTER_ATTEMPTS, SYNC_PROTOCOL_CHECK_ATTEMPTS, SYNC_PROTOCOL_CHECK_DELAY_MS, SYNC_ACCESS_DENIED_MARKER, DEBUG_SYNC_PROGRESS, DEFAULT_SWM_TTL_MS, SWM_CLEANUP_INTERVAL_MS, SYNC_DENIED_RESPONSE, GOSSIP_DIAL_COOLDOWN_MS, GOSSIP_DIAL_TIMEOUT_MS, CATCHUP_ON_CONNECT_COOLDOWN_MS, SYNC_RECONNECT_FLAP_GRACE_MS, MESSAGE_OUTBOX_TICK_MS, AGENT_PROFILE_HEARTBEAT_MS, AGENT_PROFILE_STALE_THRESHOLD_MS, WARM_CORE_CONNECTIONS_ENABLED, WARM_CORE_RECONCILE_INTERVAL_MS, WARM_CORE_MAX, WARM_CORE_KEEPALIVE_TAG, WARM_CORE_DIAL_TIMEOUT_MS, BOOT_CHAIN_IDENTITY_TIMEOUT_MS, } from './dkg-agent-constants.js';
117
187
  import { chainAuthorityReadBudgetsOf } from './chain-authority-read-budgets.js';
118
188
  import { peekFinalizedAuthorityColdResolution } from './finalized-authority-cold-resolution.js';
189
+ import { AGENTS_PHONEBOOK_PRIME_MAX_DIALS, peekOnDemandAgentsPhonebook, } from './sync/on-demand-agents-phonebook.js';
119
190
  import { raceWithBootTimeout, isTransientBootChainError } from './dkg-agent-boot.js';
120
191
  import { normalizeContextGraphSubscriptionTransition, projectContextGraphSubscriptionPersistence, } from './context-graph-subscription-policy.js';
121
192
  import { partitionSupersededContextGraphNamePlaceholders } from './dkg-agent-cg-name-resolution.js';
@@ -126,7 +197,9 @@ import { normalizeAgentDid, inferAdapterPublisherAddress, } from './dkg-agent-he
126
197
  import { DKGAgentBase } from './dkg-agent-base.js';
127
198
  import { VmReconcileShutdownTimeoutError } from './vm-reconcile-service.js';
128
199
  import { ContextGraphMembershipPersistShutdownTimeoutError } from './context-graph-membership-persist-scheduler.js';
200
+ import { ContextGraphSubscriptionPersistShutdownTimeoutError } from './context-graph-subscription-persist-scheduler.js';
129
201
  import { createLocalContextGraphOriginMembershipRecord, } from './local-context-graph-provenance.js';
202
+ import { contextGraphReadAuthorityDependencyOf, unavailableContextGraphReadAuthorityDecision, } from './context-graph-read-authority.js';
130
203
  import { deterministicStartupJitterMs, scheduleAfterStartupJitter } from './startup-jitter.js';
131
204
  import { projectContextGraphDormancy, } from './context-graph-subscription-dormancy.js';
132
205
  import { activatePersistedContextGraphSubscription as activatePersistedContextGraphSubscriptionTransaction, recoverDeferredContextGraphSubscriptionAuthorities, } from './context-graph-subscription-authority-recovery.js';
@@ -135,34 +208,11 @@ import { isRfc64PrivateRecoveryOwnerV1, resolveRfc64PrivateRecoveryContextGraphI
135
208
  import { CONTEXT_GRAPH_AUTHORITY_RPC_SITES as CG_AUTH_RPC_SITES, withRpcUsageSite, } from '@origintrail-official/dkg-chain';
136
209
  import { rfc64ExecutionPlanAllowsLegacySyncV1, resolveRfc64RuntimeCatalogBootstrapConfigV1, } from './rfc64/public-catalog-activation-config-v1.js';
137
210
  import { reconcileRfc64CatalogAuthorityPlanV1 } from './rfc64/catalog-rollout-authority-reconciliation-v1.js';
138
- import { initializeRfc64LegacySwmBoundaryV1, prepareRfc64LateLegacySwmBoundaryV1, } from './rfc64/legacy-swm-boundary-v1.js';
211
+ import { initializeRfc64LegacySwmBoundaryV1, prepareRfc64LateLegacySwmBoundaryV1, retireRfc64LegacySwmAfterFinalizedVmV1, } from './rfc64/legacy-swm-boundary-v1.js';
212
+ import { projectPersistedJoinApprovals, } from './join-approval-restart-projection.js';
213
+ import { verifiedCuratorDialAddress } from './curator-dial-address.js';
139
214
  const DEFAULT_HOST_MODE_RECONCILE_JITTER_RATIO = 0.15;
140
215
  const RFC64_SELECTED_SWM_ADMISSION_PRIORITY = 2_000;
141
- function projectPersistedJoinApprovals(persistedMembershipRows, persistedContextGraphIds, localAgentAddresses) {
142
- const newestApprovalByContextGraph = new Map();
143
- for (const membership of persistedMembershipRows) {
144
- const principalId = membership.principalId.toLowerCase();
145
- if (membership.principalType !== 'agent' ||
146
- membership.status !== 'active' ||
147
- membership.source !== 'join-approved' ||
148
- !persistedContextGraphIds.has(membership.contextGraphId) ||
149
- !localAgentAddresses.has(principalId)) {
150
- continue;
151
- }
152
- const existing = newestApprovalByContextGraph.get(membership.contextGraphId);
153
- if (!existing || membership.updatedAt > existing.updatedAt) {
154
- newestApprovalByContextGraph.set(membership.contextGraphId, {
155
- principalId,
156
- updatedAt: membership.updatedAt,
157
- curatorPeerId: typeof membership.metadata?.['curatorPeerId'] === 'string' &&
158
- membership.metadata['curatorPeerId'].trim()
159
- ? membership.metadata['curatorPeerId'].trim()
160
- : undefined,
161
- });
162
- }
163
- }
164
- return newestApprovalByContextGraph;
165
- }
166
216
  function resolveAgentSyncGlobalBackpressure(config) {
167
217
  // `trackSyncContextGraph()` mutates this list when an Edge explicitly
168
218
  // subscribes or starts a foreground catch-up. Those operator-selected graphs
@@ -363,6 +413,8 @@ function syncPageFetchCoalescingKey(params) {
363
413
  params.assetUals === undefined ? null : exactAssetFilterKey(params.assetUals),
364
414
  params.returnAcceptedPrefixOnRetryableTransportFailure === true,
365
415
  params.requesterScope ?? null,
416
+ params.responseEncoding ?? null,
417
+ params.maxAcceptedBytes ?? null,
366
418
  params.maxAcceptedQuads ?? null,
367
419
  params.maxAcceptedHeapBytesEstimate ?? null,
368
420
  ]);
@@ -450,11 +502,14 @@ function contextGraphCatchupSingleFlightKey(params) {
450
502
  function durableSyncSingleFlightKey(params) {
451
503
  if (params.hasPhaseCallback
452
504
  || params.hasAtomicCommitCallback
505
+ || params.hasWorkStartedCallback
453
506
  || params.hasAccessDeniedCallback
454
507
  || params.hasSinceBatchIdResolver
455
508
  || params.hasSignal
456
509
  || params.hasCurrentFence
457
- || params.hasChallengePinnedSelection) {
510
+ || params.hasChallengePinnedSelection
511
+ || params.hasForcedFreshExactSession
512
+ || params.hasRegisteredPublicEvidence) {
458
513
  return null;
459
514
  }
460
515
  return syncSingleFlightKey('durable-sync', {
@@ -466,6 +521,7 @@ function durableSyncSingleFlightKey(params) {
466
521
  syncAgentsMeta: params.syncAgentsMeta,
467
522
  exactAssetUals: params.exactAssetUals ?? null,
468
523
  settlementSliceTimeoutMs: params.settlementSliceTimeoutMs ?? null,
524
+ exactRecoveryTransportMode: params.exactRecoveryTransportMode ?? 'stream-preferred',
469
525
  priority: params.priority ?? null,
470
526
  });
471
527
  }
@@ -766,42 +822,16 @@ async function authenticateDurableGraphScopedAsset(params) {
766
822
  signal?.removeEventListener('abort', abortFromOperation);
767
823
  }
768
824
  }
769
- function sameStringArray(a, b) {
770
- return a.length === b.length && a.every((value, index) => value === b[index]);
771
- }
772
- function syncReconcilerEnabled(config) {
773
- return resolveSyncReconcilerEnabled(config.syncReconcilerEnabled);
774
- }
775
- function syncOnConnectEnabled(config) {
776
- return resolveBooleanSwitch(config.syncOnConnectEnabled, 'DKG_SYNC_ON_CONNECT_ENABLED', true);
777
- }
778
- function durableSyncEnabled(config) {
779
- return resolveBooleanSwitch(config.durableSyncEnabled, 'DKG_DURABLE_SYNC_ENABLED', true);
780
- }
781
825
  /** OT-RFC-59 responder cap on the peer-controlled raw-scan limit (DoS bound). Honest
782
826
  * requesters send SYNC_PAGE_SIZE (500); the headroom tolerates larger legitimate pages. */
783
827
  const CHANGELOG_MAX_SCAN_LIMIT = 2000;
784
- function emptySharedMemorySyncResult() {
785
- return createEmptySharedMemorySyncResult();
786
- }
787
- function mergeSharedMemorySyncResults(a, b) {
788
- return {
789
- ...mergeSamePeerSharedMemoryDiagnostics(a, b),
790
- };
791
- }
792
- function emptySwmRecoveryResult() {
793
- return {
794
- replacedRoots: 0,
795
- replacedGraphs: 0,
796
- insertedDataQuads: 0,
797
- insertedMetaQuads: 0,
798
- droppedDataTriples: 0,
799
- readySnapshots: 0,
800
- totalSnapshots: 0,
801
- completed: true,
802
- };
828
+ function sameStringArray(a, b) {
829
+ return a.length === b.length && a.every((value, index) => value === b[index]);
803
830
  }
804
831
  export class LifecycleSyncMethods extends DKGAgentBase {
832
+ async retireLegacySwmAfterVerifiedVmTwin(input) {
833
+ await retireRfc64LegacySwmAfterFinalizedVmV1(this, input.contextGraphId, input.kaUal, String(input.assertionVersion), input.subGraphName);
834
+ }
805
835
  async retireFinalizedSwmTwinCandidate(candidate, ctx) {
806
836
  await this.publisher.clearPublishedKnowledgeAssetSwm(candidate.contextGraphId, {
807
837
  kind: 'named-lifecycle',
@@ -884,6 +914,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
884
914
  // lanes, and the changelog lane's legacy `runResync` fallback) reports
885
915
  // its attempts and bytes under this label without carrying it as a
886
916
  // parameter, so it can never reach a coalescing key.
917
+ admission.onWorkStarted?.();
887
918
  return await withSyncAdmissionSource(source, work);
888
919
  }
889
920
  catch (error) {
@@ -952,6 +983,20 @@ export class LifecycleSyncMethods extends DKGAgentBase {
952
983
  admissionBoundary.dispose();
953
984
  }
954
985
  }
986
+ /**
987
+ * Whether this node's sync admission would take an exact VM recovery fetch
988
+ * for the graph right now. A read of the limiter: nothing is claimed or
989
+ * queued, and the fetch must still handle a refusal.
990
+ */
991
+ vmRecoverySyncAdmissionAvailable(contextGraphId) {
992
+ return !syncAdmissionWouldBeRefused(resolveAgentSyncGlobalBackpressure(this.config), {
993
+ contextGraphId,
994
+ lane: 'durable',
995
+ priority: VM_RECOVERY_SYNC_PRIORITY,
996
+ priorityClass: syncPriorityClass(VM_RECOVERY_SYNC_PRIORITY),
997
+ source: 'vm-recovery',
998
+ });
999
+ }
955
1000
  async start() {
956
1001
  if (this.vmReconcileShutdownBlocked) {
957
1002
  throw new VmReconcileShutdownTimeoutError(DKGAgentBase.VM_RECONCILE_SHUTDOWN_TIMEOUT_MS);
@@ -959,6 +1004,9 @@ export class LifecycleSyncMethods extends DKGAgentBase {
959
1004
  if (this.contextGraphMembershipPersistenceShutdownBlocked) {
960
1005
  throw new ContextGraphMembershipPersistShutdownTimeoutError(DKGAgentBase.CONTEXT_GRAPH_MEMBERSHIP_PERSIST_SHUTDOWN_TIMEOUT_MS);
961
1006
  }
1007
+ if (this.contextGraphSubscriptionPersistenceShutdownBlocked) {
1008
+ throw new ContextGraphSubscriptionPersistShutdownTimeoutError(DKGAgentBase.CONTEXT_GRAPH_SUBSCRIPTION_PERSIST_SHUTDOWN_TIMEOUT_MS);
1009
+ }
962
1010
  if (this.started)
963
1011
  return;
964
1012
  this.storageACKRegistrationRuntime.retireCurrentGeneration();
@@ -977,9 +1025,13 @@ export class LifecycleSyncMethods extends DKGAgentBase {
977
1025
  await this.contextGraphSubscriptionRehydrationPromotionRuntime?.close();
978
1026
  this.rfc64BackgroundWorkDispatcherV1.reopen();
979
1027
  this.contextGraphMembershipPersistence.reopen();
1028
+ // stop() drained and closed subscription writes; a restarted agent admits
1029
+ // them again. Writes issued before the first start() left it open.
1030
+ this.contextGraphSubscriptionPersistence.reopenIfClosed();
980
1031
  // stop() aborts detached cold authority flights; a restarted agent admits
981
1032
  // new ones (the runtime is created lazily on first use otherwise).
982
1033
  peekFinalizedAuthorityColdResolution(this)?.reopen();
1034
+ peekOnDemandAgentsPhonebook(this)?.reopen();
983
1035
  this.vmReconcileRuntimeReady = false;
984
1036
  this.graphScopedStoreClosed = false;
985
1037
  this.coreHostRecordingGeneration += 1;
@@ -1090,13 +1142,22 @@ export class LifecycleSyncMethods extends DKGAgentBase {
1090
1142
  // Move what earlier builds left in ontology, using local metadata only,
1091
1143
  // before sync serving starts. Bare bindings of graphs this node doesn't
1092
1144
  // hold need a chain read; that pass runs once start completes and before
1093
- // every store discovery pass.
1145
+ // every store discovery pass. This pass is on the startup path, so it has
1146
+ // a time budget; candidates it doesn't reach are left to those passes.
1147
+ // Until one of them reaches every candidate (this one included), ontology
1148
+ // may still hold private rows, so peers are not served it.
1094
1149
  try {
1095
- await this.relocatePrivateContextGraphMetadata({ classifyOnChain: false });
1150
+ await this.relocatePrivateContextGraphMetadata({
1151
+ classifyOnChain: false,
1152
+ budgetMs: METADATA_RELOCATION_STARTUP_BUDGET_MS,
1153
+ });
1096
1154
  }
1097
1155
  catch (err) {
1098
1156
  this.log.warn(ctx, `Failed to relocate private context graph metadata out of the ontology graph: ${err instanceof Error ? err.message : String(err)}`);
1099
1157
  }
1158
+ if (this.contextGraphServingWithheld(SYSTEM_CONTEXT_GRAPHS.ONTOLOGY)) {
1159
+ this.log.warn(ctx, 'Not serving the ontology graph to peers until the context graph metadata relocation reaches every candidate');
1160
+ }
1100
1161
  // Load registered agents from triple store; auto-register default if none exist.
1101
1162
  // loadAgentsFromStore restores defaultAgentAddress from the persisted
1102
1163
  // isDefaultAgent marker, avoiding reliance on SPARQL result ordering.
@@ -1273,11 +1334,17 @@ export class LifecycleSyncMethods extends DKGAgentBase {
1273
1334
  this.messenger.setOutboxResponseHandler(PROTOCOL_JOIN_REQUEST, async (result) => {
1274
1335
  await this.handleJoinRequestOutboxResponse(result);
1275
1336
  });
1337
+ // Snapshot live intent before any durable read or detached persistence
1338
+ // completion. Durable rows claim their part of this startup plan below.
1339
+ const liveIntents = [...this.subscribedContextGraphs].filter(([, subscription]) => subscription.subscribed && !subscription.pendingMeta);
1276
1340
  this.gossip = new GossipSubManager(this.node, this.eventBus, {
1277
1341
  networkId: this.config.networkIdentity?.networkId,
1278
1342
  chainId: this.config.networkIdentity?.chainId,
1279
1343
  isPeerAccepted: (peerId) => this.networkAdmissionCoordinator.isAcceptedPeer(peerId),
1280
1344
  });
1345
+ for (const [id, subscription] of liveIntents) {
1346
+ this.gossipSession.startupLiveIntents.set(id, { syncMode: subscription.syncMode });
1347
+ }
1281
1348
  await this.loadSwmSenderKeyState();
1282
1349
  await this.initializeSwmHostModeStore();
1283
1350
  await this.rehydrateContextGraphsFromDurableState();
@@ -1324,6 +1391,11 @@ export class LifecycleSyncMethods extends DKGAgentBase {
1324
1391
  // error, so private/curated/unregistered CGs remain denied.
1325
1392
  const queryRemoteHandler = new QueryHandler(this.queryEngine, queryAccessConfig, {
1326
1393
  isContextGraphPublic: (contextGraphId) => withRpcUsageSite(CG_AUTH_RPC_SITES.remoteQuery, () => this.isContextGraphPublicOnChain(contextGraphId, createOperationContext('query'))),
1394
+ // A graph held back from sync is not queried either, for an operator
1395
+ // whose queryAccess opens it (see contextGraphServingWithheld). The
1396
+ // handler applies this to the id its access policy and lookups use,
1397
+ // once it has checked that id is a string.
1398
+ servingWithheld: (contextGraphId) => this.contextGraphServingWithheld(contextGraphId),
1327
1399
  });
1328
1400
  // rc.9 PR-9: PROTOCOL_QUERY_REMOTE migrated onto the Universal
1329
1401
  // Messenger substrate. Wire prefix bumped to /dkg/10.0.1/* (hard
@@ -1681,6 +1753,29 @@ export class LifecycleSyncMethods extends DKGAgentBase {
1681
1753
  await this.handleKARegisteredNudge(onChainId, kaId, ctx, signal);
1682
1754
  }
1683
1755
  : undefined,
1756
+ // #2858 — refresh nudge for KA updates. An update keeps the KA id and
1757
+ // moves its root, and the sweep never revisits a settled ordinal, so a
1758
+ // node holding only a confirmed VM copy learns of the new version here.
1759
+ // Decided from local state; a V10 KA is its own batch, so the event's
1760
+ // batch id is the KA id. The event's block keeps a chain read that
1761
+ // has not seen the update from settling the refresh, and its
1762
+ // transaction spares a check of the publisher's own copy. A nudge that
1763
+ // fails holds the lane, and the lane never persists its cursor past
1764
+ // an unsettled refresh, so a restart replays that update.
1765
+ onCollectionUpdated: this.vmReconcileEnabled()
1766
+ ? async ({ batchId, merkleRoot, blockNumber, txHash, logIndex, blockHash, signal }) => {
1767
+ await this.handleKAUpdatedNudge(batchId, merkleRoot, ctx, {
1768
+ blockNumber,
1769
+ ...(txHash === undefined ? {} : { txHash }),
1770
+ ...(logIndex === undefined ? {} : { logIndex }),
1771
+ ...(blockHash === undefined ? {} : { blockHash }),
1772
+ signal,
1773
+ });
1774
+ }
1775
+ : undefined,
1776
+ collectionUpdatesPersistCeiling: this.vmReconcileEnabled()
1777
+ ? () => this.vmRefreshPersistCeiling()
1778
+ : undefined,
1684
1779
  });
1685
1780
  await this.chainPoller.start();
1686
1781
  this.log.info(ctx, `Chain event poller started`);
@@ -1853,13 +1948,37 @@ export class LifecycleSyncMethods extends DKGAgentBase {
1853
1948
  peerId: this.peerId,
1854
1949
  parseSyncRequest: this.parseSyncRequest.bind(this),
1855
1950
  authorizeSyncRequest: this.authorizeSyncRequest.bind(this),
1951
+ onExperimentalExactBatchResources: resolveExactBatchStreamEnabled()
1952
+ && this.config.nodeRole === 'core'
1953
+ ? (resources) => {
1954
+ const binding = createExactBatchResponderBinding({
1955
+ localPeerId: this.peerId,
1956
+ store: this.store,
1957
+ exportCache: resources.exportCache,
1958
+ admission: resources,
1959
+ parseSyncRequest: this.parseSyncRequest.bind(this),
1960
+ authorizeSyncRequest: this.authorizeSyncRequest.bind(this),
1961
+ isPublicContextGraph: async (cg, signal) => (await this.resolveRegisteredContextGraphAuthority(cg, {
1962
+ authorityReadMode: 'finalized-index-or-live', signal,
1963
+ })).kind === 'public',
1964
+ servingWithheld: (cg) => this.contextGraphServingWithheld(cg),
1965
+ onExport: (assetIndex, wholePayloadExports, operationContext) => this.log.info(operationContext, `Exact batch responder export asset=${assetIndex} wholePayloadExports=${wholePayloadExports}`),
1966
+ onPayload: (assetIndex, plainBytes, encodedBytes, operationContext) => this.log.info(operationContext, `Exact batch responder payload asset=${assetIndex} plainBytes=${plainBytes} encodedBytes=${encodedBytes}`),
1967
+ onFallback: (reason, assetIndex, operationContext, budgetReason) => this.log.info(operationContext, `Exact batch responder refusal asset=${assetIndex} reason=${reason}${budgetReason ? ` budgetReason=${budgetReason}` : ''}`),
1968
+ onStage: (stage, assetIndex, durationMs, operationContext) => this.log.info(operationContext, `Exact batch responder stage=${stage} asset=${assetIndex} durationMs=${durationMs.toFixed(3)}`),
1969
+ });
1970
+ registerExperimentalExactBatchResponder(this.router, exactBatchTransportOptions(120_000), binding.authorizeRequest, binding.respond);
1971
+ }
1972
+ : undefined,
1856
1973
  // Serve-skip policy (#1233): withhold the no-consumer agents/_meta snapshot
1857
1974
  // unless the operator opts in. This is the env boundary — the pure
1858
1975
  // `shouldWithholdAgentsDurableMeta` resolver is called directly with a FRESH
1859
1976
  // `process.env.DKG_SERVE_AGENTS_META` read per request, so the kill-switch is
1860
1977
  // reversible at runtime (no restart).
1861
1978
  shouldWithholdDurableMeta: (contextGraphId) => shouldWithholdAgentsDurableMeta(contextGraphId, process.env.DKG_SERVE_AGENTS_META),
1979
+ servingWithheld: (contextGraphId) => this.contextGraphServingWithheld(contextGraphId),
1862
1980
  logWarn: (ctx, message) => this.log.warn(ctx, message),
1981
+ logInfo: (ctx, message) => this.log.info(ctx, message),
1863
1982
  logDebug: (ctx, message) => this.log.debug(ctx, message),
1864
1983
  snapshotBudget: snapshotPolicy.budget,
1865
1984
  contextGraphPriorities: this.config.syncContextGraphPriorities,
@@ -1965,7 +2084,16 @@ export class LifecycleSyncMethods extends DKGAgentBase {
1965
2084
  role: 'participant',
1966
2085
  status: 'active',
1967
2086
  source: 'join-approved',
1968
- metadata: { curatorPeerId: peerId.toString() },
2087
+ metadata: {
2088
+ curatorPeerId: peerId.toString(),
2089
+ // The approved sender's own listener address is a durable
2090
+ // transport hint. An inbound remoteAddr can be an ephemeral
2091
+ // source port, so it is never persisted for restart dialing.
2092
+ ...(() => {
2093
+ const address = verifiedCuratorDialAddress(payload.curatorDialAddress, peerId.toString());
2094
+ return address ? { curatorDialAddress: address } : {};
2095
+ })(),
2096
+ },
1969
2097
  };
1970
2098
  // Commit the restart contract before changing live subscription
1971
2099
  // state. The two stores do not expose a shared transaction, so the
@@ -2229,6 +2357,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
2229
2357
  for (const systemContextGraph of [SYSTEM_CONTEXT_GRAPHS.AGENTS, SYSTEM_CONTEXT_GRAPHS.ONTOLOGY]) {
2230
2358
  this.subscribeToContextGraph(systemContextGraph, { syncMode: 'always-on' });
2231
2359
  }
2360
+ this.applyStartupContextGraphGossipPlan();
2232
2361
  // Connect to bootstrap peers
2233
2362
  if (this.config.bootstrapPeers) {
2234
2363
  for (const addr of this.config.bootstrapPeers) {
@@ -2445,6 +2574,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
2445
2574
  // this is now the only outbox tick — chat (PR-3) and every
2446
2575
  // future migrated protocol drain on the same cadence so
2447
2576
  // operators see a single "outbox tick" beat.
2577
+ let senderKeyRetryInFlight = false;
2448
2578
  this.messengerOutboxTimer = setInterval(() => {
2449
2579
  const now = Date.now();
2450
2580
  this.messenger.processOutboxTick(now)
@@ -2460,6 +2590,25 @@ export class LifecycleSyncMethods extends DKGAgentBase {
2460
2590
  `msgId=${entry.messageId.slice(0, 8)} lastError="${entry.lastError}"`);
2461
2591
  }
2462
2592
  });
2593
+ // A retryable ACK is a delivered Messenger response, so it has no
2594
+ // outbox obligation. The sender-key queue owns that retry and must
2595
+ // progress even if both peers stay connected and no further share is
2596
+ // published. Keep one pass in flight and reuse its current-authority
2597
+ // recipient check before every resend.
2598
+ if (!senderKeyRetryInFlight && this.pendingSenderKeyByAgent.size > 0) {
2599
+ senderKeyRetryInFlight = true;
2600
+ void this.drainPendingSenderKeysForConnectedPeers()
2601
+ .then((drained) => {
2602
+ if (drained > 0) {
2603
+ this.log.info(ctx, `Sender-key retry delivered ${drained} pending package(s)`);
2604
+ }
2605
+ })
2606
+ .catch((err) => {
2607
+ const message = err instanceof Error ? err.message : String(err);
2608
+ this.log.warn(ctx, `Sender-key retry tick failed: ${message}`);
2609
+ })
2610
+ .finally(() => { senderKeyRetryInFlight = false; });
2611
+ }
2463
2612
  }, MESSAGE_OUTBOX_TICK_MS);
2464
2613
  if (this.messengerOutboxTimer.unref)
2465
2614
  this.messengerOutboxTimer.unref();
@@ -2578,6 +2727,12 @@ export class LifecycleSyncMethods extends DKGAgentBase {
2578
2727
  // Malformed peer bytes → deny (mirrors the legacy lane's parse-fail path).
2579
2728
  return encodeChangelogResponse({ kind: 'denied' });
2580
2729
  }
2730
+ // A graph held back from the legacy lane is held back here too. The
2731
+ // requester falls back to that lane, which refuses it the same way, and
2732
+ // retries on a later round.
2733
+ if (this.contextGraphServingWithheld(request.contextGraphId)) {
2734
+ throw new QuietRetryableHandlerError(`"${request.contextGraphId}" is not served yet`);
2735
+ }
2581
2736
  // Same per-CG gate as PROTOCOL_SYNC: public CGs are open (returns true),
2582
2737
  // private CGs verify the signed digest — a bare (unsigned) changelog request
2583
2738
  // carries no digest, so `authorizePrivateSyncRequest` denies it. Any throw on a
@@ -2707,6 +2862,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
2707
2862
  this.warmedCores.delete(remotePeer);
2708
2863
  this.warmCoreFailedUnpins.delete(remotePeer);
2709
2864
  this.vmReconcileExactPeerCapabilities?.delete(remotePeer);
2865
+ this.vmReconcilePublicCoreTransportPreferencePolicy?.forgetPeer(remotePeer);
2710
2866
  }
2711
2867
  queueSelectedSwmFromPeerOnConnect(remotePeer, handleSyncError, delayMs = 3000) {
2712
2868
  const selectedContextGraphIds = this.selectedSwmBootstrapContextGraphIdsForPeer(remotePeer);
@@ -2931,7 +3087,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
2931
3087
  const sharedMemoryRecoveryContextGraphIds = [...new Set([
2932
3088
  ...(this.config.syncContextGraphs ?? []),
2933
3089
  ...namedSubgraphCompatibilityContextGraphIds,
2934
- ...resolveRfc64PrivateRecoveryContextGraphIdsV1(resolveRfc64RuntimeCatalogBootstrapConfigV1(this.config.rfc64CatalogBootstrap, this.config.rfc64PublicCatalogBootstrap)).filter((contextGraphId) => this.resolveRfc64CatalogReceiverAuthorityV1(contextGraphId).legacySyncAllowed),
3090
+ ...resolveRfc64PrivateRecoveryContextGraphIdsV1(resolveRfc64RuntimeCatalogBootstrapConfigV1(this.config.rfc64CatalogBootstrap, this.config.rfc64PublicCatalogBootstrap)).filter((contextGraphId) => this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId)),
2935
3091
  ])];
2936
3092
  const remotePeerIsCompleteSwmProvider = acceptedPolicies.some(({ completeSwmProviders = [] }) => completeSwmProviders.includes(remotePeer));
2937
3093
  const selectedPublicContextGraphIds = new Set(this.selectedSwmBootstrapContextGraphIdsForPeer(remotePeer));
@@ -2948,11 +3104,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
2948
3104
  getPeerProtocols: (peerId) => this.getPeerProtocols(peerId),
2949
3105
  peerCapabilities: this.peerCapabilityRegistry,
2950
3106
  getSyncContextGraphs: () => this.config.syncContextGraphs ?? [],
2951
- getDurableSyncContextGraphs: () => automaticDurableSyncContextGraphs(this.config.syncContextGraphs ?? [], {
2952
- nodeRole: this.config.nodeRole,
2953
- configValue: this.config.syncSystemContextGraphsOnConnect,
2954
- envValue: process.env.DKG_SYNC_SYSTEM_CONTEXT_GRAPHS_ON_CONNECT,
2955
- }).filter((contextGraphId) => {
3107
+ getDurableSyncContextGraphs: () => automaticDurableSyncContextGraphs(this.config.syncContextGraphs ?? [], systemContextGraphSyncOptionsOf(this.config)).filter((contextGraphId) => {
2956
3108
  const completeSwmProviders = this.resolveRfc64CompleteSwmProviderPeerIdsV1(contextGraphId);
2957
3109
  // For an RFC-64 selected public CG, VM/durable inventory is chain/core
2958
3110
  // territory. An Edge that was pinned as the complete SWM source must
@@ -3142,10 +3294,9 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3142
3294
  this.log.debug(ctx, `Skipping SWM sync for "${contextGraphId}": superseded by cleartext adoption of "${supersedingId}"`);
3143
3295
  continue;
3144
3296
  }
3145
- const authority = this.resolveRfc64CatalogReceiverAuthorityV1(contextGraphId);
3146
3297
  const completeSwmProviders = this.resolveRfc64CompleteSwmProviderPeerIdsV1(contextGraphId);
3147
3298
  const acceptedRecoveryLane = resolveRfc64SwmRecoveryLaneV1(resolveRfc64RuntimeCatalogBootstrapConfigV1(this.config.rfc64CatalogBootstrap, this.config.rfc64PublicCatalogBootstrap), contextGraphId);
3148
- const legacyRootSyncAllowed = authority.legacySyncAllowed;
3299
+ const legacyRootSyncAllowed = this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId);
3149
3300
  const namedSubgraphCompatibilityRequired = !legacyRootSyncAllowed
3150
3301
  && this.subscribedContextGraphs.get(contextGraphId)?.subscribed === true;
3151
3302
  if (!legacyRootSyncAllowed && !namedSubgraphCompatibilityRequired) {
@@ -3253,7 +3404,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3253
3404
  * leaves a peer permanently in `skippedNoSyncPeers`. libp2p emits
3254
3405
  * `peer:update` whenever a peer record changes — most importantly when
3255
3406
  * identify completes and the protocol list gets populated for the
3256
- * first time. If the new list now contains `PROTOCOL_SYNC` and we
3407
+ * first time. If the new list now contains either sync id and we
3257
3408
  * previously skipped this peer for that exact reason, fire one
3258
3409
  * `trySyncFromPeer` immediately.
3259
3410
  *
@@ -3283,7 +3434,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3283
3434
  return;
3284
3435
  if (!syncOnConnectEnabled(this.config))
3285
3436
  return;
3286
- if (!protocols.includes(PROTOCOL_SYNC))
3437
+ if (!advertisesSyncProtocol(protocols))
3287
3438
  return;
3288
3439
  const ctx = createOperationContext('sync');
3289
3440
  void peerEvents.run(() => this.retrySyncAfterPeerUpdate(peerId, ctx, peerEvents), (error) => this.log.warn(ctx, `Sync retry after peer:update failed for ${peerId.slice(-8)}: ${error instanceof Error ? error.message : String(error)}`));
@@ -3305,7 +3456,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3305
3456
  * Periodic reconciler for sync-on-connect. Walks every currently
3306
3457
  * connected peer and retries `trySyncFromPeer` for any that either:
3307
3458
  *
3308
- * - is in {@link skippedNoSyncPeers} and now advertises `PROTOCOL_SYNC`
3459
+ * - is in {@link skippedNoSyncPeers} and now advertises either sync id
3309
3460
  * (covers the case where the `peer:update` listener missed the
3310
3461
  * event for whatever reason), or
3311
3462
  * - has no recent clean success or useful-progress cooldown marker, or
@@ -3524,13 +3675,14 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3524
3675
  const isShardingTableMember = this.chain.isShardingTableMember?.bind(this.chain);
3525
3676
  if (!getIdentityIdForAddress || !isShardingTableMember)
3526
3677
  return true; // gate unavailable
3527
- // A legacy/mixed-version core profile may not carry an operational wallet.
3528
- // Discovery elsewhere supports profiles without `agentAddress`, so treat
3529
- // its absence as "gate unavailable" (fall back to phonebook nodeRole)
3530
- // rather than a hard denial — otherwise the warm set can collapse to zero
3531
- // in a network with healthy but pre-agentAddress cores.
3678
+ // Profiles are unsigned: a `nodeRole='core'` profile without an
3679
+ // operational wallet cannot be checked against the ShardingTable, so it is
3680
+ // as unverifiable as a failed read and is not pinned. Every profile this
3681
+ // codebase publishes carries `agentAddress`; on Base mainnet (2026-09-23)
3682
+ // 62 of 63 core-role profiles did, and the one that did not was pinned and
3683
+ // then failed its dial on every tick.
3532
3684
  if (!agentAddress)
3533
- return true; // gate unavailable for this profile
3685
+ return false;
3534
3686
  try {
3535
3687
  const identityId = await getIdentityIdForAddress(agentAddress);
3536
3688
  if (identityId === 0n)
@@ -3669,6 +3821,27 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3669
3821
  const result = await this.syncFromPeerDetailed(remotePeerId, contextGraphIds, onPhase, onAccessDenied, undefined, options);
3670
3822
  return result.insertedTriples;
3671
3823
  }
3824
+ /** One agent-owned admission decision for the legacy shared-memory lane. */
3825
+ async canUseLegacySharedMemorySyncForContextGraphV1(contextGraphId) {
3826
+ // The private predicate verifies local membership and current lane authority.
3827
+ return this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId)
3828
+ || await this.rfc64PrivateRootSwmOnLegacyLaneV1(contextGraphId) === true;
3829
+ }
3830
+ /** One agent-owned admission decision for the legacy durable VM lane. */
3831
+ async canUseLegacyDurableSyncForContextGraphV1(contextGraphId) {
3832
+ // The global emergency stop restores the legacy VM lane even for a
3833
+ // selected catalog graph whose persisted receiver policy remains catalog.
3834
+ if (this.config.rfc64CatalogExecutionPlan.killSwitchActive)
3835
+ return true;
3836
+ if (this.resolveRfc64CatalogReceiverAuthorityV1(contextGraphId).legacySyncAllowed) {
3837
+ return true;
3838
+ }
3839
+ // An approved private member keeps this compatibility lane while its
3840
+ // RFC-64 private receiver authority is inactive. The predicate performs
3841
+ // the authenticated local member proof; outsiders remain excluded.
3842
+ return typeof this.rfc64PrivateRootSwmOnLegacyLaneV1 === 'function'
3843
+ && await this.rfc64PrivateRootSwmOnLegacyLaneV1(contextGraphId) === true;
3844
+ }
3672
3845
  async syncFromPeerDetailed(remotePeerId, contextGraphIds, onPhase, onAccessDenied,
3673
3846
  // Phase C — optional gap-safe per-CG delta high-water mark resolver. Backed
3674
3847
  // by a CONTIGUOUS watermark when supplied; omitted ⇒ full scan (default).
@@ -3679,7 +3852,8 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3679
3852
  return createIncompleteDurableSyncResult();
3680
3853
  }
3681
3854
  const requestedContextGraphCount = contextGraphIds.length;
3682
- contextGraphIds = contextGraphIds.filter((contextGraphId) => (this.resolveRfc64CatalogReceiverAuthorityV1(contextGraphId).legacySyncAllowed));
3855
+ const legacyDurableAllowed = await Promise.all(contextGraphIds.map((contextGraphId) => LifecycleSyncMethods.prototype.canUseLegacyDurableSyncForContextGraphV1.call(this, contextGraphId)));
3856
+ contextGraphIds = contextGraphIds.filter((_, index) => legacyDurableAllowed[index]);
3683
3857
  if (contextGraphIds.length !== requestedContextGraphCount) {
3684
3858
  this.log.debug(ctx, `Skipped ${requestedContextGraphCount - contextGraphIds.length} catalog-authoritative CG(s) from legacy durable sync`);
3685
3859
  }
@@ -3735,6 +3909,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3735
3909
  return (await LifecycleSyncMethods.prototype.runLegacyDurableSyncDetailed.call(this, ctx, remotePeerId, contextGraphIds, onPhase, onAccessDenied, sinceBatchIdFor, options)).result;
3736
3910
  }
3737
3911
  async runLegacyDurableSyncDetailed(ctx, remotePeerId, contextGraphIds, onPhase, onAccessDenied, sinceBatchIdFor, options) {
3912
+ const admissionBoundary = new DurableSyncAdmissionBoundary(options?.onWorkStarted);
3738
3913
  const syncAgentsMeta = resolveSyncAgentsMeta(this.config.syncAgentsMeta, process.env.DKG_SYNC_AGENTS_META);
3739
3914
  const stopOnBackoffWorthyFailure = options?.stopOnBackoffWorthyFailure;
3740
3915
  const exactAssetSelection = options?.exactAssetSelection;
@@ -3760,6 +3935,10 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3760
3935
  let exactFetchDisposition;
3761
3936
  let exactResponderCapability;
3762
3937
  const authenticatedExactAssets = [];
3938
+ const committedExactAssetUals = [];
3939
+ // What the stream established about this peer for one graph. A run over
3940
+ // several graphs has no single answer, so it reports none.
3941
+ let exactStreamOutcome;
3763
3942
  const markExactFetchIncomplete = () => {
3764
3943
  if (exactAssetUals === undefined)
3765
3944
  return;
@@ -3780,6 +3959,9 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3780
3959
  stopOnBackoffWorthyFailure,
3781
3960
  fetchTimeoutMs,
3782
3961
  exactAssetSelection,
3962
+ forceFreshExactSession: options?.forceFreshExactSession,
3963
+ exactRecoveryTransportMode: options?.exactRecoveryTransportMode,
3964
+ registeredPublicEvidence: options?.registeredPublicEvidence,
3783
3965
  authenticationTimeoutMs,
3784
3966
  operationFetchDeadline: operationBoundary.fetchDeadline,
3785
3967
  operationDeadline: operationBoundary.deadline,
@@ -3795,6 +3977,11 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3795
3977
  if (detailed.authenticatedExactAssets !== undefined) {
3796
3978
  authenticatedExactAssets.push(...detailed.authenticatedExactAssets);
3797
3979
  }
3980
+ if (detailed.committedExactAssetUals !== undefined) {
3981
+ committedExactAssetUals.push(...detailed.committedExactAssetUals);
3982
+ }
3983
+ if (orderedContextGraphIds.length === 1)
3984
+ exactStreamOutcome = detailed.exactStreamOutcome;
3798
3985
  return durableSyncAccumulatorFromResult(detailed.result);
3799
3986
  },
3800
3987
  })),
@@ -3806,6 +3993,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3806
3993
  priorityOverride: options?.priority,
3807
3994
  operationSignal: operationBoundary.signal,
3808
3995
  source: options?.source,
3996
+ onWorkStarted: admissionBoundary.startWork,
3809
3997
  }), operationBoundary.signal);
3810
3998
  }
3811
3999
  catch (error) {
@@ -3817,6 +4005,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3817
4005
  },
3818
4006
  merge: mergeDurableSyncAccumulatorInto,
3819
4007
  markDeferred: (summary) => {
4008
+ admissionBoundary.defer();
3820
4009
  markExactFetchIncomplete();
3821
4010
  recordDurableSyncDiagnostics(summary, { deferredBackpressure: 1 });
3822
4011
  return markDurableTerminalBoundary(summary, false);
@@ -3839,12 +4028,17 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3839
4028
  onDeferred: (item, error) => this.log.info(ctx, `Deferring durable sync at CG ${item.contextGraphId} due to local backpressure: ${error.message}`),
3840
4029
  });
3841
4030
  return {
4031
+ admission: admissionBoundary.snapshot(),
3842
4032
  result: finalizeDurableSyncCompletion(accumulator),
3843
4033
  ...(exactFetchDisposition ? { exactFetchDisposition } : {}),
3844
4034
  ...(exactResponderCapability ? { exactResponderCapability } : {}),
3845
4035
  ...(authenticatedExactAssets.length === 0
3846
4036
  ? {}
3847
4037
  : { authenticatedExactAssets: Object.freeze([...authenticatedExactAssets]) }),
4038
+ ...(committedExactAssetUals.length === 0
4039
+ ? {}
4040
+ : { committedExactAssetUals: Object.freeze([...committedExactAssetUals]) }),
4041
+ ...(exactStreamOutcome === undefined ? {} : { exactStreamOutcome }),
3848
4042
  };
3849
4043
  };
3850
4044
  const singleFlightKey = durableSyncSingleFlightKey({
@@ -3856,13 +4050,17 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3856
4050
  syncAgentsMeta,
3857
4051
  hasPhaseCallback: Boolean(onPhase),
3858
4052
  hasAtomicCommitCallback: Boolean(options?.onAtomicCommitStarted),
4053
+ hasWorkStartedCallback: Boolean(options?.onWorkStarted),
3859
4054
  hasAccessDeniedCallback: Boolean(onAccessDenied),
3860
4055
  hasSinceBatchIdResolver: Boolean(sinceBatchIdFor),
3861
4056
  hasSignal: Boolean(operationBoundary.signal),
3862
4057
  hasCurrentFence: Boolean(options?.isCurrent),
3863
4058
  hasChallengePinnedSelection: exactAssetSelection?.kind === 'challenge-pinned',
4059
+ hasForcedFreshExactSession: options?.forceFreshExactSession === true,
4060
+ hasRegisteredPublicEvidence: options?.registeredPublicEvidence !== undefined,
3864
4061
  exactAssetUals,
3865
4062
  settlementSliceTimeoutMs: options?.settlementSliceTimeoutMs,
4063
+ exactRecoveryTransportMode: options?.exactRecoveryTransportMode,
3866
4064
  priority: options?.priority,
3867
4065
  });
3868
4066
  const runWithinBoundary = async () => {
@@ -3893,13 +4091,19 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3893
4091
  const ctx = createOperationContext('sync');
3894
4092
  const detailed = await this.runLegacyDurableSyncDetailed(ctx, remotePeerId, [contextGraphId], undefined, undefined, undefined, {
3895
4093
  exactAssetSelection: selection,
4094
+ forceFreshExactSession: options.forceFreshExactSession,
4095
+ exactRecoveryTransportMode: options.exactRecoveryTransportMode,
4096
+ registeredPublicEvidence: options.registeredPublicEvidence,
4097
+ ...(options.totalTimeoutMs === undefined ? {} : { totalTimeoutMs: options.totalTimeoutMs }),
3896
4098
  stopOnBackoffWorthyFailure: true,
3897
- priority: 1_000,
4099
+ priority: VM_RECOVERY_SYNC_PRIORITY,
3898
4100
  source: 'vm-recovery',
4101
+ onWorkStarted: options.onWorkStarted,
3899
4102
  signal: options.signal,
3900
4103
  isCurrent: options.isCurrent,
3901
4104
  });
3902
4105
  return {
4106
+ admission: detailed.admission,
3903
4107
  result: detailed.result,
3904
4108
  disposition: detailed.exactFetchDisposition ?? 'incomplete',
3905
4109
  ...(detailed.exactResponderCapability === undefined
@@ -3908,14 +4112,30 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3908
4112
  ...(detailed.authenticatedExactAssets === undefined
3909
4113
  ? {}
3910
4114
  : { authenticatedAssets: detailed.authenticatedExactAssets }),
4115
+ ...(detailed.committedExactAssetUals === undefined
4116
+ ? {}
4117
+ : { committedExactAssetUals: detailed.committedExactAssetUals }),
4118
+ ...(detailed.exactStreamOutcome === undefined
4119
+ ? {}
4120
+ : { streamOutcome: detailed.exactStreamOutcome }),
3911
4121
  };
3912
4122
  }
3913
4123
  /** Execute one legacy durable Context Graph after its caller owns admission. */
3914
4124
  async runLegacyDurableSyncForContextGraph(ctx, remotePeerId, contextGraphId, remainingContextGraphs, options = {}) {
3915
4125
  return (await LifecycleSyncMethods.prototype.runLegacyDurableSyncForContextGraphDetailed.call(this, ctx, remotePeerId, contextGraphId, remainingContextGraphs, options)).result;
3916
4126
  }
4127
+ /** Capture transport refusal scope without performing authority or store IO. */
4128
+ captureExperimentalExactBatchRefusalScope(contextGraphId) {
4129
+ return captureExactBatchStreamRefusalScope({
4130
+ contextGraphId, deploymentId: this.chain.deploymentId,
4131
+ binding: this.contextGraphBindingState.currentBindingFor(contextGraphId, this.subscribedContextGraphs.get(contextGraphId)),
4132
+ bindingGeneration: this.contextGraphBindingState.capture(contextGraphId),
4133
+ selectedBindingGeneration: this.selectedVmReconcileCursors?.get(contextGraphId)?.bindingGeneration,
4134
+ lifecycleGeneration: this.vmReconcileLifecycleGeneration,
4135
+ });
4136
+ }
3917
4137
  async runLegacyDurableSyncForContextGraphDetailed(ctx, remotePeerId, contextGraphId, remainingContextGraphs, options = {}) {
3918
- const { onPhase, onAtomicCommitStarted, onAccessDenied, sinceBatchIdFor, stopOnBackoffWorthyFailure, onVerifiedFullSnapshot, fetchTimeoutMs = SYNC_TOTAL_TIMEOUT_MS, exactAssetSelection, authenticationTimeoutMs = fetchTimeoutMs, operationFetchDeadline, operationDeadline, settlementSliceTimeoutMs, signal, isCurrent, durableMetaContinuation, } = options;
4138
+ const { onPhase, onAtomicCommitStarted, onAccessDenied, sinceBatchIdFor, stopOnBackoffWorthyFailure, onVerifiedFullSnapshot, fetchTimeoutMs = SYNC_TOTAL_TIMEOUT_MS, exactAssetSelection, forceFreshExactSession, exactRecoveryTransportMode = 'stream-preferred', registeredPublicEvidence, authenticationTimeoutMs = fetchTimeoutMs, operationFetchDeadline, operationDeadline, settlementSliceTimeoutMs, signal, isCurrent, durableMetaContinuation, } = options;
3919
4139
  const assertLifecycleCurrent = () => {
3920
4140
  if (isCurrent?.() === false) {
3921
4141
  throw asSyncFetchAbortError(new Error(`Exact VM recovery lifecycle for ${contextGraphId} is no longer current`));
@@ -3995,6 +4215,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
3995
4215
  sinceBatchId,
3996
4216
  signal: fetchContext.signal,
3997
4217
  forceFreshSession: forceFreshSession
4218
+ || forceFreshExactSession === true
3998
4219
  || onVerifiedFullSnapshot !== undefined,
3999
4220
  manifestDigest,
4000
4221
  manifestPrefixDigestAtOffset,
@@ -4074,7 +4295,9 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4074
4295
  + `${subscription.onChainId}`), { code: 'VM_CHAIN_CONTEXT_GRAPH_MISMATCH' });
4075
4296
  }
4076
4297
  if (verifiedOnChainId && subscription && subscription.onChainId === undefined) {
4077
- await this.persistContextGraphSubscriptionStrict(asset.contextGraphId, { ...subscription, onChainId: verifiedOnChainId, lastReconciledOrdinal: 0 }, undefined, isBindingCurrent);
4298
+ // An on-demand subscription binds in memory only; durable rows are
4299
+ // saved before the binding becomes visible.
4300
+ await this.persistContextGraphSyncStateStrict(asset.contextGraphId, { ...subscription, onChainId: verifiedOnChainId, lastReconciledOrdinal: 0 }, 'on-chain id binding', isBindingCurrent);
4078
4301
  assertCurrent();
4079
4302
  this.bindSubscriptionOnChainId(asset.contextGraphId, subscription, verifiedOnChainId);
4080
4303
  recaptureBindingGeneration();
@@ -4107,13 +4330,26 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4107
4330
  this.invalidateListContextGraphsCache();
4108
4331
  this.contextGraphMetaProjection.markDirtyFromQuads(authentication.asset.metadataQuads);
4109
4332
  try {
4333
+ let retiredTwin;
4110
4334
  const retirement = await reconcileFinalizedSwmTwin({
4111
4335
  store: this.store,
4112
4336
  writeLocks: this.writeLocks,
4113
4337
  asset: authentication.asset,
4114
- retire: (candidate) => this.retireFinalizedSwmTwinCandidate(candidate, ctx),
4338
+ retire: async (candidate) => {
4339
+ await this.retireFinalizedSwmTwinCandidate(candidate, ctx);
4340
+ retiredTwin = candidate;
4341
+ },
4115
4342
  });
4116
4343
  if (retirement === 'retired') {
4344
+ await this.retireLegacySwmAfterVerifiedVmTwin({
4345
+ contextGraphId: asset.contextGraphId,
4346
+ kaUal: asset.ual,
4347
+ assertionVersion: asset.assertionVersion,
4348
+ // The marker of the namespace whose twin was verified and
4349
+ // retired. Without it a twin in a named subgraph would
4350
+ // retire the root marker of the same asset.
4351
+ subGraphName: retiredTwin?.subGraphName,
4352
+ });
4117
4353
  this.invalidateListContextGraphsCache();
4118
4354
  this.log.info(ctx, `Retired byte-identical SWM twin after durable VM materialization for ${asset.ual}`);
4119
4355
  }
@@ -4161,7 +4397,54 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4161
4397
  };
4162
4398
  }
4163
4399
  if (exactAssetSelection !== undefined) {
4164
- return runDurableSyncDetailed(durableContext);
4400
+ const outcome = await runExactBatchStreamDriver({
4401
+ contextGraphId, remotePeerId,
4402
+ selection: exactAssetSelection, transportMode: exactRecoveryTransportMode,
4403
+ streamEnabled: resolveExactBatchStreamEnabled(),
4404
+ fetchDeadline: contextGraphBudget.fetchDeadline, signal, isCurrent,
4405
+ }, {
4406
+ router: this.router, capabilityOwner: this,
4407
+ captureConnectionKey: () => this.getSyncReconcilerConnectionKey(remotePeerId),
4408
+ captureRefusalScope: () => this.captureExperimentalExactBatchRefusalScope(contextGraphId),
4409
+ isChainEnabled: () => this.chain.chainId !== 'none',
4410
+ getPeerProtocols: () => this.getPeerProtocols(remotePeerId),
4411
+ // The recovery pass that owns this exchange may have handed it its own fresh positive
4412
+ // answer; every other fetch, and any doubt about that answer, reads the authority itself.
4413
+ isRegisteredPublic: async () => registeredPublicEvidence?.usableFor(contextGraphId, signal) === true
4414
+ || (await this.resolveRegisteredContextGraphAuthority(contextGraphId, {
4415
+ authorityReadMode: 'finalized-index-or-live', signal,
4416
+ })).kind === 'public',
4417
+ requestIdentity: () => ({
4418
+ requesterPeerId: this.peerId,
4419
+ computeSyncDigest: (...args) => this.computeSyncDigest(...args),
4420
+ getIdentityId: () => this.chain.getIdentityId(),
4421
+ signMessage: typeof this.chain.signMessage === 'function' ? this.chain.signMessage.bind(this.chain) : undefined,
4422
+ }),
4423
+ verification: {
4424
+ ctx,
4425
+ parseAndFilter: (text, graph, cg) => this.getOrCreateSyncVerifyWorker().parseAndFilter(text, graph, cg),
4426
+ processDurableBatchInWorker: durableContext.processDurableBatchInWorker,
4427
+ authenticationDeadline: contextGraphBudget.createGraphScopedAuthenticationDeadline,
4428
+ storeGraphScopedAsset: durableContext.storeGraphScopedAsset,
4429
+ },
4430
+ reconnect: async (reconnectSignal) => {
4431
+ try {
4432
+ await this.ensurePeerConnected(remotePeerId, { signal: reconnectSignal });
4433
+ }
4434
+ catch {
4435
+ // Unreachable for now, or connected but no longer admitted.
4436
+ return false;
4437
+ }
4438
+ return this.node.libp2p.getConnections()
4439
+ .some((connection) => connection.remotePeer.toString() === remotePeerId);
4440
+ },
4441
+ logInfo: message => this.log.info(ctx, message),
4442
+ });
4443
+ switch (outcome.kind) {
4444
+ case 'settled': return outcome.detailed;
4445
+ case 'not-selected':
4446
+ case 'unsupported-before-start': return runDurableSyncDetailed(durableContext);
4447
+ }
4165
4448
  }
4166
4449
  return { result: await runDurableSync(durableContext) };
4167
4450
  }
@@ -4510,9 +4793,25 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4510
4793
  deadline,
4511
4794
  fetchSharingIdentity: defaultPageFetchSharingIdentity,
4512
4795
  });
4796
+ // Match the additive builder negotiation. Authorization is still evaluated
4797
+ // by buildSyncRequest and by the responder before any export is admitted.
4798
+ const responseEncoding = resolveExactSyncGzipProfile({
4799
+ includeSharedMemory, phase, assetUals, responseEncoding: EXACT_SYNC_GZIP_ENCODING,
4800
+ })?.responseEncoding;
4513
4801
  const exactAccumulationLimits = assetUals === undefined
4514
4802
  ? undefined
4515
- : exactSyncPhaseAccumulationLimits(assetUals);
4803
+ : exactSyncPhaseAccumulationLimits(assetUals, responseEncoding);
4804
+ const effectiveMaxAcceptedQuads = exactAccumulationLimits?.maxQuads === undefined
4805
+ ? maxAcceptedQuads
4806
+ : maxAcceptedQuads === undefined
4807
+ ? exactAccumulationLimits.maxQuads
4808
+ : Math.min(exactAccumulationLimits.maxQuads, maxAcceptedQuads);
4809
+ const exactHeapLimit = exactAccumulationLimits?.maxHeapBytesEstimate;
4810
+ const effectiveMaxAcceptedHeapBytesEstimate = exactHeapLimit === undefined
4811
+ ? maxAcceptedHeapBytesEstimate
4812
+ : maxAcceptedHeapBytesEstimate === undefined
4813
+ ? exactHeapLimit
4814
+ : Math.min(exactHeapLimit, maxAcceptedHeapBytesEstimate);
4516
4815
  // Coalescing is declared by the capability, never inferred from singleton
4517
4816
  // identity. Exclusive private rounds cannot inherit another job's clock.
4518
4817
  const fetchSharingIdentity = effectiveWorkAdmission.fetchSharingIdentity;
@@ -4532,8 +4831,10 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4532
4831
  assetUals,
4533
4832
  returnAcceptedPrefixOnRetryableTransportFailure,
4534
4833
  requesterScope,
4535
- maxAcceptedQuads,
4536
- maxAcceptedHeapBytesEstimate,
4834
+ responseEncoding,
4835
+ maxAcceptedBytes: exactAccumulationLimits?.maxBytes,
4836
+ maxAcceptedQuads: effectiveMaxAcceptedQuads,
4837
+ maxAcceptedHeapBytesEstimate: effectiveMaxAcceptedHeapBytesEstimate,
4537
4838
  });
4538
4839
  const inFlight = inFlightSyncPageFetchesFor(this);
4539
4840
  // Read once, here: this fetch runs inside the admitted operation, so the
@@ -4590,15 +4891,12 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4590
4891
  snapshotRef,
4591
4892
  sinceBatchId,
4592
4893
  assetUals,
4894
+ responseEncoding,
4593
4895
  returnAcceptedPrefixOnRetryableTransportFailure,
4594
4896
  requesterScope,
4595
4897
  maxAcceptedBytes: exactAccumulationLimits?.maxBytes,
4596
- maxAcceptedQuads: exactAccumulationLimits?.maxQuads === undefined
4597
- ? maxAcceptedQuads
4598
- : maxAcceptedQuads === undefined
4599
- ? exactAccumulationLimits.maxQuads
4600
- : Math.min(exactAccumulationLimits.maxQuads, maxAcceptedQuads),
4601
- maxAcceptedHeapBytesEstimate,
4898
+ maxAcceptedQuads: effectiveMaxAcceptedQuads,
4899
+ maxAcceptedHeapBytesEstimate: effectiveMaxAcceptedHeapBytesEstimate,
4602
4900
  pageSizeProfileCache: syncPageSizeProfileCacheFor(this),
4603
4901
  deadline,
4604
4902
  recovery,
@@ -4861,11 +5159,12 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4861
5159
  return execution(emptySharedMemorySyncResult());
4862
5160
  }
4863
5161
  const recoveryExecutor = this.createSwmTargetExecutorSessionV1();
4864
- const recoverPrivateContextGraph = (contextGraphId, recoveryLease, onRetry) => recoveryExecutor.recoverPrivateTarget({
5162
+ const recoverPrivateContextGraph = async (contextGraphId, recoveryLease, onRetry) => recoveryExecutor.recoverPrivateTarget({
4865
5163
  remotePeerId,
4866
5164
  contextGraphId,
4867
5165
  includeRootScope: requestedScope !== null
4868
- || this.resolveRfc64CatalogReceiverAuthorityV1(contextGraphId).legacySyncAllowed,
5166
+ || this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId)
5167
+ || await this.rfc64PrivateRootSwmOnLegacyLaneV1(contextGraphId),
4869
5168
  recoveryGuard: recoveryLease,
4870
5169
  onRetry,
4871
5170
  });
@@ -4972,7 +5271,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
4972
5271
  contextGraphId,
4973
5272
  remainingContextGraphs,
4974
5273
  includeRootScope: requestedScope !== null
4975
- || this.resolveRfc64CatalogReceiverAuthorityV1(contextGraphId).legacySyncAllowed,
5274
+ || this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId),
4976
5275
  stopOnBackoffWorthyFailure,
4977
5276
  mode,
4978
5277
  });
@@ -5047,7 +5346,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5047
5346
  selectedSwmPriority: selectedPublicWork,
5048
5347
  });
5049
5348
  },
5050
- merge: mergeSharedMemorySyncResults,
5349
+ merge: mergeSamePeerSharedMemoryDiagnostics,
5051
5350
  onResult: (item, result) => {
5052
5351
  if (selectedSwmEnabled
5053
5352
  && item.lane === 'shared_memory'
@@ -5101,7 +5400,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5101
5400
  source: options?.source,
5102
5401
  selectedSwmPriority: true,
5103
5402
  }),
5104
- merge: mergeSharedMemorySyncResults,
5403
+ merge: mergeSamePeerSharedMemoryDiagnostics,
5105
5404
  markDeferred: (summary) => ({
5106
5405
  ...summary,
5107
5406
  deferredBackpressure: (summary.deferredBackpressure ?? 0) + 1,
@@ -5124,7 +5423,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5124
5423
  },
5125
5424
  });
5126
5425
  const { summary: continuationSummary } = continuationExecution;
5127
- const finalSummary = mergeSharedMemorySyncResults(initialSummary, continuationSummary);
5426
+ const finalSummary = mergeSamePeerSharedMemoryDiagnostics(initialSummary, continuationSummary);
5128
5427
  const incompleteSelectedContextGraphs = new Set(continuationExecution.incompleteContextGraphIds);
5129
5428
  const continuedSelectedContextGraphs = new Set(selectedContinuationUnits.map(({ work: unitWork }) => unitWork.contextGraphId));
5130
5429
  for (const target of selectedPublicTargets) {
@@ -5164,11 +5463,14 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5164
5463
  this.log.warn(ctx, `Skipping SWM recovery from ${remotePeerId.slice(-8)} (DKG_DURABLE_SYNC_ENABLED=0)`);
5165
5464
  return emptySwmRecoveryResult();
5166
5465
  }
5167
- return this.runContextGraphSyncWithBackpressure(ctx, contextGraphId, 'swm_recovery', `swm-recovery:${contextGraphId}:${remotePeerId.slice(-8)}`, () => this.createSwmTargetExecutorSessionV1()
5466
+ return this.runContextGraphSyncWithBackpressure(ctx, contextGraphId, 'swm_recovery', `swm-recovery:${contextGraphId}:${remotePeerId.slice(-8)}`, async () => this.createSwmTargetExecutorSessionV1()
5168
5467
  .recoverPrivateTarget({
5169
5468
  remotePeerId,
5170
5469
  contextGraphId,
5171
- includeRootScope: this.resolveRfc64CatalogReceiverAuthorityV1(contextGraphId).legacySyncAllowed,
5470
+ includeRootScope: this.rfc64LegacySwmGossipAllowedForContextGraph(contextGraphId)
5471
+ // A private graph's root scope stays on the legacy member lane
5472
+ // while its RFC-64 authority is not active (#2858).
5473
+ || await this.rfc64PrivateRootSwmOnLegacyLaneV1(contextGraphId),
5172
5474
  }), { source: 'swm-recovery' });
5173
5475
  }
5174
5476
  /**
@@ -5300,16 +5602,6 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5300
5602
  });
5301
5603
  }
5302
5604
  /** Focused VM-recovery operation that returns clean per-peer miss evidence. */
5303
- async syncVmRecoveryFromConnectedPeers(contextGraphId, options) {
5304
- const catchup = await this.syncContextGraphFromConnectedPeers(contextGraphId, options);
5305
- return {
5306
- catchup,
5307
- // Embedders may still override the catch-up method with the pre-evidence
5308
- // result shape. Treat that legacy shape as no proof; production results
5309
- // always carry the immutable field below.
5310
- cleanMissPeerIds: [...(catchup.cleanSharedMemoryPeerIds ?? [])],
5311
- };
5312
- }
5313
5605
  selectCatchupPeerWindow(peers, options) {
5314
5606
  const maxPeers = options?.maxPeers;
5315
5607
  if (maxPeers === undefined || !Number.isInteger(maxPeers) || maxPeers <= 0) {
@@ -5470,7 +5762,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5470
5762
  // into HEAD's `accessDeniedPeers` counter so the existing daemon
5471
5763
  // catchup-status endpoint and UI keep working — see
5472
5764
  // `cli/src/daemon.ts` subscribe job and `catchup-runner.ts`.
5473
- const emptyShared = () => createEmptySharedMemorySyncResult(1);
5765
+ const emptyShared = () => emptySharedMemorySyncResult(1);
5474
5766
  // Bounded fan-out: at most CATCHUP_MAX_CONCURRENT_PEER_SYNCS peer syncs run
5475
5767
  // at once. The pre-cap unbounded `Promise.all` over every sync-capable peer
5476
5768
  // was the top amplifier of the 2026-07-07 mainnet sync storm — one
@@ -5755,7 +6047,13 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5755
6047
  const ctx = createOperationContext('sync');
5756
6048
  await primeCatchupConnectionsAtom(this.node.libp2p, this.discovery, this.peerId, async (peerId) => {
5757
6049
  await this.networkAdmissionCoordinator.ensureAdmitted(peerId, ctx);
5758
- });
6050
+ },
6051
+ // An on-demand phonebook holds every relay-advertising profile; walking
6052
+ // all of them on each catch-up is a dial storm. Nodes that sync the
6053
+ // phonebook on every connect (and the kill switch) keep today's walk.
6054
+ this.onDemandAgentsPhonebookEnabled()
6055
+ ? { maxDials: AGENTS_PHONEBOOK_PRIME_MAX_DIALS }
6056
+ : {});
5759
6057
  }
5760
6058
  /**
5761
6059
  * Pull `_meta` (and SWM) for a CG immediately after receiving a curator
@@ -5786,26 +6084,16 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5786
6084
  const ctx = createOperationContext('sync');
5787
6085
  const curatorShort = curatorPeerId.slice(-8);
5788
6086
  let curatorTargetSucceeded = false;
5789
- const approvedAgentAddress = this.localApprovedAgentByCG.get(contextGraphId);
5790
- if (!approvedAgentAddress) {
6087
+ // One acceptance (member proof plus authenticated policy) judges both the
6088
+ // snapshot the curator serves and the local proof that completes the join.
6089
+ const acceptance = await this.resolveApprovedMemberAcceptance(contextGraphId);
6090
+ if (!acceptance) {
5791
6091
  throw new Error(`Post-approval sync for "${contextGraphId}" has no approved local agent binding`);
5792
6092
  }
5793
- let expectedDelegateeOpKey;
5794
- try {
5795
- expectedDelegateeOpKey = await inferAdapterPublisherAddress(this.chain);
5796
- }
5797
- catch {
5798
- // The signed join flow always binds the current libp2p peer, so an
5799
- // adapter that cannot expose its op-key still has a usable proof.
5800
- }
5801
6093
  const curatorMetaRefreshOptions = {
5802
6094
  trustedCuratorPeerId: curatorPeerId,
5803
6095
  force: true,
5804
- memberProof: {
5805
- approvedAgentAddress,
5806
- expectedDelegateePeerId: this.peerId,
5807
- expectedDelegateeOpKey,
5808
- },
6096
+ approvedMember: acceptance,
5809
6097
  };
5810
6098
  // Curator-direct attempt. Any throw here (relay reservation gone,
5811
6099
  // dial timeout, AbortSignal, transient `Remote closed connection
@@ -5849,12 +6137,14 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5849
6137
  // transfer into a false-ready subscription. Retry once after each
5850
6138
  // catchup round and require a live metadata proof before declaring
5851
6139
  // the curator-targeted bootstrap complete.
5852
- let hasAuthoritativeMeta = await this.hasConfirmedMetaState(contextGraphId)
5853
- .catch(() => false);
6140
+ // The bootstrap completes only once the local metadata proves this
6141
+ // approved member; a public definition stored before the join
6142
+ // (RFC-64 bootstrap) must not end it while the curator's snapshot
6143
+ // is still stale (#2831 review).
6144
+ let hasAuthoritativeMeta = await this.hasConfirmedApprovedMemberMetaState(contextGraphId, acceptance).catch(() => false);
5854
6145
  if (!hasAuthoritativeMeta) {
5855
6146
  await this.refreshMetaFromCurator(contextGraphId, curatorMetaRefreshOptions);
5856
- hasAuthoritativeMeta = await this.hasConfirmedMetaState(contextGraphId)
5857
- .catch(() => false);
6147
+ hasAuthoritativeMeta = await this.hasConfirmedApprovedMemberMetaState(contextGraphId, acceptance).catch(() => false);
5858
6148
  }
5859
6149
  if (hasAuthoritativeMeta) {
5860
6150
  await this.refreshMetaSyncedFlags([contextGraphId]);
@@ -5907,53 +6197,94 @@ export class LifecycleSyncMethods extends DKGAgentBase {
5907
6197
  * authorize VM, payload, plaintext-recovery, or SWM activation. Those lanes
5908
6198
  * are installed only after the fetched metadata (or the registered chain
5909
6199
  * roster) makes the ordinary read-authority resolver return `allowed`.
6200
+ *
6201
+ * Reports whether a later attempt can still succeed: a failed fetch, a
6202
+ * snapshot that does not prove this member yet, or unavailable authority is
6203
+ * `retry`; no approval binding or denied authority is `stop`.
5910
6204
  */
5911
- async resumePendingJoinApprovalMetadata(contextGraphId, curatorPeerId) {
6205
+ async resumePendingJoinApprovalMetadata(contextGraphId, curatorPeerId, curatorDialAddress) {
5912
6206
  const ctx = createOperationContext('sync');
5913
- const approvedAgentAddress = this.localApprovedAgentByCG.get(contextGraphId);
5914
- if (!approvedAgentAddress)
5915
- return;
5916
- let expectedDelegateeOpKey;
5917
- try {
5918
- expectedDelegateeOpKey = await inferAdapterPublisherAddress(this.chain);
5919
- }
5920
- catch {
5921
- // The durable approval always binds the current libp2p peer. An adapter
5922
- // without an observable operational key still has a usable proof.
5923
- }
6207
+ const acceptance = await this.resolveApprovedMemberAcceptance(contextGraphId);
6208
+ if (!acceptance)
6209
+ return 'stop';
5924
6210
  const refreshed = await this.refreshMetaFromCurator(contextGraphId, {
5925
6211
  trustedCuratorPeerId: curatorPeerId,
6212
+ curatorDialAddressHint: curatorDialAddress,
5926
6213
  force: true,
5927
- memberProof: {
5928
- approvedAgentAddress,
5929
- expectedDelegateePeerId: this.peerId,
5930
- expectedDelegateeOpKey,
5931
- },
6214
+ approvedMember: acceptance,
5932
6215
  }).catch((error) => {
5933
6216
  this.log.warn(ctx, `Pending join-approval metadata recovery for "${contextGraphId}" failed: ${error instanceof Error ? error.message : String(error)}`);
5934
6217
  return false;
5935
6218
  });
5936
- if (!refreshed || !(await this.hasConfirmedMetaState(contextGraphId).catch(() => false))) {
6219
+ if (!refreshed
6220
+ || !(await this.hasConfirmedApprovedMemberMetaState(contextGraphId, acceptance)
6221
+ .catch(() => false))) {
5937
6222
  this.log.warn(ctx, `Pending join-approval metadata recovery for "${contextGraphId}" did not establish authoritative metadata; keeping data lanes closed`);
5938
- return;
6223
+ return 'retry';
5939
6224
  }
5940
6225
  const authority = await withRpcUsageSite(CG_AUTH_RPC_SITES.joinResume, () => this.resolveContextGraphReadAuthority(contextGraphId, {
5941
6226
  allowSubscriptionFallback: false,
5942
6227
  })).catch(() => ({ outcome: 'unavailable' }));
5943
6228
  if (authority.outcome !== 'allowed') {
5944
6229
  this.log.warn(ctx, `Pending join-approval metadata recovery for "${contextGraphId}" completed but current read authority is ${authority.outcome}; keeping data lanes closed`);
5945
- return;
5946
- }
6230
+ // A stale approval cannot override an explicit current denial.
6231
+ return authority.outcome === 'unavailable' ? 'retry' : 'stop';
6232
+ }
6233
+ // A shutdown that began during the reads above must not clear the row's
6234
+ // pending state or open its data lanes while the node tears down; the
6235
+ // next start recovers the row again.
6236
+ const stopping = () => this.node.stopSignal?.aborted === true;
6237
+ if (stopping())
6238
+ return 'stop';
5947
6239
  await this.refreshMetaSyncedFlags([contextGraphId]);
5948
6240
  const current = this.subscribedContextGraphs.get(contextGraphId);
5949
- if (!current?.subscribed)
5950
- return;
6241
+ if (!current?.subscribed || stopping())
6242
+ return 'stop';
5951
6243
  this.subscribeToContextGraph(contextGraphId, {
5952
6244
  persist: false,
5953
6245
  syncMode: current.syncMode,
5954
6246
  });
5955
6247
  this.persistLocalNodeMembership(contextGraphId, 'rehydrated-subscription');
5956
6248
  await this.runImmediatePostApprovalSync(contextGraphId, curatorPeerId);
6249
+ return 'completed';
6250
+ }
6251
+ /**
6252
+ * Run the restricted pending-metadata recovery of a restarted join approval
6253
+ * until it completes or can no longer complete (#2832). Right after a
6254
+ * restart the node's authority reads can still be rebuilding its finalized
6255
+ * index, so a single attempt could fail transiently and leave every data
6256
+ * lane closed until the next restart. A `retry` outcome, or an attempt that
6257
+ * throws, is tried again with backoff while the row is still a subscribed,
6258
+ * join-approved, pending-metadata row; the node stopping ends the loop.
6259
+ */
6260
+ async recoverPendingJoinApprovalMetadata(contextGraphId, curatorPeerId, curatorDialAddress) {
6261
+ const stopSignal = this.node.stopSignal;
6262
+ for (let attempt = 0;; attempt += 1) {
6263
+ let outcome;
6264
+ try {
6265
+ outcome = await this.resumePendingJoinApprovalMetadata(contextGraphId, curatorPeerId, curatorDialAddress);
6266
+ }
6267
+ catch (error) {
6268
+ // A store or network fault that escapes an attempt is as transient as
6269
+ // a `retry`. Ending the loop on it would leave the row closed until
6270
+ // the next restart again.
6271
+ this.log.warn(createOperationContext('sync'), `Pending join-approval recovery attempt for "${contextGraphId}" failed: ${error instanceof Error ? error.message : String(error)}`);
6272
+ outcome = 'retry';
6273
+ }
6274
+ if (outcome !== 'retry')
6275
+ return;
6276
+ const delayMs = JOIN_APPROVAL_METADATA_RECOVERY_RETRY_MS[Math.min(attempt, JOIN_APPROVAL_METADATA_RECOVERY_RETRY_MS.length - 1)];
6277
+ if (!(await waitUnlessStopped(delayMs, stopSignal)))
6278
+ return;
6279
+ const current = this.subscribedContextGraphs.get(contextGraphId);
6280
+ if (!this.localApprovedAgentByCG.has(contextGraphId)
6281
+ || current?.subscribed !== true
6282
+ // A concurrent data catch-up can set `synced` while authoritative
6283
+ // join metadata is still pending or unknown. Only its explicit
6284
+ // confirmation ends this join-specific retry.
6285
+ || (current.synced === true && current.metaSynced === true && current.pendingMeta !== true))
6286
+ return;
6287
+ }
5957
6288
  }
5958
6289
  selectCatchupPeers(peers, preferredPeerId, privateOnly = false) {
5959
6290
  return orderCatchupPeers(peers, preferredPeerId, privateOnly, this.peerCapabilityRegistry.snapshotCorePeerIds());
@@ -6008,7 +6339,9 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6008
6339
  * abort contract.
6009
6340
  */
6010
6341
  async waitForSyncProtocol(pid, signal) {
6011
- return waitForPeerProtocol(this.node.libp2p.peerStore, pid, PROTOCOL_SYNC, SYNC_PROTOCOL_CHECK_ATTEMPTS, SYNC_PROTOCOL_CHECK_DELAY_MS, signal);
6342
+ return waitForPeerProtocol(this.node.libp2p.peerStore, pid,
6343
+ // Either id proves sync support (#2822; see `advertisesSyncProtocol`).
6344
+ [PROTOCOL_SYNC, PROTOCOL_SYNC_POOLED], SYNC_PROTOCOL_CHECK_ATTEMPTS, SYNC_PROTOCOL_CHECK_DELAY_MS, signal);
6012
6345
  }
6013
6346
  async refreshMetaSyncedFlags(contextGraphIds) {
6014
6347
  for (const contextGraphId of contextGraphIds) {
@@ -6327,14 +6660,16 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6327
6660
  pending.add(revision);
6328
6661
  }
6329
6662
  enqueueContextGraphSubscriptionPersistWrite(contextGraphId, write) {
6330
- const previous = this.contextGraphSubscriptionPersistChains.get(contextGraphId) ?? Promise.resolve();
6331
- const run = previous.then(write);
6332
- const chain = run.catch(() => undefined);
6333
- this.contextGraphSubscriptionPersistChains.set(contextGraphId, chain);
6334
- void chain.finally(() => {
6335
- if (this.contextGraphSubscriptionPersistChains.get(contextGraphId) !== chain)
6336
- return;
6337
- this.contextGraphSubscriptionPersistChains.delete(contextGraphId);
6663
+ // The scheduler owns per-context-graph ordering, strict non-coalescing,
6664
+ // write-start timing (a microtask after admission), shutdown drain and
6665
+ // bounds; the revision maps below stay the cancel/supersede layer on top of
6666
+ // it. The returned promise rejects when the write (or admission) fails, so
6667
+ // an awaiting caller sees the failure. The lane keeps draining, so a failed
6668
+ // write does not stall the next one for this context graph.
6669
+ const run = this.contextGraphSubscriptionPersistence.enqueue(contextGraphId, write);
6670
+ // Idle cleanup runs after the caller's own handlers and marks a failure as
6671
+ // handled for a caller that drops the promise, as the chain tail did.
6672
+ void run.catch(() => undefined).finally(() => {
6338
6673
  this.clearContextGraphSubscriptionPersistRevisionStateIfIdle(contextGraphId);
6339
6674
  });
6340
6675
  return run;
@@ -6355,7 +6690,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6355
6690
  clearContextGraphSubscriptionPersistRevisionStateIfIdle(contextGraphId) {
6356
6691
  if ((this.contextGraphSubscriptionPersistPendingRevisions.get(contextGraphId)?.size ?? 0) > 0)
6357
6692
  return;
6358
- if (this.contextGraphSubscriptionPersistChains.has(contextGraphId))
6693
+ if (this.contextGraphSubscriptionPersistence.hasLane(contextGraphId))
6359
6694
  return;
6360
6695
  const sub = this.subscribedContextGraphs.get(contextGraphId);
6361
6696
  if (sub?.subscribed === true || sub?.coreHosted === true)
@@ -6506,6 +6841,9 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6506
6841
  const recoverySelectionChanged = effects.recoveryChanged;
6507
6842
  if (!receiverSelectionChanged && !recoverySelectionChanged)
6508
6843
  return;
6844
+ // Record the inactive edge synchronously: a same-tick resubscription can
6845
+ // otherwise look like an unchanged active lane to repair backoff.
6846
+ this.observeRfc64SwmCatalogProjectionLaneAvailabilityV1(contextGraphId);
6509
6847
  if (receiverSelectionChanged && !effects.nextReceiverActive) {
6510
6848
  this.rfc64PublicCatalogServiceV1?.deactivateReceiverContextGraph(contextGraphId);
6511
6849
  this.clearRfc64CatalogOperationalTargetsV1(contextGraphId);
@@ -6539,8 +6877,8 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6539
6877
  void this.replayRfc64CatalogToConnectedPeersV1(contextGraphId)
6540
6878
  .catch(() => undefined);
6541
6879
  }
6542
- // Re-entering the idempotent start boundary also dirties an existing
6543
- // failed repair for this newly active CG, including retryIntervalMs=0.
6880
+ // The observed inactive edge makes this recovery eligible immediately,
6881
+ // including retryIntervalMs=0; duplicate active starts retain cooldown.
6544
6882
  this.startRfc64SwmCatalogProjectionSupervisorV1(createOperationContext('system'));
6545
6883
  }
6546
6884
  }
@@ -6650,6 +6988,12 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6650
6988
  this.finishContextGraphSubscriptionPersistRevision(contextGraphId, options?.revision);
6651
6989
  });
6652
6990
  }
6991
+ /**
6992
+ * Strict write of a row that must be durable. Throws when the projection
6993
+ * would keep member intent process-local, so it suits persisted-row
6994
+ * activation, not the sync path of a live on-demand subscription (see
6995
+ * {@link persistContextGraphSyncStateStrict}).
6996
+ */
6653
6997
  async persistContextGraphSubscriptionStrict(contextGraphId, subscription, syncScoped, isCurrent = () => true) {
6654
6998
  await this.persistContextGraphSubscriptionProjectionStrict({
6655
6999
  contextGraphId,
@@ -6661,10 +7005,11 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6661
7005
  });
6662
7006
  }
6663
7007
  /**
6664
- * One strict subscription persistence protocol shared by joins and registry
6665
- * discovery. It owns snapshot capture, generation validation, per-graph
6666
- * serialization, and the store-first write. Callers select only whether an
6667
- * intentionally process-local on-demand member projection is acceptable.
7008
+ * One strict subscription persistence protocol shared by joins, registry
7009
+ * discovery, and sync-owned binding and cursor progress. It owns snapshot
7010
+ * capture, generation validation, per-graph serialization, and the
7011
+ * store-first write. Callers select only whether an intentionally
7012
+ * process-local on-demand member projection is acceptable.
6668
7013
  */
6669
7014
  async persistContextGraphSubscriptionProjectionStrict(input) {
6670
7015
  const store = this.config.contextGraphSubscriptionStore;
@@ -6678,7 +7023,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6678
7023
  const expectedBindingGeneration = this.contextGraphBindingState.capture(input.contextGraphId);
6679
7024
  const sub = input.subscription ?? expectedLiveSub;
6680
7025
  if (!sub?.subscribed && !sub?.coreHosted) {
6681
- throw new Error(`Cannot persist context graph "${input.contextGraphId}": active subscription or host state is missing`);
7026
+ throw new Error(`Cannot persist context graph "${input.contextGraphId}" (${input.operation}): active subscription or host state is missing`);
6682
7027
  }
6683
7028
  const persistence = projectContextGraphSubscriptionPersistence({
6684
7029
  contextGraphId: input.contextGraphId,
@@ -6702,7 +7047,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6702
7047
  || current !== expectedLiveSub
6703
7048
  || (!current?.subscribed && !current?.coreHosted)
6704
7049
  || !this.contextGraphBindingState.isGenerationCurrent(input.contextGraphId, expectedBindingGeneration)) {
6705
- throw asSyncFetchAbortError(new Error(`Context graph "${input.contextGraphId}" changed before its strict subscription snapshot was persisted`));
7050
+ throw asSyncFetchAbortError(new Error(`Context graph "${input.contextGraphId}" changed before its strict subscription snapshot (${input.operation}) was persisted`));
6706
7051
  }
6707
7052
  await store.save(record);
6708
7053
  });
@@ -6722,6 +7067,25 @@ export class LifecycleSyncMethods extends DKGAgentBase {
6722
7067
  operation: 'chain discovery',
6723
7068
  });
6724
7069
  }
7070
+ /**
7071
+ * Sync-owned durability boundary for a live subscription's on-chain id
7072
+ * binding and VM reconcile cursor. Like chain discovery, sync keeps the
7073
+ * canonical projection instead of demanding durable member intent: an
7074
+ * on-demand member subscription is process-local, so nothing is written and
7075
+ * the caller advances only its in-memory state; a Core hosting obligation
7076
+ * still saves its host-only row; an always-on subscription is saved before
7077
+ * the caller exposes the new state. Demanding member intent here stalled
7078
+ * every `dkg subscribe` without `--save` at its first cursor advance.
7079
+ */
7080
+ async persistContextGraphSyncStateStrict(contextGraphId, subscription, operation, isCurrent) {
7081
+ await this.persistContextGraphSubscriptionProjectionStrict({
7082
+ contextGraphId,
7083
+ subscription,
7084
+ isCurrent,
7085
+ requireDurableMemberIntent: false,
7086
+ operation,
7087
+ });
7088
+ }
6725
7089
  /**
6726
7090
  * Persist the two durable halves of a requester-side join approval.
6727
7091
  *
@@ -7005,12 +7369,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7005
7369
  onChainId: row.onChainId,
7006
7370
  onChainHash: row.onChainHash,
7007
7371
  },
7008
- }).catch(() => ({
7009
- outcome: 'unavailable',
7010
- source: 'legacy-local',
7011
- reason: 'unexpected-authority-error',
7012
- metadataBootstrap: 'eligible',
7013
- }))),
7372
+ }).catch((error) => unavailableContextGraphReadAuthorityDecision('legacy-local', 'unexpected-authority-error', contextGraphReadAuthorityDependencyOf(error)))),
7014
7373
  activate: async (row, onChainId, revision) => {
7015
7374
  await this.activatePersistedContextGraphSubscriptionRecord(row, {
7016
7375
  onChainId,
@@ -7048,6 +7407,10 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7048
7407
  });
7049
7408
  this.log.info(ctx, `Activated persisted context-graph subscription "${contextGraphId}" after authority recovery`);
7050
7409
  },
7410
+ capped: (contextGraphId) => {
7411
+ this.contextGraphSubscriptionRehydrationPendingIds.add(contextGraphId);
7412
+ this.contextGraphSubscriptionRehydrationPromotionRuntime?.request();
7413
+ },
7051
7414
  });
7052
7415
  }
7053
7416
  /**
@@ -7130,12 +7493,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7130
7493
  onChainId: row.onChainId,
7131
7494
  onChainHash: row.onChainHash,
7132
7495
  },
7133
- }).catch(() => ({
7134
- outcome: 'unavailable',
7135
- source: 'legacy-local',
7136
- reason: 'unexpected-authority-error',
7137
- metadataBootstrap: 'eligible',
7138
- }));
7496
+ }).catch((error) => unavailableContextGraphReadAuthorityDecision('legacy-local', 'unexpected-authority-error', contextGraphReadAuthorityDependencyOf(error)));
7139
7497
  signal.throwIfAborted();
7140
7498
  if (!runtime.owns(signal))
7141
7499
  return 'idle';
@@ -7298,6 +7656,8 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7298
7656
  if (!store)
7299
7657
  return;
7300
7658
  const ctx = createOperationContext('init');
7659
+ let authorityBudget;
7660
+ const startupPlan = this.gossipSession.beginDurableStartupPlan(this.contextGraphSubscriptionRehydrationAccountedIds);
7301
7661
  try {
7302
7662
  // System context graphs (AGENTS/ONTOLOGY) are auto-subscribed separately
7303
7663
  // by start(); their persisted rows must NOT be rehydrated here too. Re-
@@ -7306,6 +7666,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7306
7666
  // dormant. Exclude them from the rehydration set entirely.
7307
7667
  const systemContextGraphs = new Set(Object.values(SYSTEM_CONTEXT_GRAPHS));
7308
7668
  const persistedRows = await store.loadAll();
7669
+ startupPlan.claimDurableRows(persistedRows);
7309
7670
  // A name-hash placeholder whose verified cleartext row is also durable
7310
7671
  // was adopted earlier; the crash window between the two writes can
7311
7672
  // leave both. Never reactivate the placeholder. Record the adoption as
@@ -7381,10 +7742,10 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7381
7742
  // snapshot already read by the provenance phase. Load every persisted
7382
7743
  // row (not just rows under the activation cap) so a dormant subscription
7383
7744
  // still has the right signer when an operator activates it explicitly.
7384
- if (persistedMembershipRows !== null) {
7385
- const persistedContextGraphIds = new Set(rows.map((row) => row.id));
7386
- const localAgentAddresses = new Set([...this.localAgents.keys()].map((address) => address.toLowerCase()));
7387
- const newestApprovalByContextGraph = projectPersistedJoinApprovals(persistedMembershipRows, persistedContextGraphIds, localAgentAddresses);
7745
+ const newestApprovalByContextGraph = persistedMembershipRows === null
7746
+ ? null
7747
+ : projectPersistedJoinApprovals(persistedMembershipRows, new Set(rows.map((row) => row.id)), new Set([...this.localAgents.keys()].map((address) => address.toLowerCase())));
7748
+ if (newestApprovalByContextGraph) {
7388
7749
  for (const [contextGraphId, approval] of newestApprovalByContextGraph) {
7389
7750
  this.localApprovedAgentByCG.set(contextGraphId, approval.principalId);
7390
7751
  if (approval.curatorPeerId) {
@@ -7419,6 +7780,43 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7419
7780
  dormancyById.clear();
7420
7781
  const activatedRows = [];
7421
7782
  let activatedUserRows = 0;
7783
+ // #2815: every row's authority may need a chain read, and start() (with
7784
+ // the daemon API behind it) waits for this loop. Past the budget, a row
7785
+ // without a durable join approval is left dormant as
7786
+ // `authorityUnavailable` unread; background authority recovery resolves
7787
+ // it after start and activates it only once it resolves as allowed.
7788
+ const configuredAuthorityBudgetMs = this.config.contextGraphSubscriptionRehydrationAuthorityBudgetMs;
7789
+ let authorityBudgetMs = DEFAULT_REHYDRATION_STARTUP_AUTHORITY_BUDGET_MS;
7790
+ if (configuredAuthorityBudgetMs != null) {
7791
+ if (Number.isSafeInteger(configuredAuthorityBudgetMs)
7792
+ && configuredAuthorityBudgetMs >= 0
7793
+ && configuredAuthorityBudgetMs <= MAX_REHYDRATION_AUTHORITY_BUDGET_MS) {
7794
+ authorityBudgetMs = configuredAuthorityBudgetMs;
7795
+ }
7796
+ else {
7797
+ this.log.warn(ctx, `Ignoring invalid contextGraphSubscriptionRehydrationAuthorityBudgetMs=${configuredAuthorityBudgetMs} ` +
7798
+ `(must be a whole number of milliseconds from 0 to ${MAX_REHYDRATION_AUTHORITY_BUDGET_MS}); ` +
7799
+ `using default ${DEFAULT_REHYDRATION_STARTUP_AUTHORITY_BUDGET_MS}.`);
7800
+ }
7801
+ }
7802
+ const deferredIds = [];
7803
+ let deferredUserRows = 0;
7804
+ // Past the budget, a user row goes to background authority recovery only
7805
+ // while the activation cap still has room for it; beyond that it waits
7806
+ // for rolling activation unread, as a row beyond the cap always has.
7807
+ // Hosted rows are exempt from the cap and always go to recovery.
7808
+ const leaveUnresolved = (row) => {
7809
+ if (!row.coreHosted && cap > 0 && activatedUserRows + deferredUserRows >= cap) {
7810
+ dormancyById.set(row.id, 'activationCap');
7811
+ this.contextGraphSubscriptionRehydrationPendingIds.add(row.id);
7812
+ return;
7813
+ }
7814
+ if (!row.coreHosted)
7815
+ deferredUserRows += 1;
7816
+ dormancyById.set(row.id, 'authorityUnavailable');
7817
+ deferredIds.push(row.id);
7818
+ };
7819
+ authorityBudget = startRehydrationAuthorityBudget(authorityBudgetMs);
7422
7820
  for (let i = 0; i < toActivate.length; i++) {
7423
7821
  const row = toActivate[i];
7424
7822
  // The cap limits successful non-hosted activations, not candidates.
@@ -7434,7 +7832,29 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7434
7832
  const approvedAgentAddress = row.subscribed
7435
7833
  ? this.localApprovedAgentByCG.get(row.id)
7436
7834
  : undefined;
7437
- const hasJoinApproval = approvedAgentAddress !== undefined;
7835
+ let hasJoinApproval = approvedAgentAddress !== undefined;
7836
+ // The membership row is the restart hint, not the current requester
7837
+ // decision. A later explicit pending/rejected decision must retire a
7838
+ // stale join-approved hint instead of resurrecting its subscription in
7839
+ // restricted pending-metadata mode. Missing decision state remains the
7840
+ // compatibility shape for legacy persisted membership rows.
7841
+ if (approvedAgentAddress !== undefined) {
7842
+ try {
7843
+ const requesterState = await this.readRequesterJoinRequestState(row.id, approvedAgentAddress);
7844
+ hasJoinApproval = requesterState === null
7845
+ || requesterState.status === 'approved';
7846
+ }
7847
+ catch {
7848
+ hasJoinApproval = false;
7849
+ }
7850
+ }
7851
+ // A join-approved row keeps the synchronous path: only it can restore
7852
+ // the restricted pending-metadata bootstrap, which background
7853
+ // authority recovery does not offer.
7854
+ if (!hasJoinApproval && authorityBudget.spent()) {
7855
+ leaveUnresolved(row);
7856
+ continue;
7857
+ }
7438
7858
  // A crash between a historical false-ready sync and the approval
7439
7859
  // reset could leave all three persisted bits true. The durable
7440
7860
  // join-approved marker identifies a private bootstrap, so prove both
@@ -7458,7 +7878,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7458
7878
  // in-memory state needed for one authenticated metadata fetch. That
7459
7879
  // restricted path cannot activate data lanes until this same authority
7460
7880
  // resolver subsequently returns `allowed`.
7461
- const readAuthority = await this.resolveContextGraphSubscriptionBootstrapAuthority(row.id, {
7881
+ const authorityRead = this.resolveContextGraphSubscriptionBootstrapAuthority(row.id, {
7462
7882
  allowSubscriptionFallback: false,
7463
7883
  signal: AbortSignal.timeout(chainAuthorityReadBudgetsOf(this).requestTimeoutMs),
7464
7884
  durableSubscriptionBinding: {
@@ -7466,12 +7886,16 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7466
7886
  onChainId: row.onChainId,
7467
7887
  onChainHash: row.onChainHash,
7468
7888
  },
7469
- }).catch(() => ({
7470
- outcome: 'unavailable',
7471
- source: 'legacy-local',
7472
- reason: 'unexpected-authority-error',
7473
- metadataBootstrap: 'eligible',
7474
- }));
7889
+ }).catch((error) => unavailableContextGraphReadAuthorityDecision('legacy-local', 'unexpected-authority-error', contextGraphReadAuthorityDependencyOf(error)));
7890
+ // A read the budget stops waiting for ends on its own request
7891
+ // timeout; its late answer is ignored and activates nothing.
7892
+ const readAuthority = hasJoinApproval
7893
+ ? await authorityRead
7894
+ : await authorityBudget.race(authorityRead);
7895
+ if (readAuthority === REHYDRATION_AUTHORITY_DEFERRED) {
7896
+ leaveUnresolved(row);
7897
+ continue;
7898
+ }
7475
7899
  // A stale approval cannot override an explicit current membership
7476
7900
  // denial. The authority resolver supplies a typed bootstrap policy so
7477
7901
  // lifecycle code never infers security semantics from diagnostic text.
@@ -7519,7 +7943,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7519
7943
  const curatorPeerId = this.preferredSyncPeers.get(row.id);
7520
7944
  this.log.info(ctx, `Restored persisted context-graph subscription "${row.id}" in restricted pending-metadata mode; VM, payload recovery, and SWM remain closed`);
7521
7945
  if (curatorPeerId) {
7522
- void this.resumePendingJoinApprovalMetadata(row.id, curatorPeerId).catch((error) => {
7946
+ void this.recoverPendingJoinApprovalMetadata(row.id, curatorPeerId, newestApprovalByContextGraph?.get(row.id)?.curatorDialAddress).catch((error) => {
7523
7947
  this.log.warn(ctx, `Pending join-approval recovery for "${row.id}" stopped safely: ${error instanceof Error ? error.message : String(error)}`);
7524
7948
  });
7525
7949
  }
@@ -7579,13 +8003,23 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7579
8003
  if (dormancy.dormantReasons.authorityDenied.length > 0) {
7580
8004
  this.log.warn(ctx, `${dormancy.dormantReasons.authorityDenied.length} context-graph subscription(s) left dormant because current read authority denied this node.`);
7581
8005
  }
7582
- if (dormancy.dormantReasons.authorityUnavailable.length > 0) {
7583
- this.log.warn(ctx, `${dormancy.dormantReasons.authorityUnavailable.length} context-graph subscription(s) left dormant because current read authority was unavailable; retry after restoring the authority source.`);
8006
+ const unavailableAtStartup = dormancy.dormantReasons.authorityUnavailable.length - deferredIds.length;
8007
+ if (unavailableAtStartup > 0) {
8008
+ this.log.warn(ctx, `${unavailableAtStartup} context-graph subscription(s) left dormant because current read authority was unavailable; retry after restoring the authority source.`);
8009
+ }
8010
+ if (deferredIds.length > 0) {
8011
+ this.log.warn(ctx, `Stopped waiting on read authority for ${deferredIds.length} persisted context-graph subscription(s) ` +
8012
+ `after the ${authorityBudgetMs} ms startup budget. They stay dormant until background authority ` +
8013
+ `recovery resolves them as allowed.`);
7584
8014
  }
7585
8015
  }
7586
8016
  catch (err) {
7587
8017
  this.log.warn(ctx, `Failed to rehydrate persisted context-graph subscriptions: ${err instanceof Error ? err.message : String(err)}`);
7588
8018
  }
8019
+ finally {
8020
+ authorityBudget?.dispose();
8021
+ startupPlan.finish();
8022
+ }
7589
8023
  }
7590
8024
  /**
7591
8025
  * Operator recovery for #997: tear down every active in-memory subscription
@@ -7642,7 +8076,7 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7642
8076
  }
7643
8077
  }
7644
8078
  const activeUserIdsWithPendingStoreWrite = store
7645
- ? activeUserIds.filter((id) => this.contextGraphSubscriptionPersistChains.has(id))
8079
+ ? activeUserIds.filter((id) => this.contextGraphSubscriptionPersistence.hasLane(id))
7646
8080
  : [];
7647
8081
  const storeDeleteIds = [...new Set([...persistedUserIds, ...activeUserIdsWithPendingStoreWrite])];
7648
8082
  const total = storeDeleteIds.length;
@@ -7726,10 +8160,10 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7726
8160
  }, normalizedContextGraphId, input),
7727
8161
  }, contextGraphId);
7728
8162
  }
7729
- async hasConfirmedMetaState(contextGraphId, options) {
8163
+ async hasConfirmedMetaState(contextGraphId, options = {}) {
7730
8164
  return confirmContextGraphMetadataV1({
7731
8165
  chain: this.chain,
7732
- resolveActivePublicChainProof: () => this.resolveActivePublicContextGraphChainProof(contextGraphId, createOperationContext('sync'), options?.signal),
8166
+ resolveActivePublicChainProof: () => this.resolveActivePublicContextGraphChainProof(contextGraphId, createOperationContext('sync'), options.signal),
7733
8167
  isPrivateContextGraph: (id) => this.isPrivateContextGraph(id),
7734
8168
  localApprovedAgentByContextGraph: this.localApprovedAgentByCG,
7735
8169
  peerId: this.peerId,
@@ -7737,6 +8171,46 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7737
8171
  subscriptions: this.subscribedContextGraphs,
7738
8172
  }, contextGraphId, options);
7739
8173
  }
8174
+ /**
8175
+ * Join bootstrap completion: the local metadata proves this node's approved
8176
+ * member, judged with the same acceptance the snapshot refresh used.
8177
+ */
8178
+ hasConfirmedApprovedMemberMetaState(contextGraphId, acceptance) {
8179
+ return this.hasConfirmedMetaState(contextGraphId, { purpose: 'approved-member', acceptance });
8180
+ }
8181
+ /**
8182
+ * The one approved-member acceptance a join attempt is judged with: this
8183
+ * node's approval binding, its libp2p peer and operational key, and the
8184
+ * authenticated access policy (#2831 review). The curator refresh and join
8185
+ * completion both consume this same value. `undefined` without an approval
8186
+ * binding.
8187
+ *
8188
+ * The policy is `public` only when the graph's SWM transport authority is
8189
+ * plaintext: registered public, or unregistered under an active accepted
8190
+ * owner-signed public policy (see classifySwmTransportAuthority). A retained
8191
+ * snapshot therefore never outvotes a registration the index shows. Private,
8192
+ * approved-private-replica, legacy-unregistered or unavailable authority, or
8193
+ * an unreadable chain, is `unproven`, which admits only the complete private
8194
+ * definition.
8195
+ */
8196
+ async resolveApprovedMemberAcceptance(contextGraphId) {
8197
+ const approvedAgentAddress = this.localApprovedAgentByCG.get(contextGraphId);
8198
+ if (!approvedAgentAddress)
8199
+ return undefined;
8200
+ let expectedDelegateeOpKey;
8201
+ try {
8202
+ expectedDelegateeOpKey = await inferAdapterPublisherAddress(this.chain);
8203
+ }
8204
+ catch {
8205
+ // The signed join flow always binds the current libp2p peer, so an
8206
+ // adapter that cannot expose its op-key still has a usable proof.
8207
+ }
8208
+ return resolveApprovedMemberAcceptanceDecision({
8209
+ approvedAgentAddress,
8210
+ expectedDelegateePeerId: this.peerId,
8211
+ expectedDelegateeOpKey,
8212
+ }, () => this.resolveSwmTransportAuthority(contextGraphId, { authorityReadMode: 'finalized-index-or-live' }));
8213
+ }
7740
8214
  async hasConfirmedSharedMemoryMetaState(contextGraphId) {
7741
8215
  return this.hasConfirmedMetaState(contextGraphId);
7742
8216
  }
@@ -7745,8 +8219,13 @@ export class LifecycleSyncMethods extends DKGAgentBase {
7745
8219
  // The accepted snapshot is itself finalized, name-bound authority for a
7746
8220
  // catalog-owned graph. It replaces both the legacy registration read and
7747
8221
  // its metadata-bootstrap proof at this internal transport boundary.
7748
- if (acceptedRfc64Authority !== undefined)
7749
- return acceptedRfc64Authority;
8222
+ if (acceptedRfc64Authority === true)
8223
+ return true;
8224
+ // A private graph whose RFC-64 authority is not active keeps the legacy
8225
+ // member checks below (#2858); a refusal by an active authority stands.
8226
+ if (acceptedRfc64Authority === false
8227
+ && !(await this.rfc64PrivateRootSwmOnLegacyLaneV1(contextGraphId)))
8228
+ return false;
7750
8229
  if (!(await this.hasConfirmedSharedMemoryMetaState(contextGraphId))) {
7751
8230
  return false;
7752
8231
  }