@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
@@ -7,59 +7,30 @@
7
7
  * 1:1 move; methods take `this: DKGAgent` so cross-calls resolve against the
8
8
  * composed class.
9
9
  */
10
+ import { collectProjectedDelegatees } from './internal/workspace-projected-delegatees.js';
10
11
  import { createHash, randomUUID } from 'node:crypto';
11
- import { PROTOCOL_SWM_SENDER_KEY, encodeGossipEnvelope, computeGossipSigningPayload, GOSSIP_ENVELOPE_VERSION, GOSSIP_TYPE_WORKSPACE_PUBLISH, createOperationContext, logKaLifecycleEvent, WORKSPACE_AGENT_ENCRYPTION_KEY_ALGORITHM_X25519, WORKSPACE_RECIPIENT_ENCRYPTION_KEY_PURPOSE, decodeWorkspaceEncryptionKey, SWM_SENDER_KEY_PACKAGE_ACK_TYPE, SWM_SENDER_KEY_PACKAGE_ACK_RETRYABLE_REASON_CODES, SWM_SENDER_KEY_PACKAGE_VERSION, computeSwmSenderKeyMembershipHash, computeSwmSenderKeyPackageAAD, decodeWorkspacePublishRequest, decodeSwmSenderKeyPackage, decodeSwmSenderKeyPackageAck, decryptSwmSenderKeyMessage, decryptSwmSenderKeyPackage, encodeSwmSenderKeyMessage, encodeSwmSenderKeyPackage, encodeSwmSenderKeyPackageAck, encryptSwmSenderKeyMessage, encryptSwmSenderKeyPackage, generateEd25519Keypair, generateSwmSenderChainKey, generateSwmSenderEpochId, ratchetSwmSenderChainKey, uint64ForProto, SWM_SENDER_KEY_SKIPPED_MESSAGE_CACHE_LIMIT, } from '@origintrail-official/dkg-core';
12
+ import { PROTOCOL_SWM_SENDER_KEY, encodeGossipEnvelope, computeGossipSigningPayload, GOSSIP_ENVELOPE_VERSION, GOSSIP_TYPE_WORKSPACE_PUBLISH, createOperationContext, logKaLifecycleEvent, WORKSPACE_AGENT_ENCRYPTION_KEY_ALGORITHM_X25519, WORKSPACE_RECIPIENT_ENCRYPTION_KEY_PURPOSE, decodeWorkspaceEncryptionKey, SWM_SENDER_KEY_PACKAGE_ACK_TYPE, SWM_SENDER_KEY_PACKAGE_ACK_RETRYABLE_REASON_CODES, SWM_SENDER_KEY_PACKAGE_VERSION, computeSwmSenderKeyMembershipHash, computeSwmSenderKeyPackageAAD, decodeWorkspacePublishRequest, decodeSwmSenderKeyPackage, decodeSwmSenderKeyPackageAck, decryptSwmSenderKeyMessage, decryptSwmSenderKeyPackage, encodeSwmSenderKeyMessage, encodeSwmSenderKeyPackage, encodeSwmSenderKeyPackageAck, encryptSwmSenderKeyMessage, encryptSwmSenderKeyPackage, generateEd25519Keypair, generateSwmSenderChainKey, generateSwmSenderEpochId, ratchetSwmSenderChainKey, uint64ForProto, SWM_SENDER_KEY_SKIPPED_MESSAGE_CACHE_LIMIT, tryCanonicalPeerIdString, } from '@origintrail-official/dkg-core';
12
13
  import { createRpcTimeoutError, withRpcRequestContext } from '@origintrail-official/dkg-chain';
13
- import { resolveWorkspaceAgentRecipients, resolveWorkspaceAgentRecipientKeys, } from '@origintrail-official/dkg-publisher';
14
+ import { resolveWorkspaceAgentRecipients, resolveWorkspaceAgentRecipientKeys, isWorkspaceAgentEncryptionKeyMissingError, WorkspaceAgentEncryptionKeyMissingError, } from '@origintrail-official/dkg-publisher';
14
15
  import { ethers } from 'ethers';
15
16
  import { resolveActivePublicContextGraphChainProof as resolveStrictActivePublicChainProof, } from './active-public-context-graph-chain-proof.js';
16
17
  import { resolveContextGraphAgentGateAuthorityDecision, } from './internal/context-graph-authority/context-graph-agent-gate-authority.js';
17
18
  import { resolveLiveOnChainAccessPolicyState as resolveLiveAccessPolicyState, } from './internal/context-graph-authority/context-graph-access-policy.js';
18
- import { createContextGraphAuthorityError, } from './internal/context-graph-authority/context-graph-authority.js';
19
+ import { createContextGraphAuthorityError, isContextGraphAuthorityUnavailableMarker, isRetryableContextGraphAuthorityUnavailableReason, } from './internal/context-graph-authority/context-graph-authority.js';
20
+ import { resolveSwmMemberRecoveryAuthorityDecision, resolveSwmRegisteredAuthorityDecision, resolveSwmTransportAuthorityDecision, } from './internal/context-graph-authority/swm-transport-authority.js';
19
21
  import { FANOUT_RESPONSE_REJECTED, FANOUT_RESPONSE_RETRYABLE, } from './swm/substrate-fanout.js';
20
22
  import { SyncTargetSupersededError } from './sync/error-tags.js';
21
23
  import { resolveAssetUalFromKaIdentity } from './ka-identity.js';
22
- import { TIMEOUT_SENTINEL, CHAIN_POLICY_READ_TIMEOUT_MS, SWM_SENDER_KEY_PENDING_DRAIN_LOG_CTX, } from './dkg-agent-constants.js';
24
+ import { SWM_RECIPIENT_KEY_FETCH_WAIT_MS, TIMEOUT_SENTINEL, CHAIN_POLICY_READ_TIMEOUT_MS, SWM_SENDER_KEY_PENDING_DRAIN_LOG_CTX, } from './dkg-agent-constants.js';
23
25
  import { chainAuthorityReadBudgetsOf } from './chain-authority-read-budgets.js';
24
26
  import { isBoundedOperationTimeoutError, runBoundedOperation, } from './bounded-operation.js';
25
27
  import { StaleSenderKeyTargetError, SwmSenderKeySetupRejectionError, } from './dkg-agent-types.js';
26
- import { swmSenderStateKey, swmReceiverStateKey, serializeSwmSenderSendState, serializeSwmSenderReceiveState, serializePendingSenderKeyEntry, deserializeSwmSenderSendState, deserializeSwmSenderReceiveState, deserializePendingSenderKeyEntry, } from './dkg-agent-swm-state.js';
28
+ import { computeSwmSenderKeyRecipientRouteHash, swmSenderStateKey, swmReceiverStateKey, serializeSwmSenderSendState, serializeSwmSenderReceiveState, serializePendingSenderKeyEntry, deserializeSwmSenderSendState, deserializeSwmSenderReceiveState, deserializePendingSenderKeyEntry, } from './dkg-agent-swm-state.js';
27
29
  import { DKGAgentBase } from './dkg-agent-base.js';
28
- import { localContextGraphIdMatchesCommittedNameHash } from './context-graph-binding-state.js';
30
+ import { isCanonicalPositiveContextGraphId, localContextGraphIdMatchesCommittedNameHash, } from './context-graph-binding-state.js';
29
31
  import { CONTEXT_GRAPH_AUTHORITY_RPC_SITES as CG_AUTH_RPC_SITES, withRpcUsageSite, } from '@origintrail-official/dkg-chain';
30
32
  const KA_LIFECYCLE_ASSET_UAL_RESOLVE_TIMEOUT_MS = 50;
31
- function delegationIsCurrentlyActive(expiresAtValues, nowMs) {
32
- if (expiresAtValues.length === 0)
33
- return true;
34
- return expiresAtValues.some((value) => {
35
- const expiresAt = Number(value);
36
- return !Number.isFinite(expiresAt) || expiresAt <= 0 || expiresAt >= nowMs;
37
- });
38
- }
39
- function collectProjectedDelegatees(meta, field, normalizeValue) {
40
- const members = new Set([...meta.allowedAgents, ...meta.participantAgents].map((agent) => agent.toLowerCase()));
41
- const revoked = new Set(meta.revokedAgents.map((agent) => agent.toLowerCase()));
42
- const out = new Map();
43
- const nowMs = Date.now();
44
- for (const delegation of meta.delegations) {
45
- if (!delegationIsCurrentlyActive(delegation.expiresAtValues, nowMs))
46
- continue;
47
- for (const rawAgent of delegation.agents) {
48
- const agent = rawAgent.toLowerCase();
49
- if (!agent || !members.has(agent) || revoked.has(agent))
50
- continue;
51
- const values = out.get(agent) ?? [];
52
- for (const rawValue of delegation[field]) {
53
- const value = normalizeValue(rawValue);
54
- if (value && !values.includes(value))
55
- values.push(value);
56
- }
57
- if (values.length > 0)
58
- out.set(agent, values);
59
- }
60
- }
61
- return out;
62
- }
33
+ const SWM_RECIPIENT_AUTHORITY_STABILITY_ATTEMPTS = 3;
63
34
  function mapContextGraphSlotBindingOutcome(outcome, mode) {
64
35
  if (outcome.kind === 'match')
65
36
  return true;
@@ -172,6 +143,62 @@ function bindLiveAuthorityRead(chain, read, freshness) {
172
143
  freshness,
173
144
  });
174
145
  }
146
+ /**
147
+ * The recipient-key failure a sender reports once fetching cannot help: why
148
+ * the keys are unknown and what gets them here (#2849).
149
+ */
150
+ function withMemberKeyHint(error) {
151
+ const { agentAddresses } = error;
152
+ const one = agentAddresses.length === 1;
153
+ return new WorkspaceAgentEncryptionKeyMissingError(agentAddresses, `${new WorkspaceAgentEncryptionKeyMissingError(agentAddresses).message}: this node has neither `
154
+ + (one ? 'a join request from the agent nor its profile. Have the member' : 'join requests from these agents nor their profiles. Have each member')
155
+ + ' join through an invite, or retry once '
156
+ + (one ? 'its profile has' : 'their profiles have')
157
+ + ' reached this node (profiles are re-published about every 20 minutes).');
158
+ }
159
+ function hasExactRecipientAgentRoster(resolution, participantAgents) {
160
+ try {
161
+ const resolvedAgents = new Set(resolution.recipients.map(({ agentAddress }) => ethers.getAddress(agentAddress).toLowerCase()));
162
+ const currentAgents = new Set(participantAgents.map((address) => ethers.getAddress(address).toLowerCase()));
163
+ return currentAgents.size === resolvedAgents.size
164
+ && [...currentAgents].every((address) => resolvedAgents.has(address));
165
+ }
166
+ catch {
167
+ return false;
168
+ }
169
+ }
170
+ function hasExactWorkspaceRecipientSet(left, right) {
171
+ const canonical = (recipient) => [
172
+ ethers.getAddress(recipient.agentAddress).toLowerCase(),
173
+ recipient.recipientKeyId,
174
+ recipient.peerId ?? '',
175
+ ].join('\u0000');
176
+ try {
177
+ const leftRecipients = left.recipients.map(canonical).sort();
178
+ const rightRecipients = right.recipients.map(canonical).sort();
179
+ return leftRecipients.length === rightRecipients.length
180
+ && leftRecipients.every((recipient, index) => recipient === rightRecipients[index]);
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ }
186
+ function sameStringSet(left, right) {
187
+ const leftSet = new Set(left);
188
+ const rightSet = new Set(right);
189
+ return leftSet.size === rightSet.size && [...leftSet].every((value) => rightSet.has(value));
190
+ }
191
+ function pendingSenderKeyEntryMatchesDrainAuthority(entry, authority) {
192
+ return entry.contextGraphId === authority.contextGraphId
193
+ && (authority.allSubgraphs === true
194
+ || (entry.subGraphName ?? undefined) === (authority.subGraphName ?? undefined))
195
+ && entry.recipientAgentAddress === authority.recipientAgentAddress
196
+ && entry.recipientKeyId === authority.recipientKeyId
197
+ && entry.recipientPeerId === authority.recipientPeerId
198
+ && (authority.senderAgentAddress === undefined
199
+ || entry.senderAgentAddress === authority.senderAgentAddress)
200
+ && (authority.epochId === undefined || entry.epochId === authority.epochId);
201
+ }
175
202
  export class WorkspaceCryptoMethods extends DKGAgentBase {
176
203
  getWorkspaceGossipSigningAgent() {
177
204
  const defaultAddress = this.defaultAgentAddress?.toLowerCase();
@@ -227,8 +254,8 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
227
254
  async resolveContextGraphAgentGateAuthority(contextGraphId, options = {}) {
228
255
  return withRpcUsageSite(CG_AUTH_RPC_SITES.gate, () => resolveContextGraphAgentGateAuthorityDecision({
229
256
  contextGraphId,
230
- getRegisteredAuthority: () => this.resolveRegisteredContextGraphAuthority(contextGraphId, { signal: options.signal }),
231
- resolveRfc64PrivateRoster: () => this.resolveRfc64PrivateReadRosterV1(contextGraphId),
257
+ getTransportAuthority: () => this.resolveSwmTransportAuthority(contextGraphId, { signal: options.signal }),
258
+ readMetadataRevision: () => this.contextGraphMetaProjection.readAuthorityFactsRevision,
232
259
  getLegacyMeta: () => this.getCgMeta(contextGraphId, { signal: options.signal }),
233
260
  getSubscriptionAgents: () => (this.subscribedContextGraphs.get(contextGraphId)?.participantAgents ?? []),
234
261
  }));
@@ -243,32 +270,89 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
243
270
  return [];
244
271
  }
245
272
  /**
246
- * R9 (SECURITY) — FRESH, `_meta`-only member-recovery gate.
273
+ * R9 (SECURITY) — authoritative member-recovery gate.
247
274
  *
248
- * Resolves `allowedAgents ∪ participantAgents` minus `revokedAgents` from the
249
- * CG `_meta` projection (store-backed, write-invalidated), with the
250
- * network-influenced `subscribedContextGraphs` subscription cache
251
- * DELIBERATELY OMITTED — that cache is poisonable, and folding it in is
252
- * exactly what `member-recovery-auth.ts` forbids.
275
+ * Registered and active accepted-private graphs use their exact authority
276
+ * roster. Only a legacy unregistered graph (including accepted public, whose
277
+ * local gate controls recovery rather than reads) resolves the effective
278
+ * store-backed metadata projection of
279
+ * `allowedAgents ∪ participantAgents` minus `revokedAgents` from the CG
280
+ * metadata. The network-influenced `subscribedContextGraphs`
281
+ * subscription cache is DELIBERATELY OMITTED — that cache is poisonable, and
282
+ * folding it in is exactly what `member-recovery-auth.ts` forbids.
253
283
  *
254
284
  * Unlike {@link getContextGraphAgentGateAddresses} (which also feeds normal
255
285
  * sync admission and may fold in the subscription cache only for graphs that
256
286
  * are not registered on-chain), this read is used ONLY for `request.recovery`
257
287
  * and is passed straight to
258
288
  * `isMemberRecoveryAuthorized`, which hard-denies on null/empty. Returns
259
- * `null` when the CG has no `_meta` agent gate at all (⇒ hard-deny).
289
+ * `null` when the CG has no projected agent gate at all (⇒ hard-deny).
260
290
  */
261
291
  async getMemberRecoveryGate(contextGraphId, options = {}) {
262
- const registeredAuthority = await withRpcUsageSite(CG_AUTH_RPC_SITES.recoveryGate, () => this.resolveRegisteredContextGraphAuthority(contextGraphId, { signal: options.signal }));
263
- if (registeredAuthority.kind === 'private')
264
- return registeredAuthority.participantAgents;
265
- if (registeredAuthority.kind !== 'unregistered')
292
+ const recoveryAuthority = await withRpcUsageSite(CG_AUTH_RPC_SITES.recoveryGate, () => resolveSwmMemberRecoveryAuthorityDecision(this, contextGraphId, { signal: options.signal }));
293
+ if (recoveryAuthority.kind === 'private-roster') {
294
+ return [...recoveryAuthority.participantAgents];
295
+ }
296
+ if (recoveryAuthority.kind !== 'legacy-unregistered')
266
297
  return null;
298
+ const metadataRevision = this.contextGraphMetaProjection
299
+ .readContextGraphAuthorityFactsRevision(contextGraphId);
300
+ const metadataGate = await this.getLocalMetadataMemberRecoveryGate(contextGraphId, options);
301
+ // Metadata is another async boundary. Re-resolve the authoritative state
302
+ // before returning it so a private policy activation/rotation or a chain
303
+ // registration that commits during the store read takes precedence over
304
+ // the now-stale local projection.
305
+ const currentRecoveryAuthority = await withRpcUsageSite(CG_AUTH_RPC_SITES.recoveryGate, () => resolveSwmMemberRecoveryAuthorityDecision(this, contextGraphId, { signal: options.signal }));
306
+ if (currentRecoveryAuthority.kind === 'private-roster') {
307
+ return [...currentRecoveryAuthority.participantAgents];
308
+ }
309
+ if (currentRecoveryAuthority.kind !== 'legacy-unregistered')
310
+ return null;
311
+ // A revocation or other authority-fact mutation during the metadata read
312
+ // invalidates the captured roster even if registration remained absent.
313
+ // Recovery is retryable, so fail closed instead of serving that snapshot.
314
+ return this.contextGraphMetaProjection
315
+ .readContextGraphAuthorityFactsRevision(contextGraphId) === metadataRevision
316
+ ? metadataGate
317
+ : null;
318
+ }
319
+ /**
320
+ * Authority source used while constructing or mutating a private roster.
321
+ * Registered private graphs retain their finalized chain participant set;
322
+ * unregistered graphs use the effective store-backed metadata projection.
323
+ * This deliberately ignores an accepted-private overlay roster so rotation
324
+ * does not ask the roster it is replacing to define its own successor.
325
+ */
326
+ async getMemberRecoveryRosterSource(contextGraphId, options = {}) {
327
+ const registered = await this.resolveSwmRegisteredAuthority(contextGraphId, { signal: options.signal });
328
+ if (registered.kind === 'private')
329
+ return [...registered.participantAgents];
330
+ if (registered.kind !== 'unregistered')
331
+ return null;
332
+ const metadataRevision = this.contextGraphMetaProjection
333
+ .readContextGraphAuthorityFactsRevision(contextGraphId);
334
+ const metadataGate = await this.getLocalMetadataMemberRecoveryGate(contextGraphId, options);
335
+ const currentRegistered = await this.resolveSwmRegisteredAuthority(contextGraphId, { signal: options.signal });
336
+ if (currentRegistered.kind === 'private') {
337
+ return [...currentRegistered.participantAgents];
338
+ }
339
+ if (currentRegistered.kind !== 'unregistered')
340
+ return null;
341
+ return this.contextGraphMetaProjection
342
+ .readContextGraphAuthorityFactsRevision(contextGraphId) === metadataRevision
343
+ ? metadataGate
344
+ : null;
345
+ }
346
+ /**
347
+ * Fresh effective store-backed metadata member set. This deliberately stays
348
+ * separate from the transport-authoritative recovery decision.
349
+ */
350
+ async getLocalMetadataMemberRecoveryGate(contextGraphId, options = {}) {
267
351
  const seen = new Set();
268
352
  const agents = [];
269
353
  const meta = await this.getCgMeta(contextGraphId, { signal: options.signal });
270
354
  if (meta.allowedAgents.length === 0 && meta.participantAgents.length === 0) {
271
- return null; // no _meta agent gate ⇒ hard-deny at the recovery gate
355
+ return null; // no projected agent gate ⇒ hard-deny at the recovery gate
272
356
  }
273
357
  const revoked = new Set(meta.revokedAgents.map((addr) => addr.toLowerCase()));
274
358
  const add = (value) => {
@@ -494,7 +578,24 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
494
578
  const trimmed = contextGraphId.trim();
495
579
  let onChainId = null;
496
580
  let resolvedFromLocalCg = false;
497
- if (typeof this.getContextGraphOnChainId === 'function') {
581
+ if (this.chain?.contextGraphAuthorityIndexRevisionReader !== undefined
582
+ && typeof this.resolveContextGraphRegistrationBinding === 'function'
583
+ && !isCanonicalPositiveContextGraphId(trimmed)) {
584
+ // An indexed adapter takes the identity from the finalized registration
585
+ // binding too, never from a live registry range scan (#2827 follow-up).
586
+ // Finalized absence is `unregistered`, as a scan's miss was; any other
587
+ // unanswered read is `unknown`.
588
+ const binding = await this.resolveContextGraphRegistrationBinding(contextGraphId, { signal });
589
+ if (binding.kind === 'registered') {
590
+ onChainId = binding.onChainId.toString();
591
+ resolvedFromLocalCg = true;
592
+ }
593
+ else if (binding.kind === 'unavailable'
594
+ && binding.reason !== 'finalized-name-absence-unaccepted') {
595
+ return 'unknown';
596
+ }
597
+ }
598
+ else if (typeof this.getContextGraphOnChainId === 'function') {
498
599
  onChainId = await this.getContextGraphOnChainId(contextGraphId, { signal });
499
600
  if (onChainId)
500
601
  resolvedFromLocalCg = true;
@@ -553,6 +654,96 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
553
654
  this.onChainAccessPolicyCache.set(onChainId, accessPolicy);
554
655
  return accessPolicy;
555
656
  }
657
+ /**
658
+ * Registered-chain authority for the SWM consumers that need the raw roster,
659
+ * the agent gate and member recovery (#2827). The policy, and why the
660
+ * finalized authority index is the only registration evidence, live in
661
+ * {@link resolveSwmRegisteredAuthorityDecision}.
662
+ */
663
+ resolveSwmRegisteredAuthority(contextGraphId, options = {}) {
664
+ return resolveSwmRegisteredAuthorityDecision(this, contextGraphId, options);
665
+ }
666
+ /**
667
+ * How SWM on this graph may travel, for both ends of the wire
668
+ * ({@link resolveSwmTransportAuthorityDecision}).
669
+ */
670
+ resolveSwmTransportAuthority(contextGraphId, options = {}) {
671
+ return resolveSwmTransportAuthorityDecision(this, contextGraphId, options);
672
+ }
673
+ /**
674
+ * Resolve the transport peer gate that applies to inbound SWM traffic.
675
+ *
676
+ * Ordinary graphs retain the legacy merged metadata projection. A graph
677
+ * carrying a durable local join approval must instead use the peer roster
678
+ * from the same source-qualified proof that authorized its private replica;
679
+ * falling back to the merged projection there would let an unrelated
680
+ * AGENTS/ONTOLOGY row widen the inbound gate. Registration (or a proven
681
+ * public policy) supersedes that participant proof and keeps the established
682
+ * registered/public behaviour.
683
+ */
684
+ async resolveApprovedPrivateReplicaSwmAllowedPeersOverride(contextGraphId) {
685
+ if (!this.localApprovedAgentByCG.has(contextGraphId)) {
686
+ return undefined;
687
+ }
688
+ const transport = await this.resolveSwmTransportAuthority(contextGraphId, {
689
+ authorityReadMode: 'finalized-index-or-live',
690
+ });
691
+ switch (transport.kind) {
692
+ case 'approved-private-replica':
693
+ // An empty proved list is an authoritative open peer gate. Keep it
694
+ // distinct from `undefined` (this override does not apply) so the
695
+ // SharedMemoryHandler projection wrapper never falls back to a merged
696
+ // secondary-source row.
697
+ return [...new Set(transport.allowedPeers)];
698
+ case 'plaintext':
699
+ case 'private-roster':
700
+ return undefined;
701
+ case 'unavailable':
702
+ throw createContextGraphAuthorityError(`Context graph "${contextGraphId}" SWM peer gate authority is unavailable (${transport.reason})`, transport);
703
+ case 'legacy-unregistered':
704
+ // The approval may have been removed while the authority read was in
705
+ // flight. Only that transition restores ordinary legacy behaviour.
706
+ if (!this.localApprovedAgentByCG.has(contextGraphId)) {
707
+ return undefined;
708
+ }
709
+ throw createContextGraphAuthorityError(`Context graph "${contextGraphId}" still has a local join approval but no approved private replica authority`, {
710
+ reason: 'finalized-name-absence-unaccepted',
711
+ detail: 'approved private replica authority did not survive current SWM authority resolution',
712
+ });
713
+ }
714
+ }
715
+ /** List/null adapter for SWM consumers that do not consume meta records. */
716
+ async resolveSwmAllowedPeersForCurrentAuthority(contextGraphId) {
717
+ const approvedReplicaOverride = await this.resolveApprovedPrivateReplicaSwmAllowedPeersOverride(contextGraphId);
718
+ if (approvedReplicaOverride === undefined) {
719
+ return this.getContextGraphAllowedPeers(contextGraphId);
720
+ }
721
+ return approvedReplicaOverride.length > 0 ? approvedReplicaOverride : null;
722
+ }
723
+ /**
724
+ * Whether SWM on this graph is public-readable, so plaintext may be both
725
+ * sent and accepted. One predicate for both ends of the wire: the sender's
726
+ * recipient resolver and the receiver's plaintext oracle.
727
+ *
728
+ * Without an active accepted owner-signed public policy it is exactly the
729
+ * live on-chain probe (isContextGraphPublicOnChain). With one, it is the
730
+ * `plaintext` transport authority of {@link resolveSwmTransportAuthority},
731
+ * the same answer the sender's recipient selection uses.
732
+ */
733
+ async isContextGraphSwmPublic(contextGraphId, opCtx) {
734
+ if (!this.hasActiveAcceptedRfc64PublicUnregisteredAuthorityV1(contextGraphId)) {
735
+ return this.isContextGraphPublicOnChain(contextGraphId, opCtx);
736
+ }
737
+ try {
738
+ const transport = await withRpcUsageSite(CG_AUTH_RPC_SITES.publicProbe, () => this.resolveSwmTransportAuthority(contextGraphId, { authorityReadMode: 'finalized-index-or-live' }));
739
+ return transport.kind === 'plaintext';
740
+ }
741
+ catch (err) {
742
+ this.log.warn(opCtx ?? createOperationContext('share'), `isContextGraphSwmPublic(${contextGraphId}) could not resolve registered authority — `
743
+ + `treating the graph as NOT public (fail-closed): ${err instanceof Error ? err.message : String(err)}`);
744
+ return false;
745
+ }
746
+ }
556
747
  /**
557
748
  * True iff `contextGraphId` is DEFINITIVELY public per its on-chain
558
749
  * access policy (policy enum `0`). Gates SWM encryption: an on-chain
@@ -820,9 +1011,18 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
820
1011
  * avoids the resolver's "Missing public encryption key" throw for an
821
1012
  * allowlisted agent whose key isn't locally available — irrelevant for
822
1013
  * a public CG that never encrypts. Private graphs resolve recipients from
823
- * the live roster; unavailable registered authority fails closed.
1014
+ * the live roster; unavailable registered authority fails closed. An
1015
+ * unregistered graph whose accepted owner-signed policy is public is
1016
+ * treated like an on-chain public one. An approved private replica retains
1017
+ * the full effective metadata roster, while any explicit graph peer
1018
+ * allowlist restricts the recipient keys available to every roster member.
824
1019
  */
825
1020
  async resolveWorkspaceRecipientsGated(input) {
1021
+ // Hydrate durable sender-key state before resolving recipients. The
1022
+ // publisher invokes the encryptor synchronously after this resolver, so
1023
+ // this keeps state I/O out of the authority-fenced interval between the
1024
+ // final recipient recheck and sender-key epoch selection/creation.
1025
+ await this.loadSwmSenderKeyState();
826
1026
  return this.resolveWorkspaceAgentRecipientsForCurrentAuthority(input);
827
1027
  }
828
1028
  /**
@@ -842,60 +1042,231 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
842
1042
  * current chain state (`requireLiveRosterForPrivate`), never from the index.
843
1043
  */
844
1044
  async resolveWorkspaceAgentRecipientsForCurrentAuthority(input) {
845
- const registeredAuthority = await withRpcUsageSite(CG_AUTH_RPC_SITES.recipients, () => this.resolveRegisteredContextGraphAuthority(input.contextGraphId, {
1045
+ // The receiver decides plaintext from this same transport authority
1046
+ // (isContextGraphSwmPublic), so the two ends cannot disagree (#2827).
1047
+ const transport = await withRpcUsageSite(CG_AUTH_RPC_SITES.recipients, () => this.resolveSwmTransportAuthority(input.contextGraphId, {
846
1048
  authorityReadMode: 'finalized-index-or-live',
847
1049
  requireLiveRosterForPrivate: true,
848
1050
  }));
849
- if (registeredAuthority.kind === 'unregistered') {
850
- return resolveWorkspaceAgentRecipients(this.store, input);
851
- }
852
- if (registeredAuthority.kind === 'public') {
1051
+ if (transport.kind === 'plaintext') {
853
1052
  return { requiresEncryption: false, recipients: [] };
854
1053
  }
855
- if (registeredAuthority.kind === 'unavailable') {
856
- const message = `Registered context graph "${input.contextGraphId}" authority is unavailable (${registeredAuthority.reason})`;
857
- throw createContextGraphAuthorityError(message, registeredAuthority);
858
- }
859
- if (registeredAuthority.participantAgents.length === 0) {
860
- throw new Error(`Registered context graph "${input.contextGraphId}" requires encrypted SWM gossip but its authoritative chain roster is empty or unavailable`);
861
- }
862
- const allowedPeers = await this.getContextGraphAllowedPeers(input.contextGraphId);
863
- const allowedPeerSet = allowedPeers === null ? null : new Set(allowedPeers);
864
- // Resolve only the live chain-authorized addresses. Filtering a completed
865
- // local resolution afterward is too late: stale removed members can have
866
- // malformed/missing key metadata that makes the local resolver throw
867
- // before the chain intersection is reached, blocking every post-revoke
868
- // write until the local cleanup retry succeeds.
869
- const recipients = [];
870
- for (const agentAddress of registeredAuthority.participantAgents) {
871
- const agentRecipients = await resolveWorkspaceAgentRecipientKeys(this.store, agentAddress);
872
- const authorizedRecipients = allowedPeerSet === null
873
- ? agentRecipients
874
- : agentRecipients.filter((recipient) => (recipient.peerId !== undefined && allowedPeerSet.has(recipient.peerId)));
875
- if (authorizedRecipients.length === 0) {
876
- throw new Error(`Registered context graph "${input.contextGraphId}" requires encrypted SWM gossip but `
877
- + `chain-authorized DKG agent ${ethers.getAddress(agentAddress)} has no recipient key `
878
- + 'advertised by a peer in the context graph allowlist');
879
- }
880
- recipients.push(...authorizedRecipients);
881
- }
882
- const [firstRecipient, ...remainingRecipients] = recipients;
883
- if (!firstRecipient) {
884
- throw new Error(`Registered context graph "${input.contextGraphId}" requires encrypted SWM gossip but has no chain-authorized DKG agent recipients`);
1054
+ let recipientAuthorityRevision = null;
1055
+ let resolveKeys;
1056
+ if (transport.kind === 'legacy-unregistered') {
1057
+ resolveKeys = async () => {
1058
+ const attemptRevision = this.contextGraphMetaProjection.readAuthorityFactsRevision;
1059
+ const resolution = await resolveWorkspaceAgentRecipients(this.store, input);
1060
+ recipientAuthorityRevision = attemptRevision;
1061
+ return resolution;
1062
+ };
1063
+ }
1064
+ else if (transport.kind === 'approved-private-replica') {
1065
+ // Resolve the complete effective metadata roster first. Participant
1066
+ // approval authorizes this receiver; it is not a replacement roster.
1067
+ // The peer gate comes from the same source-qualified, revision-fenced
1068
+ // proof as the transport classification, never the merged projection.
1069
+ resolveKeys = async () => {
1070
+ const attemptRevision = this.contextGraphMetaProjection.readAuthorityFactsRevision;
1071
+ const resolution = await resolveWorkspaceAgentRecipients(this.store, input);
1072
+ if (!resolution.requiresEncryption) {
1073
+ throw new Error(`Approved private replica "${input.contextGraphId}" resolved a plaintext SWM roster`);
1074
+ }
1075
+ if (transport.allowedPeers.length === 0) {
1076
+ recipientAuthorityRevision = attemptRevision;
1077
+ return resolution;
1078
+ }
1079
+ const allowedPeerSet = new Set(transport.allowedPeers);
1080
+ const effectiveAgentAddresses = new Set(resolution.recipients.map(({ agentAddress }) => agentAddress.toLowerCase()));
1081
+ const authorizedRecipients = resolution.recipients.filter((recipient) => (recipient.peerId !== undefined && allowedPeerSet.has(recipient.peerId)));
1082
+ const authorizedAgentAddresses = new Set(authorizedRecipients.map(({ agentAddress }) => agentAddress.toLowerCase()));
1083
+ for (const agentAddress of effectiveAgentAddresses) {
1084
+ if (!authorizedAgentAddresses.has(agentAddress)) {
1085
+ throw new Error(`Approved private replica "${input.contextGraphId}" requires encrypted SWM gossip but `
1086
+ + `effective DKG agent ${ethers.getAddress(agentAddress)} has no recipient key `
1087
+ + 'advertised by a peer in the context graph allowlist');
1088
+ }
1089
+ }
1090
+ const [firstRecipient, ...remainingRecipients] = authorizedRecipients;
1091
+ if (!firstRecipient) {
1092
+ throw new Error(`Approved private replica "${input.contextGraphId}" requires encrypted SWM gossip but has no allowed DKG agent recipients`);
1093
+ }
1094
+ const authorizedResolution = {
1095
+ requiresEncryption: true,
1096
+ recipients: [firstRecipient, ...remainingRecipients],
1097
+ };
1098
+ recipientAuthorityRevision = attemptRevision;
1099
+ return authorizedResolution;
1100
+ };
885
1101
  }
886
- return {
887
- requiresEncryption: true,
888
- recipients: [firstRecipient, ...remainingRecipients],
1102
+ else {
1103
+ if (transport.kind === 'unavailable') {
1104
+ const message = `Registered context graph "${input.contextGraphId}" authority is unavailable (${transport.reason})`;
1105
+ throw createContextGraphAuthorityError(message, transport);
1106
+ }
1107
+ const participantAgents = transport.participantAgents;
1108
+ if (participantAgents.length === 0) {
1109
+ throw new Error(`Registered context graph "${input.contextGraphId}" requires encrypted SWM gossip but its authoritative chain roster is empty or unavailable`);
1110
+ }
1111
+ // Resolve only the live chain-authorized addresses. Filtering a completed
1112
+ // local resolution afterward is too late: stale removed members can have
1113
+ // malformed/missing key metadata that makes the local resolver throw
1114
+ // before the chain intersection is reached, blocking every post-revoke
1115
+ // write until the local cleanup retry succeeds.
1116
+ resolveKeys = async () => {
1117
+ // The registered/accepted private roster, local peer gate, and verified
1118
+ // recipient-key routes are conjunctive authorities. Capture their shared
1119
+ // revision before every attempt so a phonebook-hydration retry owns a new
1120
+ // snapshot, while the final transport recheck cannot return a route
1121
+ // removed or revoked meanwhile.
1122
+ const attemptRevision = this.contextGraphMetaProjection.readAuthorityFactsRevision;
1123
+ const allowedPeers = await this.getContextGraphAllowedPeers(input.contextGraphId);
1124
+ const allowedPeerSet = allowedPeers === null ? null : new Set(allowedPeers);
1125
+ const recipients = [];
1126
+ // Every member without a key is named at once, so one phonebook fetch
1127
+ // can cover them all (#2849). Any other key failure still stops here.
1128
+ const missingKeys = [];
1129
+ for (const agentAddress of participantAgents) {
1130
+ let agentRecipients;
1131
+ try {
1132
+ agentRecipients = await resolveWorkspaceAgentRecipientKeys(this.store, agentAddress);
1133
+ }
1134
+ catch (error) {
1135
+ if (!isWorkspaceAgentEncryptionKeyMissingError(error))
1136
+ throw error;
1137
+ missingKeys.push(...error.agentAddresses);
1138
+ continue;
1139
+ }
1140
+ const authorizedRecipients = allowedPeerSet === null
1141
+ ? agentRecipients
1142
+ : agentRecipients.filter((recipient) => (recipient.peerId !== undefined && allowedPeerSet.has(recipient.peerId)));
1143
+ if (authorizedRecipients.length === 0) {
1144
+ throw new Error(`Registered context graph "${input.contextGraphId}" requires encrypted SWM gossip but `
1145
+ + `chain-authorized DKG agent ${ethers.getAddress(agentAddress)} has no recipient key `
1146
+ + 'advertised by a peer in the context graph allowlist');
1147
+ }
1148
+ recipients.push(...authorizedRecipients);
1149
+ }
1150
+ if (missingKeys.length > 0)
1151
+ throw new WorkspaceAgentEncryptionKeyMissingError(missingKeys);
1152
+ const [firstRecipient, ...remainingRecipients] = recipients;
1153
+ if (!firstRecipient) {
1154
+ throw new Error(`Registered context graph "${input.contextGraphId}" requires encrypted SWM gossip but has no chain-authorized DKG agent recipients`);
1155
+ }
1156
+ // Publish only the snapshot owned by the attempt that actually
1157
+ // completed. A failed pre-hydration attempt must not pin its revision
1158
+ // across the phonebook write and the successful retry.
1159
+ recipientAuthorityRevision = attemptRevision;
1160
+ return {
1161
+ requiresEncryption: true,
1162
+ recipients: [firstRecipient, ...remainingRecipients],
1163
+ };
1164
+ };
1165
+ }
1166
+ // A member added by address before it joined is known here only by its
1167
+ // profile, which an Edge fetches on demand (#2849). One fetch asks for
1168
+ // every member whose key is missing, then the keys are resolved once more.
1169
+ // Every member still needs a key, so a share that cannot get one stays
1170
+ // closed.
1171
+ const resolveWithPhonebookHydration = async () => {
1172
+ try {
1173
+ return await resolveKeys();
1174
+ }
1175
+ catch (error) {
1176
+ if (!isWorkspaceAgentEncryptionKeyMissingError(error))
1177
+ throw error;
1178
+ if (typeof this.ensureAgentsInOnDemandPhonebook !== 'function') {
1179
+ throw withMemberKeyHint(error);
1180
+ }
1181
+ await this.ensureAgentsInOnDemandPhonebook(error.agentAddresses.map((address) => address.toLowerCase()), AbortSignal.timeout(SWM_RECIPIENT_KEY_FETCH_WAIT_MS));
1182
+ }
1183
+ try {
1184
+ return await resolveKeys();
1185
+ }
1186
+ catch (error) {
1187
+ throw isWorkspaceAgentEncryptionKeyMissingError(error) ? withMemberKeyHint(error) : error;
1188
+ }
889
1189
  };
1190
+ let resolution = await resolveWithPhonebookHydration();
1191
+ if (transport.kind === 'private-roster'
1192
+ || transport.kind === 'approved-private-replica'
1193
+ || transport.kind === 'legacy-unregistered') {
1194
+ // Key and phonebook lookup are asynchronous. Re-read the paired
1195
+ // transport decision after them so an accepted-private (or registered)
1196
+ // roster rotation cannot return keys for a member removed meanwhile.
1197
+ // The store revision is deliberately conservative because recipient
1198
+ // facts can live in any named graph. Unrelated graph activity therefore
1199
+ // triggers a bounded optimistic retry, but a retry is accepted only when
1200
+ // both the exact (agent,key,peer) set and transport authority are stable.
1201
+ for (let attempt = 0; attempt < SWM_RECIPIENT_AUTHORITY_STABILITY_ATTEMPTS; attempt += 1) {
1202
+ const currentTransport = await withRpcUsageSite(CG_AUTH_RPC_SITES.recipients, () => this.resolveSwmTransportAuthority(input.contextGraphId, {
1203
+ authorityReadMode: 'finalized-index-or-live',
1204
+ requireLiveRosterForPrivate: true,
1205
+ }));
1206
+ if (currentTransport.kind === 'unavailable') {
1207
+ throw createContextGraphAuthorityError(`Context graph "${input.contextGraphId}" recipient authority is unavailable (${currentTransport.reason})`, currentTransport);
1208
+ }
1209
+ const transportStayedCurrent = transport.kind === 'private-roster'
1210
+ ? currentTransport.kind === 'private-roster'
1211
+ && resolution.requiresEncryption
1212
+ && hasExactRecipientAgentRoster(resolution, currentTransport.participantAgents)
1213
+ : transport.kind === 'approved-private-replica'
1214
+ ? currentTransport.kind === 'approved-private-replica'
1215
+ && sameStringSet(transport.allowedPeers, currentTransport.allowedPeers)
1216
+ : currentTransport.kind === 'legacy-unregistered';
1217
+ const revisionStayedCurrent = recipientAuthorityRevision
1218
+ === this.contextGraphMetaProjection.readAuthorityFactsRevision;
1219
+ if (transportStayedCurrent && revisionStayedCurrent)
1220
+ break;
1221
+ const hasAnotherAttempt = attempt + 1 < SWM_RECIPIENT_AUTHORITY_STABILITY_ATTEMPTS;
1222
+ if (!transportStayedCurrent || !hasAnotherAttempt) {
1223
+ throw createContextGraphAuthorityError(`Context graph "${input.contextGraphId}" private authority changed while recipient keys were resolving`, {
1224
+ reason: 'chain-participant-authority-unavailable',
1225
+ detail: 'retry recipient resolution against the current private authority',
1226
+ });
1227
+ }
1228
+ const retriedResolution = await resolveWithPhonebookHydration();
1229
+ const recipientSnapshotStayedCurrent = resolution.requiresEncryption
1230
+ ? retriedResolution.requiresEncryption
1231
+ && hasExactWorkspaceRecipientSet(resolution, retriedResolution)
1232
+ : !retriedResolution.requiresEncryption;
1233
+ if (!recipientSnapshotStayedCurrent) {
1234
+ throw createContextGraphAuthorityError(`Context graph "${input.contextGraphId}" private authority changed while recipient keys were resolving`, {
1235
+ reason: 'chain-participant-authority-unavailable',
1236
+ detail: 'recipient routes changed while retrying against current private authority',
1237
+ });
1238
+ }
1239
+ resolution = retriedResolution;
1240
+ }
1241
+ }
1242
+ return resolution;
890
1243
  }
891
1244
  async encryptWorkspacePayloadWithSenderKey(input) {
892
- await this.loadSwmSenderKeyState();
1245
+ let resolution = input.resolution;
1246
+ if (!this.swmSenderKeyStateLoaded) {
1247
+ await this.loadSwmSenderKeyState();
1248
+ // Recipient authority may have changed while durable state was loading.
1249
+ // Resolve once against the now-hydrated state and proceed only when the
1250
+ // exact agent/key/peer snapshot is unchanged. The production publisher
1251
+ // avoids this compatibility reread by hydrating in
1252
+ // resolveWorkspaceRecipientsGated above.
1253
+ const currentResolution = await this.resolveWorkspaceAgentRecipientsForCurrentAuthority({
1254
+ contextGraphId: input.contextGraphId,
1255
+ });
1256
+ if (!currentResolution.requiresEncryption
1257
+ || !hasExactWorkspaceRecipientSet(resolution, currentResolution)) {
1258
+ throw createContextGraphAuthorityError(`Context graph "${input.contextGraphId}" authority changed while sender-key state was loading`, {
1259
+ reason: 'chain-participant-authority-unavailable',
1260
+ detail: 'retry recipient resolution before creating or reusing a sender-key epoch',
1261
+ });
1262
+ }
1263
+ resolution = currentResolution;
1264
+ }
893
1265
  const ctx = createOperationContext('share', input.operationId);
894
1266
  const sender = this.getLocalSigningAgentForAddress(input.senderAgentAddress);
895
1267
  if (!sender) {
896
1268
  throw new Error(`Cannot create SWM Sender Key epoch: no local custodial signing key for agent ${input.senderAgentAddress}`);
897
1269
  }
898
- const resolution = input.resolution;
899
1270
  const senderAddress = ethers.getAddress(sender.agentAddress);
900
1271
  const recipientSet = new Set(resolution.recipients.map((recipient) => recipient.agentAddress.toLowerCase()));
901
1272
  if (!recipientSet.has(senderAddress.toLowerCase())) {
@@ -914,9 +1285,16 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
914
1285
  recipientKeyId: recipient.recipientKeyId,
915
1286
  })),
916
1287
  });
1288
+ const recipientRouteHash = computeSwmSenderKeyRecipientRouteHash({
1289
+ contextGraphId: input.contextGraphId,
1290
+ subGraphName: input.subGraphName,
1291
+ recipients: resolution.recipients,
1292
+ });
917
1293
  const stateKey = swmSenderStateKey(input.contextGraphId, input.subGraphName, senderAddress);
918
1294
  let state = this.swmSenderKeySendStates.get(stateKey);
919
- if (!state || state.membershipHash !== membershipHash) {
1295
+ if (!state
1296
+ || state.membershipHash !== membershipHash
1297
+ || state.recipientRouteHash !== recipientRouteHash) {
920
1298
  const pruned = this.prunePendingSenderKeysForEpochRotation({
921
1299
  contextGraphId: input.contextGraphId,
922
1300
  subGraphName: input.subGraphName,
@@ -939,7 +1317,12 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
939
1317
  await this.saveSwmSenderKeyState();
940
1318
  }
941
1319
  else {
942
- await this.drainPendingSenderKeyForRecipients(resolution.recipients, ctx);
1320
+ await this.drainPendingSenderKeyForRecipients(resolution.recipients, ctx, {
1321
+ contextGraphId: input.contextGraphId,
1322
+ subGraphName: input.subGraphName,
1323
+ senderAgentAddress: state.senderAgentAddress,
1324
+ epochId: state.epochId,
1325
+ });
943
1326
  }
944
1327
  const encrypted = await encryptSwmSenderKeyMessage({
945
1328
  chainKey: state.chainKey,
@@ -974,6 +1357,11 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
974
1357
  senderAgentAddress,
975
1358
  epochId,
976
1359
  membershipHash: input.membershipHash,
1360
+ recipientRouteHash: computeSwmSenderKeyRecipientRouteHash({
1361
+ contextGraphId: input.contextGraphId,
1362
+ subGraphName: input.subGraphName,
1363
+ recipients: input.recipients,
1364
+ }),
977
1365
  chainKey,
978
1366
  nextMessageIndex: 0,
979
1367
  senderSigningSecretKey: senderSigningKeypair.secretKey,
@@ -989,7 +1377,18 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
989
1377
  senderPrivateKey: input.sender.privateKey,
990
1378
  });
991
1379
  const packageBytes = encodeSwmSenderKeyPackage(pkg);
992
- if (this.hasLocalAgent(recipientAgentAddress)) {
1380
+ const recipientIsLocal = this.hasLocalAgent(recipientAgentAddress);
1381
+ let targetsLocalPeer = recipient.peerId === undefined;
1382
+ if (recipientIsLocal && recipient.peerId !== undefined) {
1383
+ const localPeerId = this.node.peerId.toString();
1384
+ const canonicalRecipientPeerId = tryCanonicalPeerIdString(recipient.peerId);
1385
+ const canonicalLocalPeerId = tryCanonicalPeerIdString(localPeerId);
1386
+ targetsLocalPeer = recipient.peerId === localPeerId
1387
+ || (canonicalRecipientPeerId !== null
1388
+ && canonicalLocalPeerId !== null
1389
+ && canonicalRecipientPeerId === canonicalLocalPeerId);
1390
+ }
1391
+ if (recipientIsLocal && targetsLocalPeer) {
993
1392
  try {
994
1393
  await this.acceptSwmSenderKeyPackage(pkg, this.node.peerId.toString(), input.ctx);
995
1394
  return { kind: 'success', agentAddress: recipientAgentAddress };
@@ -1026,7 +1425,7 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1026
1425
  });
1027
1426
  pendingSenderKeyQueued = true;
1028
1427
  this.log.warn(input.ctx, `SWM sender-key setup for ${recipientAgentAddress} keyId=${recipient.recipientKeyId} ` +
1029
- `queued (no advertised peerId) — will deliver when recipient connects`);
1428
+ `queued (no advertised peerId) — will deliver after a verified peer route is learned`);
1030
1429
  return { kind: 'success', agentAddress: recipientAgentAddress };
1031
1430
  }
1032
1431
  this.log.info(input.ctx, `SWM sender-key setup send: senderAgent=${senderAgentAddress} recipientAgent=${recipientAgentAddress} ` +
@@ -1067,6 +1466,7 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1067
1466
  senderAgentAddress: senderAgentAddress.toLowerCase(),
1068
1467
  recipientAgentAddress: recipientAgentAddress.toLowerCase(),
1069
1468
  recipientKeyId: recipient.recipientKeyId,
1469
+ recipientPeerId: recipient.peerId,
1070
1470
  epochId: state.epochId,
1071
1471
  contextGraphId: state.contextGraphId,
1072
1472
  subGraphName: state.subGraphName,
@@ -1088,6 +1488,7 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1088
1488
  senderAgentAddress: senderAgentAddress.toLowerCase(),
1089
1489
  recipientAgentAddress: recipientAgentAddress.toLowerCase(),
1090
1490
  recipientKeyId: recipient.recipientKeyId,
1491
+ recipientPeerId: recipient.peerId,
1091
1492
  epochId: state.epochId,
1092
1493
  contextGraphId: state.contextGraphId,
1093
1494
  subGraphName: state.subGraphName,
@@ -1106,6 +1507,7 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1106
1507
  senderAgentAddress: senderAgentAddress.toLowerCase(),
1107
1508
  recipientAgentAddress: recipientAgentAddress.toLowerCase(),
1108
1509
  recipientKeyId: recipient.recipientKeyId,
1510
+ recipientPeerId: recipient.peerId,
1109
1511
  epochId: state.epochId,
1110
1512
  contextGraphId: state.contextGraphId,
1111
1513
  subGraphName: state.subGraphName,
@@ -1125,6 +1527,7 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1125
1527
  senderAgentAddress: senderAgentAddress.toLowerCase(),
1126
1528
  recipientAgentAddress: recipientAgentAddress.toLowerCase(),
1127
1529
  recipientKeyId: recipient.recipientKeyId,
1530
+ recipientPeerId: recipient.peerId,
1128
1531
  epochId: state.epochId,
1129
1532
  contextGraphId: state.contextGraphId,
1130
1533
  subGraphName: state.subGraphName,
@@ -1233,26 +1636,34 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1233
1636
  /**
1234
1637
  * PR-2 (SWM-fanout plan): enqueue a sender-key package whose recipient
1235
1638
  * has no advertised `dkg:peerId` (so we can't even ask the messenger
1236
- * to queue it). Older epochs for the same `(sender, recipient)` pair
1237
- * are evicted — a newer epoch supersedes them by definition.
1639
+ * to queue it). Older epochs for the same `(sender, recipient, context
1640
+ * graph, subgraph)` scope are evicted — a newer epoch supersedes them by
1641
+ * definition. Other graph/subgraph obligations remain independent.
1238
1642
  *
1239
- * Per-key dedup: `(senderAgentAddress, recipientKeyId, epochId)`
1240
- * matches an existing row, we replace it (idempotent re-enqueue).
1643
+ * Per-route dedup: `(senderAgentAddress, recipientKeyId,
1644
+ * recipientPeerId, epochId)` matches an existing row, we replace it
1645
+ * (idempotent re-enqueue). Distinct peers advertising the same key retain
1646
+ * independent delivery obligations.
1241
1647
  */
1242
1648
  enqueuePendingSenderKey(entry) {
1243
1649
  const recipientKey = entry.recipientAgentAddress.toLowerCase();
1244
1650
  const existing = this.pendingSenderKeyByAgent.get(recipientKey) ?? [];
1245
- // Drop older epochs for the same (sender, recipient) pair; the newer
1246
- // epoch's membership-hash supersedes them. Keep entries for OTHER
1247
- // senders / recipients unchanged.
1651
+ // Drop older epochs only within the same sender + graph/subgraph scope;
1652
+ // the newer epoch's membership hash supersedes those rows. The map key
1653
+ // already scopes recipient agent. Keep every other scope unchanged.
1248
1654
  const filtered = existing.filter((e) => {
1249
1655
  if (e.senderAgentAddress !== entry.senderAgentAddress)
1250
1656
  return true;
1657
+ if (e.contextGraphId !== entry.contextGraphId
1658
+ || (e.subGraphName ?? undefined) !== (entry.subGraphName ?? undefined)) {
1659
+ return true;
1660
+ }
1251
1661
  if (e.epochId === entry.epochId) {
1252
- // Same epoch: dedupe by recipientKeyId — caller may re-enqueue
1253
- // on retry. Replace by dropping the old slot; the new one is
1254
- // appended below.
1255
- return e.recipientKeyId !== entry.recipientKeyId;
1662
+ // Same epoch: dedupe only the exact key + peer route. A successful
1663
+ // ACK from one peer must never overwrite a retry owed to another peer
1664
+ // that advertises the same agent/key pair.
1665
+ return e.recipientKeyId !== entry.recipientKeyId
1666
+ || e.recipientPeerId !== entry.recipientPeerId;
1256
1667
  }
1257
1668
  return false;
1258
1669
  });
@@ -1281,17 +1692,21 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1281
1692
  return removed;
1282
1693
  }
1283
1694
  async drainPendingSenderKeyQueueForPeer(input) {
1284
- const recipientAgentAddress = input.recipientAgentAddress.toLowerCase();
1695
+ const authority = {
1696
+ ...input.authority,
1697
+ recipientAgentAddress: input.authority.recipientAgentAddress.toLowerCase(),
1698
+ senderAgentAddress: input.authority.senderAgentAddress?.toLowerCase(),
1699
+ };
1700
+ const recipientAgentAddress = authority.recipientAgentAddress;
1285
1701
  const existingDrain = this.pendingSenderKeyDrainByAgent.get(recipientAgentAddress);
1286
1702
  if (existingDrain) {
1287
1703
  await existingDrain;
1288
1704
  if (!this.pendingSenderKeyByAgent.has(recipientAgentAddress))
1289
1705
  return 0;
1290
- return this.drainPendingSenderKeyQueueForPeer(input);
1706
+ return this.drainPendingSenderKeyQueueForPeer({ authority, ctx: input.ctx });
1291
1707
  }
1292
1708
  const drain = this.drainPendingSenderKeyQueueForPeerLocked({
1293
- peerId: input.peerId,
1294
- recipientAgentAddress,
1709
+ authority,
1295
1710
  ctx: input.ctx,
1296
1711
  }).finally(() => {
1297
1712
  if (this.pendingSenderKeyDrainByAgent.get(recipientAgentAddress) === drain) {
@@ -1302,19 +1717,75 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1302
1717
  return drain;
1303
1718
  }
1304
1719
  async drainPendingSenderKeyQueueForPeerLocked(input) {
1305
- const recipientAgentAddress = input.recipientAgentAddress;
1720
+ const { authority } = input;
1721
+ const recipientAgentAddress = authority.recipientAgentAddress;
1306
1722
  const queue = this.pendingSenderKeyByAgent.get(recipientAgentAddress);
1307
1723
  if (!queue || queue.length === 0)
1308
1724
  return 0;
1309
1725
  let drained = 0;
1310
- const remaining = [];
1726
+ // `sendReliable` yields. Enqueue/epoch rotation can replace the live array
1727
+ // while this drain is in flight, so record outcomes against the exact
1728
+ // snapshot objects instead of later overwriting the whole map entry. At
1729
+ // commit, only original objects still present in the live queue are
1730
+ // transformed; concurrently inserted replacements/new scopes survive and
1731
+ // originals concurrently superseded by a new epoch are not resurrected.
1732
+ const outcomes = new Map();
1733
+ const commitOutcomes = () => {
1734
+ const live = this.pendingSenderKeyByAgent.get(recipientAgentAddress) ?? [];
1735
+ const reconciled = [];
1736
+ for (const liveEntry of live) {
1737
+ if (!outcomes.has(liveEntry)) {
1738
+ reconciled.push(liveEntry);
1739
+ continue;
1740
+ }
1741
+ const replacement = outcomes.get(liveEntry);
1742
+ if (replacement)
1743
+ reconciled.push(replacement);
1744
+ }
1745
+ if (reconciled.length === 0) {
1746
+ this.pendingSenderKeyByAgent.delete(recipientAgentAddress);
1747
+ }
1748
+ else {
1749
+ this.pendingSenderKeyByAgent.set(recipientAgentAddress, reconciled);
1750
+ }
1751
+ };
1311
1752
  for (let i = 0; i < queue.length; i += 1) {
1312
1753
  const entry = queue[i];
1754
+ // A row may only be consumed by the caller's exact current-authority
1755
+ // route and graph scope. Legacy/no-peer rows are expanded into explicit
1756
+ // peer-bound obligations before reaching this drain. Foreground callers
1757
+ // additionally bind the current sender + epoch; connection-open callers
1758
+ // explicitly authorize every subgraph for one resolved CG.
1759
+ if (!pendingSenderKeyEntryMatchesDrainAuthority(entry, authority)) {
1760
+ outcomes.set(entry, entry);
1761
+ continue;
1762
+ }
1763
+ // Authority can change while this route waits for the per-agent drain
1764
+ // lock, or while a preceding row is in flight. Re-resolve immediately
1765
+ // before every send so a stale caller snapshot can never consume a row.
1766
+ let routeStillCurrent = false;
1313
1767
  try {
1314
- const sendResult = await this.messenger.sendReliable(input.peerId, PROTOCOL_SWM_SENDER_KEY, entry.packageBytes, { messageId: this.swmSenderKeyPendingMessageId(entry) });
1768
+ const resolution = await this.resolveWorkspaceAgentRecipientsForCurrentAuthority({
1769
+ contextGraphId: entry.contextGraphId,
1770
+ });
1771
+ routeStillCurrent = resolution.requiresEncryption
1772
+ && resolution.recipients.some((recipient) => (recipient.agentAddress.toLowerCase() === entry.recipientAgentAddress
1773
+ && recipient.recipientKeyId === entry.recipientKeyId
1774
+ && recipient.peerId === entry.recipientPeerId));
1775
+ }
1776
+ catch {
1777
+ // Fail closed. The queued obligation remains available for a later
1778
+ // current-authority retry.
1779
+ }
1780
+ if (!routeStillCurrent) {
1781
+ outcomes.set(entry, entry);
1782
+ continue;
1783
+ }
1784
+ try {
1785
+ const sendResult = await this.messenger.sendReliable(authority.recipientPeerId, PROTOCOL_SWM_SENDER_KEY, entry.packageBytes, { messageId: this.swmSenderKeyPendingMessageId(entry) });
1315
1786
  if (!sendResult.delivered) {
1316
1787
  if (sendResult.queued || ('inFlight' in sendResult && sendResult.inFlight)) {
1317
- remaining.push(entry);
1788
+ outcomes.set(entry, entry);
1318
1789
  continue;
1319
1790
  }
1320
1791
  throw new Error(`Unexpected undelivered Sender Key retry result: ${sendResult.error}`);
@@ -1326,65 +1797,134 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1326
1797
  catch {
1327
1798
  // Malformed/legacy ACK: no positive acceptance yet. Keep the
1328
1799
  // row queued so a mixed-version rollout cannot strand the recipient.
1329
- remaining.push(this.rotateSwmSenderKeyPendingMessageId(entry));
1800
+ outcomes.set(entry, this.rotateSwmSenderKeyPendingMessageId(entry));
1330
1801
  continue;
1331
1802
  }
1332
1803
  if (ack.version !== SWM_SENDER_KEY_PACKAGE_VERSION ||
1333
1804
  ack.type !== SWM_SENDER_KEY_PACKAGE_ACK_TYPE) {
1334
1805
  // Malformed/legacy ACK: no positive acceptance yet. Keep the
1335
1806
  // row queued so a mixed-version rollout cannot strand the recipient.
1336
- remaining.push(this.rotateSwmSenderKeyPendingMessageId(entry));
1807
+ outcomes.set(entry, this.rotateSwmSenderKeyPendingMessageId(entry));
1337
1808
  continue;
1338
1809
  }
1339
1810
  if (ack.accepted) {
1340
1811
  drained += 1;
1812
+ outcomes.set(entry, null);
1341
1813
  }
1342
1814
  else if (this.isRetryableSwmSenderKeySetupAckReason(ack.reasonCode)) {
1343
- remaining.push(this.rotateSwmSenderKeyPendingMessageId(entry));
1815
+ outcomes.set(entry, this.rotateSwmSenderKeyPendingMessageId(entry));
1344
1816
  }
1345
1817
  else {
1346
1818
  const reason = ack.reason ?? 'unknown reason';
1347
1819
  const reasonCode = ack.reasonCode ?? 'legacy-unknown';
1348
1820
  this.log.warn(input.ctx ?? SWM_SENDER_KEY_PENDING_DRAIN_LOG_CTX, `SWM sender-key pending retry for ${entry.recipientAgentAddress} keyId=${entry.recipientKeyId} ` +
1349
- `peerId=${input.peerId} contextGraph=${entry.contextGraphId}${entry.subGraphName ? `/${entry.subGraphName}` : ''} ` +
1821
+ `peerId=${authority.recipientPeerId} contextGraph=${entry.contextGraphId}${entry.subGraphName ? `/${entry.subGraphName}` : ''} ` +
1350
1822
  `dropped after terminal rejection (${reasonCode}): ${reason}`);
1351
1823
  // Terminal rejection: keep it out of the queue, but do not
1352
1824
  // report it as a successful drain.
1825
+ outcomes.set(entry, null);
1353
1826
  }
1354
1827
  }
1355
1828
  catch (err) {
1356
- remaining.push(...queue.slice(i));
1357
- if (remaining.length === 0) {
1358
- this.pendingSenderKeyByAgent.delete(recipientAgentAddress);
1359
- }
1360
- else {
1361
- this.pendingSenderKeyByAgent.set(recipientAgentAddress, remaining);
1829
+ outcomes.set(entry, entry);
1830
+ for (const unprocessed of queue.slice(i + 1)) {
1831
+ outcomes.set(unprocessed, unprocessed);
1362
1832
  }
1833
+ commitOutcomes();
1363
1834
  await this.saveSwmSenderKeyState();
1364
1835
  const message = err instanceof Error ? err.message : String(err);
1365
1836
  this.log.warn(input.ctx ?? SWM_SENDER_KEY_PENDING_DRAIN_LOG_CTX, `SWM sender-key pending retry for ${entry.recipientAgentAddress} keyId=${entry.recipientKeyId} ` +
1366
- `peerId=${input.peerId} contextGraph=${entry.contextGraphId}${entry.subGraphName ? `/${entry.subGraphName}` : ''} ` +
1837
+ `peerId=${authority.recipientPeerId} contextGraph=${entry.contextGraphId}${entry.subGraphName ? `/${entry.subGraphName}` : ''} ` +
1367
1838
  `failed before the Messenger substrate queued a retry: ${message}`);
1368
1839
  throw err;
1369
1840
  }
1370
1841
  }
1371
- if (remaining.length === 0) {
1372
- this.pendingSenderKeyByAgent.delete(recipientAgentAddress);
1373
- }
1374
- else {
1375
- this.pendingSenderKeyByAgent.set(recipientAgentAddress, remaining);
1376
- }
1842
+ commitOutcomes();
1377
1843
  await this.saveSwmSenderKeyState();
1378
1844
  return drained;
1379
1845
  }
1380
1846
  /**
1381
- * Drain queued sender-key packages whose recipient agent is one of
1382
- * the agent addresses advertised by `peerId`. Returns the number of
1383
- * rows successfully delivered (acked) and removed.
1847
+ * Upgrade legacy/no-peer pending rows into one durable obligation per exact
1848
+ * `(agent, key, peer)` route in a current authority-fenced recipient
1849
+ * snapshot. The replacement is synchronous so drains can never observe a
1850
+ * partially expanded multi-peer obligation.
1851
+ */
1852
+ expandUnboundPendingSenderKeyRoutes(input) {
1853
+ const peersByAgentAndKey = new Map();
1854
+ for (const recipient of input.recipients) {
1855
+ if (!recipient.peerId)
1856
+ continue;
1857
+ const routeKey = `${recipient.agentAddress.toLowerCase()}\0${recipient.recipientKeyId}`;
1858
+ const peers = peersByAgentAndKey.get(routeKey) ?? new Set();
1859
+ peers.add(recipient.peerId);
1860
+ peersByAgentAndKey.set(routeKey, peers);
1861
+ }
1862
+ if (peersByAgentAndKey.size === 0)
1863
+ return 0;
1864
+ const boundRouteIdentity = (entry, peerId) => JSON.stringify([
1865
+ entry.senderAgentAddress,
1866
+ entry.recipientKeyId,
1867
+ peerId,
1868
+ entry.epochId,
1869
+ entry.contextGraphId,
1870
+ entry.subGraphName ?? null,
1871
+ ]);
1872
+ const senderAgentAddress = input.senderAgentAddress?.toLowerCase();
1873
+ let expanded = 0;
1874
+ for (const [recipientAgentAddress, queue] of this.pendingSenderKeyByAgent.entries()) {
1875
+ const existingBoundRoutes = new Set(queue
1876
+ .flatMap((entry) => entry.recipientPeerId === undefined
1877
+ ? []
1878
+ : [boundRouteIdentity(entry, entry.recipientPeerId)]));
1879
+ let changed = false;
1880
+ const replacement = [];
1881
+ for (const entry of queue) {
1882
+ const matchesScope = entry.contextGraphId === input.contextGraphId
1883
+ && (input.allSubgraphs
1884
+ || (entry.subGraphName ?? undefined) === (input.subGraphName ?? undefined))
1885
+ && (senderAgentAddress === undefined || entry.senderAgentAddress === senderAgentAddress)
1886
+ && (input.epochId === undefined || entry.epochId === input.epochId);
1887
+ if (entry.recipientPeerId !== undefined || !matchesScope) {
1888
+ replacement.push(entry);
1889
+ continue;
1890
+ }
1891
+ const peers = peersByAgentAndKey.get(`${entry.recipientAgentAddress}\0${entry.recipientKeyId}`);
1892
+ if (!peers || peers.size === 0) {
1893
+ replacement.push(entry);
1894
+ continue;
1895
+ }
1896
+ changed = true;
1897
+ expanded += 1;
1898
+ for (const peerId of peers) {
1899
+ const identity = boundRouteIdentity(entry, peerId);
1900
+ if (existingBoundRoutes.has(identity))
1901
+ continue;
1902
+ replacement.push({ ...entry, recipientPeerId: peerId });
1903
+ existingBoundRoutes.add(identity);
1904
+ }
1905
+ }
1906
+ if (changed) {
1907
+ if (replacement.length === 0) {
1908
+ this.pendingSenderKeyByAgent.delete(recipientAgentAddress);
1909
+ }
1910
+ else {
1911
+ this.pendingSenderKeyByAgent.set(recipientAgentAddress, replacement);
1912
+ }
1913
+ }
1914
+ }
1915
+ return expanded;
1916
+ }
1917
+ /**
1918
+ * Drain queued sender-key packages whose exact current recipient route is
1919
+ * the newly connected `peerId`. Returns the number of rows successfully
1920
+ * delivered (acked) and removed.
1384
1921
  *
1385
1922
  * Fired from the `connection:open` listener — see line 2382 — so the
1386
1923
  * cost lives on the cold path of "we just connected to a new peer",
1387
- * not on every share. Each successful `sendReliable` with
1924
+ * not on every share. Every context graph represented by either a bound or
1925
+ * legacy row is resolved first; bound rows never bypass that authority read.
1926
+ * Legacy/no-peer rows are expanded only from that graph's current,
1927
+ * authority-fenced recipient snapshot. Each successful `sendReliable` with
1388
1928
  * `delivered=true && ack.accepted=true` deletes the row and counts as
1389
1929
  * drained; soft (`delivered=false`) and explicitly retryable delivered
1390
1930
  * rejections leave it queued for the next attempt; terminal delivered
@@ -1395,21 +1935,80 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1395
1935
  if (this.pendingSenderKeyByAgent.size === 0)
1396
1936
  return 0;
1397
1937
  let drained = 0;
1398
- let agentAddresses = [];
1399
- try {
1400
- const profile = await this.discovery.findAgentByPeerId(peerId);
1401
- if (profile?.agentAddress) {
1402
- agentAddresses = [profile.agentAddress.toLowerCase()];
1938
+ const pendingContextGraphIds = new Set([...this.pendingSenderKeyByAgent.values()]
1939
+ .flatMap((queue) => queue
1940
+ .filter((entry) => entry.recipientPeerId === undefined || entry.recipientPeerId === peerId)
1941
+ .map((entry) => entry.contextGraphId)));
1942
+ let expandedRows = 0;
1943
+ for (const contextGraphId of pendingContextGraphIds) {
1944
+ let resolution;
1945
+ try {
1946
+ resolution = await this.resolveWorkspaceAgentRecipientsForCurrentAuthority({
1947
+ contextGraphId,
1948
+ });
1949
+ }
1950
+ catch {
1951
+ // Authority/key resolution failure is benign on connection-open. No
1952
+ // row for this CG — including already bound rows — may bypass it.
1953
+ continue;
1954
+ }
1955
+ if (!resolution.requiresEncryption)
1956
+ continue;
1957
+ expandedRows += this.expandUnboundPendingSenderKeyRoutes({
1958
+ recipients: resolution.recipients,
1959
+ contextGraphId,
1960
+ allSubgraphs: true,
1961
+ });
1962
+ const routes = new Map();
1963
+ for (const recipient of resolution.recipients) {
1964
+ if (recipient.peerId !== peerId)
1965
+ continue;
1966
+ const recipientAgentAddress = recipient.agentAddress.toLowerCase();
1967
+ const authority = {
1968
+ contextGraphId,
1969
+ allSubgraphs: true,
1970
+ recipientAgentAddress,
1971
+ recipientKeyId: recipient.recipientKeyId,
1972
+ recipientPeerId: peerId,
1973
+ };
1974
+ const queue = this.pendingSenderKeyByAgent.get(recipientAgentAddress);
1975
+ if (!queue?.some((entry) => (pendingSenderKeyEntryMatchesDrainAuthority(entry, authority))))
1976
+ continue;
1977
+ routes.set(`${recipientAgentAddress}\0${recipient.recipientKeyId}\0${peerId}`, authority);
1978
+ }
1979
+ for (const authority of routes.values()) {
1980
+ drained += await this.drainPendingSenderKeyQueueForPeer({ authority, ctx });
1403
1981
  }
1404
1982
  }
1405
- catch {
1406
- // Resolution failure is benign — we'll try again on the next
1407
- // connection:open burst. Don't propagate.
1983
+ if (expandedRows > 0) {
1984
+ // A connection can teach us routes for another peer. Persist that legacy
1985
+ // migration even when this peer had no exact authorized row to drain.
1986
+ await this.saveSwmSenderKeyState();
1408
1987
  }
1409
- if (agentAddresses.length === 0)
1988
+ return drained;
1989
+ }
1990
+ /**
1991
+ * A delivered Sender Key setup can receive a retryable authority denial.
1992
+ * That leaves a durable pending row but does not create a Messenger outbox
1993
+ * retry, and an already-connected recipient may never produce another
1994
+ * connection:open event. Retry only peer-bound rows on the ordinary outbox
1995
+ * cadence. The drain below re-resolves current graph authority and the exact
1996
+ * recipient key/peer route before sending any package.
1997
+ */
1998
+ async drainPendingSenderKeysForConnectedPeers() {
1999
+ await this.loadSwmSenderKeyState();
2000
+ if (this.pendingSenderKeyByAgent.size === 0 || !this.node.isStarted)
2001
+ return 0;
2002
+ const pendingPeers = new Set([...this.pendingSenderKeyByAgent.values()]
2003
+ .flatMap((queue) => queue.flatMap((entry) => entry.recipientPeerId === undefined ? [] : [entry.recipientPeerId])));
2004
+ if (pendingPeers.size === 0)
1410
2005
  return 0;
1411
- for (const recipientAgentAddress of agentAddresses) {
1412
- drained += await this.drainPendingSenderKeyQueueForPeer({ peerId, recipientAgentAddress, ctx });
2006
+ let drained = 0;
2007
+ for (const peer of this.node.libp2p.getPeers()) {
2008
+ const peerId = peer.toString();
2009
+ if (!pendingPeers.has(peerId))
2010
+ continue;
2011
+ drained += await this.drainPendingSenderKeyForPeer(peerId);
1413
2012
  }
1414
2013
  return drained;
1415
2014
  }
@@ -1419,25 +2018,41 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1419
2018
  * connections where no fresh connection:open event will fire after the
1420
2019
  * remote membership/key view converges.
1421
2020
  */
1422
- async drainPendingSenderKeyForRecipients(recipients, ctx) {
2021
+ async drainPendingSenderKeyForRecipients(recipients, ctx, scope) {
1423
2022
  if (this.pendingSenderKeyByAgent.size === 0)
1424
2023
  return 0;
1425
- const peerByAgent = new Map();
2024
+ const senderAgentAddress = scope.senderAgentAddress.toLowerCase();
2025
+ this.expandUnboundPendingSenderKeyRoutes({
2026
+ recipients,
2027
+ contextGraphId: scope.contextGraphId,
2028
+ subGraphName: scope.subGraphName,
2029
+ senderAgentAddress,
2030
+ epochId: scope.epochId,
2031
+ });
2032
+ const routes = new Map();
1426
2033
  for (const recipient of recipients) {
1427
2034
  if (!recipient.peerId)
1428
2035
  continue;
1429
2036
  const recipientAgentAddress = recipient.agentAddress.toLowerCase();
1430
2037
  if (!this.pendingSenderKeyByAgent.has(recipientAgentAddress))
1431
2038
  continue;
1432
- if (!peerByAgent.has(recipientAgentAddress)) {
1433
- peerByAgent.set(recipientAgentAddress, recipient.peerId);
1434
- }
2039
+ const authority = {
2040
+ contextGraphId: scope.contextGraphId,
2041
+ subGraphName: scope.subGraphName,
2042
+ senderAgentAddress,
2043
+ epochId: scope.epochId,
2044
+ recipientAgentAddress,
2045
+ recipientKeyId: recipient.recipientKeyId,
2046
+ recipientPeerId: recipient.peerId,
2047
+ };
2048
+ const routeKey = `${recipientAgentAddress}\0${recipient.recipientKeyId}\0${recipient.peerId}`;
2049
+ routes.set(routeKey, authority);
1435
2050
  }
1436
- if (peerByAgent.size === 0)
2051
+ if (routes.size === 0)
1437
2052
  return 0;
1438
2053
  let drained = 0;
1439
- for (const [recipientAgentAddress, peerId] of peerByAgent.entries()) {
1440
- drained += await this.drainPendingSenderKeyQueueForPeer({ peerId, recipientAgentAddress, ctx });
2054
+ for (const authority of routes.values()) {
2055
+ drained += await this.drainPendingSenderKeyQueueForPeer({ authority, ctx });
1441
2056
  }
1442
2057
  if (drained > 0 && ctx) {
1443
2058
  this.log.info(ctx, `SWM sender-key pending retry drained ${drained} queued package(s) during publish`);
@@ -1667,7 +2282,21 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1667
2282
  if (recovered.toLowerCase() !== senderAgentAddress.toLowerCase()) {
1668
2283
  throw new SwmSenderKeySetupRejectionError('bad-signature', `Sender Key setup signature recovered ${recovered}, expected ${senderAgentAddress}`);
1669
2284
  }
1670
- const agentGateAddresses = await withRpcUsageSite(CG_AUTH_RPC_SITES.senderKeyAccept, () => this.getContextGraphAgentGateAddresses(pkg.contextGraphId));
2285
+ const agentGateAuthority = await withRpcUsageSite(CG_AUTH_RPC_SITES.senderKeyAccept, () => this.resolveContextGraphAgentGateAuthority(pkg.contextGraphId));
2286
+ if (agentGateAuthority.kind === 'unavailable') {
2287
+ // Not knowing the gate is not evidence that either endpoint is outside
2288
+ // it. Answering `sender-not-allowed` here made an authority failure look
2289
+ // like a membership decision (#2827). A transient failure asks the
2290
+ // sender to retain and retry the package; one that needs a software or
2291
+ // configuration change is terminal, classified exactly as the promote
2292
+ // retry is (isRetryableContextGraphAuthorityUnavailableReason).
2293
+ throw new SwmSenderKeySetupRejectionError(isRetryableContextGraphAuthorityUnavailableReason(agentGateAuthority.reason)
2294
+ ? 'agent-gate-pending'
2295
+ : 'agent-gate-unavailable', `Context graph "${pkg.contextGraphId}" agent gate authority is unavailable (${agentGateAuthority.reason})`);
2296
+ }
2297
+ const agentGateAddresses = agentGateAuthority.kind === 'available'
2298
+ ? agentGateAuthority.agentAddresses
2299
+ : null;
1671
2300
  if (!agentGateAddresses) {
1672
2301
  // A cold private member can receive Sender Key setup after the finalized
1673
2302
  // chain binding but before its accepted RFC-64 roster or legacy `_meta`
@@ -1689,7 +2318,17 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
1689
2318
  if (!agentGateSet.has(recipientAgentAddress.toLowerCase())) {
1690
2319
  throw new SwmSenderKeySetupRejectionError('recipient-not-allowed', `Recipient agent ${recipientAgentAddress} is not allowed for context graph "${pkg.contextGraphId}"`);
1691
2320
  }
1692
- const allowedPeers = await this.getContextGraphAllowedPeers(pkg.contextGraphId);
2321
+ let allowedPeers;
2322
+ try {
2323
+ allowedPeers = await this.resolveSwmAllowedPeersForCurrentAuthority(pkg.contextGraphId);
2324
+ }
2325
+ catch (error) {
2326
+ if (!isContextGraphAuthorityUnavailableMarker(error))
2327
+ throw error;
2328
+ throw new SwmSenderKeySetupRejectionError(isRetryableContextGraphAuthorityUnavailableReason(error.reason)
2329
+ ? 'agent-gate-pending'
2330
+ : 'agent-gate-unavailable', `Context graph "${pkg.contextGraphId}" SWM peer gate authority is unavailable (${error.reason})`);
2331
+ }
1693
2332
  if (allowedPeers !== null && !allowedPeers.includes(fromPeerId)) {
1694
2333
  throw new SwmSenderKeySetupRejectionError('sender-not-allowed', `Sender peer ${fromPeerId} is not allowed for context graph "${pkg.contextGraphId}"`);
1695
2334
  }
@@ -2018,23 +2657,32 @@ export class WorkspaceCryptoMethods extends DKGAgentBase {
2018
2657
  const path = this.swmSenderKeyStatePath();
2019
2658
  if (!path)
2020
2659
  return;
2021
- const { mkdir, writeFile, chmod } = await import('node:fs/promises');
2022
- const { dirname } = await import('node:path');
2023
- await mkdir(dirname(path), { recursive: true });
2024
- const payload = {
2025
- version: 1,
2026
- send: [...this.swmSenderKeySendStates.values()].map(serializeSwmSenderSendState),
2027
- receive: [...this.swmSenderKeyReceiveStates.values()].map(serializeSwmSenderReceiveState),
2028
- pending: [...this.pendingSenderKeyByAgent.values()]
2029
- .flatMap((queue) => queue.map(serializePendingSenderKeyEntry)),
2030
- };
2031
- await writeFile(path, JSON.stringify(payload, null, 2), { mode: 0o600 });
2032
- try {
2033
- await chmod(path, 0o600);
2034
- }
2035
- catch {
2036
- // Best-effort on platforms/filesystems that do not support chmod.
2037
- }
2660
+ const save = this.swmSenderKeyStateSaveQueue.then(async () => {
2661
+ const { mkdir, writeFile, chmod } = await import('node:fs/promises');
2662
+ const { dirname } = await import('node:path');
2663
+ await mkdir(dirname(path), { recursive: true });
2664
+ // Capture inside the serialized section. A caller queued behind an
2665
+ // in-flight write must persist the state current when its turn begins,
2666
+ // not a stale snapshot captured while the older write was outstanding.
2667
+ const payload = {
2668
+ version: 1,
2669
+ send: [...this.swmSenderKeySendStates.values()].map(serializeSwmSenderSendState),
2670
+ receive: [...this.swmSenderKeyReceiveStates.values()].map(serializeSwmSenderReceiveState),
2671
+ pending: [...this.pendingSenderKeyByAgent.values()]
2672
+ .flatMap((queue) => queue.map(serializePendingSenderKeyEntry)),
2673
+ };
2674
+ await writeFile(path, JSON.stringify(payload, null, 2), { mode: 0o600 });
2675
+ try {
2676
+ await chmod(path, 0o600);
2677
+ }
2678
+ catch {
2679
+ // Best-effort on platforms/filesystems that do not support chmod.
2680
+ }
2681
+ });
2682
+ // A failed save is still reported to its caller, but must not poison the
2683
+ // queue and suppress every later persistence attempt.
2684
+ this.swmSenderKeyStateSaveQueue = save.catch(() => undefined);
2685
+ await save;
2038
2686
  }
2039
2687
  async resolveWorkspaceGossipSigningAgent(contextGraphId) {
2040
2688
  const authority = await withRpcUsageSite(CG_AUTH_RPC_SITES.signer, () => this.resolveContextGraphAgentGateAuthority(contextGraphId));