@origintrail-official/dkg-agent 10.0.19 → 10.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (733) hide show
  1. package/dist/approved-private-replica.d.ts +54 -0
  2. package/dist/approved-private-replica.d.ts.map +1 -0
  3. package/dist/approved-private-replica.js +148 -0
  4. package/dist/approved-private-replica.js.map +1 -0
  5. package/dist/bounded-operation.d.ts +2 -0
  6. package/dist/bounded-operation.d.ts.map +1 -1
  7. package/dist/bounded-operation.js +5 -0
  8. package/dist/bounded-operation.js.map +1 -1
  9. package/dist/chain-finality-confirmations-v1.d.ts +7 -0
  10. package/dist/chain-finality-confirmations-v1.d.ts.map +1 -0
  11. package/dist/chain-finality-confirmations-v1.js +9 -0
  12. package/dist/chain-finality-confirmations-v1.js.map +1 -0
  13. package/dist/chain-reconciler.d.ts +23 -0
  14. package/dist/chain-reconciler.d.ts.map +1 -1
  15. package/dist/chain-reconciler.js +35 -0
  16. package/dist/chain-reconciler.js.map +1 -1
  17. package/dist/confirmed-graph-scoped-vm-resolver.d.ts +7 -1
  18. package/dist/confirmed-graph-scoped-vm-resolver.d.ts.map +1 -1
  19. package/dist/confirmed-graph-scoped-vm-resolver.js +5 -3
  20. package/dist/confirmed-graph-scoped-vm-resolver.js.map +1 -1
  21. package/dist/context-graph-authority-dependency.d.ts +11 -0
  22. package/dist/context-graph-authority-dependency.d.ts.map +1 -0
  23. package/dist/context-graph-authority-dependency.js +50 -0
  24. package/dist/context-graph-authority-dependency.js.map +1 -0
  25. package/dist/context-graph-binding-state.d.ts +6 -0
  26. package/dist/context-graph-binding-state.d.ts.map +1 -1
  27. package/dist/context-graph-binding-state.js +17 -10
  28. package/dist/context-graph-binding-state.js.map +1 -1
  29. package/dist/context-graph-claim-proof.d.ts +74 -0
  30. package/dist/context-graph-claim-proof.d.ts.map +1 -0
  31. package/dist/context-graph-claim-proof.js +137 -0
  32. package/dist/context-graph-claim-proof.js.map +1 -0
  33. package/dist/context-graph-member-proof.d.ts +33 -0
  34. package/dist/context-graph-member-proof.d.ts.map +1 -0
  35. package/dist/context-graph-member-proof.js +142 -0
  36. package/dist/context-graph-member-proof.js.map +1 -0
  37. package/dist/context-graph-membership-persist-scheduler.d.ts +7 -23
  38. package/dist/context-graph-membership-persist-scheduler.d.ts.map +1 -1
  39. package/dist/context-graph-membership-persist-scheduler.js +12 -88
  40. package/dist/context-graph-membership-persist-scheduler.js.map +1 -1
  41. package/dist/context-graph-meta-confirmation.d.ts +22 -2
  42. package/dist/context-graph-meta-confirmation.d.ts.map +1 -1
  43. package/dist/context-graph-meta-confirmation.js +54 -23
  44. package/dist/context-graph-meta-confirmation.js.map +1 -1
  45. package/dist/context-graph-meta-projection.d.ts +13 -2
  46. package/dist/context-graph-meta-projection.d.ts.map +1 -1
  47. package/dist/context-graph-meta-projection.js +61 -24
  48. package/dist/context-graph-meta-projection.js.map +1 -1
  49. package/dist/context-graph-metadata-relocation.d.ts +18 -30
  50. package/dist/context-graph-metadata-relocation.d.ts.map +1 -1
  51. package/dist/context-graph-metadata-relocation.js +32 -2
  52. package/dist/context-graph-metadata-relocation.js.map +1 -1
  53. package/dist/context-graph-private-meta-proof.d.ts +8 -9
  54. package/dist/context-graph-private-meta-proof.d.ts.map +1 -1
  55. package/dist/context-graph-private-meta-proof.js +25 -89
  56. package/dist/context-graph-private-meta-proof.js.map +1 -1
  57. package/dist/context-graph-public-meta-proof.d.ts +11 -1
  58. package/dist/context-graph-public-meta-proof.d.ts.map +1 -1
  59. package/dist/context-graph-public-meta-proof.js +23 -3
  60. package/dist/context-graph-public-meta-proof.js.map +1 -1
  61. package/dist/context-graph-read-authority.d.ts +30 -3
  62. package/dist/context-graph-read-authority.d.ts.map +1 -1
  63. package/dist/context-graph-read-authority.js +62 -18
  64. package/dist/context-graph-read-authority.js.map +1 -1
  65. package/dist/context-graph-storage-discovery.d.ts +14 -4
  66. package/dist/context-graph-storage-discovery.d.ts.map +1 -1
  67. package/dist/context-graph-storage-discovery.js +27 -7
  68. package/dist/context-graph-storage-discovery.js.map +1 -1
  69. package/dist/context-graph-subscription-authority-recovery.d.ts +7 -0
  70. package/dist/context-graph-subscription-authority-recovery.d.ts.map +1 -1
  71. package/dist/context-graph-subscription-authority-recovery.js +1 -0
  72. package/dist/context-graph-subscription-authority-recovery.js.map +1 -1
  73. package/dist/context-graph-subscription-persist-scheduler.d.ts +52 -0
  74. package/dist/context-graph-subscription-persist-scheduler.d.ts.map +1 -0
  75. package/dist/context-graph-subscription-persist-scheduler.js +78 -0
  76. package/dist/context-graph-subscription-persist-scheduler.js.map +1 -0
  77. package/dist/curator-dial-address.d.ts +16 -0
  78. package/dist/curator-dial-address.d.ts.map +1 -0
  79. package/dist/curator-dial-address.js +58 -0
  80. package/dist/curator-dial-address.js.map +1 -0
  81. package/dist/curator-meta-refresh.d.ts +18 -4
  82. package/dist/curator-meta-refresh.d.ts.map +1 -1
  83. package/dist/curator-meta-refresh.js +61 -58
  84. package/dist/curator-meta-refresh.js.map +1 -1
  85. package/dist/curator-peer-connection.d.ts +21 -0
  86. package/dist/curator-peer-connection.d.ts.map +1 -0
  87. package/dist/curator-peer-connection.js +41 -0
  88. package/dist/curator-peer-connection.js.map +1 -0
  89. package/dist/dkg-agent-agents-phonebook.d.ts +41 -0
  90. package/dist/dkg-agent-agents-phonebook.d.ts.map +1 -0
  91. package/dist/dkg-agent-agents-phonebook.js +155 -0
  92. package/dist/dkg-agent-agents-phonebook.js.map +1 -0
  93. package/dist/dkg-agent-base.d.ts +162 -24
  94. package/dist/dkg-agent-base.d.ts.map +1 -1
  95. package/dist/dkg-agent-base.js +175 -147
  96. package/dist/dkg-agent-base.js.map +1 -1
  97. package/dist/dkg-agent-cg-chain-observation.d.ts +6 -1
  98. package/dist/dkg-agent-cg-chain-observation.d.ts.map +1 -1
  99. package/dist/dkg-agent-cg-chain-observation.js +20 -5
  100. package/dist/dkg-agent-cg-chain-observation.js.map +1 -1
  101. package/dist/dkg-agent-cg-name-resolution.d.ts +38 -2
  102. package/dist/dkg-agent-cg-name-resolution.d.ts.map +1 -1
  103. package/dist/dkg-agent-cg-name-resolution.js +100 -8
  104. package/dist/dkg-agent-cg-name-resolution.js.map +1 -1
  105. package/dist/dkg-agent-cg-registry.d.ts +43 -3
  106. package/dist/dkg-agent-cg-registry.d.ts.map +1 -1
  107. package/dist/dkg-agent-cg-registry.js +267 -129
  108. package/dist/dkg-agent-cg-registry.js.map +1 -1
  109. package/dist/dkg-agent-cg-resolve.d.ts +6 -4
  110. package/dist/dkg-agent-cg-resolve.d.ts.map +1 -1
  111. package/dist/dkg-agent-cg-resolve.js +40 -18
  112. package/dist/dkg-agent-cg-resolve.js.map +1 -1
  113. package/dist/dkg-agent-constants.d.ts +10 -2
  114. package/dist/dkg-agent-constants.d.ts.map +1 -1
  115. package/dist/dkg-agent-constants.js +10 -2
  116. package/dist/dkg-agent-constants.js.map +1 -1
  117. package/dist/dkg-agent-context-graph.d.ts.map +1 -1
  118. package/dist/dkg-agent-context-graph.js +1 -5
  119. package/dist/dkg-agent-context-graph.js.map +1 -1
  120. package/dist/dkg-agent-crypto.d.ts +128 -21
  121. package/dist/dkg-agent-crypto.d.ts.map +1 -1
  122. package/dist/dkg-agent-crypto.js +824 -176
  123. package/dist/dkg-agent-crypto.js.map +1 -1
  124. package/dist/dkg-agent-diagnostics.d.ts.map +1 -1
  125. package/dist/dkg-agent-diagnostics.js +4 -3
  126. package/dist/dkg-agent-diagnostics.js.map +1 -1
  127. package/dist/dkg-agent-helpers.d.ts +2 -2
  128. package/dist/dkg-agent-helpers.d.ts.map +1 -1
  129. package/dist/dkg-agent-helpers.js +3 -3
  130. package/dist/dkg-agent-helpers.js.map +1 -1
  131. package/dist/dkg-agent-join.d.ts +12 -1
  132. package/dist/dkg-agent-join.d.ts.map +1 -1
  133. package/dist/dkg-agent-join.js +80 -92
  134. package/dist/dkg-agent-join.js.map +1 -1
  135. package/dist/dkg-agent-lifecycle.d.ts +129 -22
  136. package/dist/dkg-agent-lifecycle.d.ts.map +1 -1
  137. package/dist/dkg-agent-lifecycle.js +690 -211
  138. package/dist/dkg-agent-lifecycle.js.map +1 -1
  139. package/dist/dkg-agent-publish.d.ts +33 -40
  140. package/dist/dkg-agent-publish.d.ts.map +1 -1
  141. package/dist/dkg-agent-publish.js +194 -281
  142. package/dist/dkg-agent-publish.js.map +1 -1
  143. package/dist/dkg-agent-query.d.ts +7 -0
  144. package/dist/dkg-agent-query.d.ts.map +1 -1
  145. package/dist/dkg-agent-query.js +102 -86
  146. package/dist/dkg-agent-query.js.map +1 -1
  147. package/dist/dkg-agent-registered-private-empty-vm.d.ts +70 -0
  148. package/dist/dkg-agent-registered-private-empty-vm.d.ts.map +1 -0
  149. package/dist/dkg-agent-registered-private-empty-vm.js +133 -0
  150. package/dist/dkg-agent-registered-private-empty-vm.js.map +1 -0
  151. package/dist/dkg-agent-rfc64-catalog-auto-publish.d.ts +8 -3
  152. package/dist/dkg-agent-rfc64-catalog-auto-publish.d.ts.map +1 -1
  153. package/dist/dkg-agent-rfc64-catalog-auto-publish.js +45 -51
  154. package/dist/dkg-agent-rfc64-catalog-auto-publish.js.map +1 -1
  155. package/dist/dkg-agent-rfc64-catalog.d.ts +87 -80
  156. package/dist/dkg-agent-rfc64-catalog.d.ts.map +1 -1
  157. package/dist/dkg-agent-rfc64-catalog.js +726 -476
  158. package/dist/dkg-agent-rfc64-catalog.js.map +1 -1
  159. package/dist/dkg-agent-rfc64-meta-bootstrap.d.ts +6 -1
  160. package/dist/dkg-agent-rfc64-meta-bootstrap.d.ts.map +1 -1
  161. package/dist/dkg-agent-rfc64-meta-bootstrap.js +29 -13
  162. package/dist/dkg-agent-rfc64-meta-bootstrap.js.map +1 -1
  163. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.d.ts +8 -0
  164. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.d.ts.map +1 -1
  165. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.js +249 -40
  166. package/dist/dkg-agent-rfc64-swm-catalog-projection-supervisor.js.map +1 -1
  167. package/dist/dkg-agent-rfc64-swm-catalog-projection.d.ts.map +1 -1
  168. package/dist/dkg-agent-rfc64-swm-catalog-projection.js +3 -2
  169. package/dist/dkg-agent-rfc64-swm-catalog-projection.js.map +1 -1
  170. package/dist/dkg-agent-swm-host.d.ts +217 -52
  171. package/dist/dkg-agent-swm-host.d.ts.map +1 -1
  172. package/dist/dkg-agent-swm-host.js +1305 -858
  173. package/dist/dkg-agent-swm-host.js.map +1 -1
  174. package/dist/dkg-agent-swm-state.d.ts +15 -0
  175. package/dist/dkg-agent-swm-state.d.ts.map +1 -1
  176. package/dist/dkg-agent-swm-state.js +43 -0
  177. package/dist/dkg-agent-swm-state.js.map +1 -1
  178. package/dist/dkg-agent-swm-substrate.d.ts +49 -8
  179. package/dist/dkg-agent-swm-substrate.d.ts.map +1 -1
  180. package/dist/dkg-agent-swm-substrate.js +219 -46
  181. package/dist/dkg-agent-swm-substrate.js.map +1 -1
  182. package/dist/dkg-agent-types.d.ts +86 -27
  183. package/dist/dkg-agent-types.d.ts.map +1 -1
  184. package/dist/dkg-agent-types.js.map +1 -1
  185. package/dist/dkg-agent-vm-promotion.d.ts +4 -0
  186. package/dist/dkg-agent-vm-promotion.d.ts.map +1 -1
  187. package/dist/dkg-agent-vm-promotion.js +40 -5
  188. package/dist/dkg-agent-vm-promotion.js.map +1 -1
  189. package/dist/dkg-agent-vm-reconcile-scheduling.d.ts +7 -0
  190. package/dist/dkg-agent-vm-reconcile-scheduling.d.ts.map +1 -1
  191. package/dist/dkg-agent-vm-reconcile-scheduling.js +18 -0
  192. package/dist/dkg-agent-vm-reconcile-scheduling.js.map +1 -1
  193. package/dist/dkg-agent.d.ts +31 -2
  194. package/dist/dkg-agent.d.ts.map +1 -1
  195. package/dist/dkg-agent.js +188 -72
  196. package/dist/dkg-agent.js.map +1 -1
  197. package/dist/exact-graph-content-verifier.d.ts.map +1 -1
  198. package/dist/exact-graph-content-verifier.js +3 -2
  199. package/dist/exact-graph-content-verifier.js.map +1 -1
  200. package/dist/finalization-handler.d.ts +26 -211
  201. package/dist/finalization-handler.d.ts.map +1 -1
  202. package/dist/finalization-handler.js +94 -1652
  203. package/dist/finalization-handler.js.map +1 -1
  204. package/dist/finalization-recovery-sqlite-displacement.d.ts +37 -0
  205. package/dist/finalization-recovery-sqlite-displacement.d.ts.map +1 -0
  206. package/dist/finalization-recovery-sqlite-displacement.js +102 -0
  207. package/dist/finalization-recovery-sqlite-displacement.js.map +1 -0
  208. package/dist/finalization-recovery-sqlite-policy.d.ts +20 -4
  209. package/dist/finalization-recovery-sqlite-policy.d.ts.map +1 -1
  210. package/dist/finalization-recovery-sqlite-policy.js +21 -5
  211. package/dist/finalization-recovery-sqlite-policy.js.map +1 -1
  212. package/dist/finalization-recovery-sqlite-rows.d.ts +53 -0
  213. package/dist/finalization-recovery-sqlite-rows.d.ts.map +1 -0
  214. package/dist/finalization-recovery-sqlite-rows.js +77 -0
  215. package/dist/finalization-recovery-sqlite-rows.js.map +1 -0
  216. package/dist/finalization-recovery-sqlite-store.d.ts +10 -4
  217. package/dist/finalization-recovery-sqlite-store.d.ts.map +1 -1
  218. package/dist/finalization-recovery-sqlite-store.js +49 -50
  219. package/dist/finalization-recovery-sqlite-store.js.map +1 -1
  220. package/dist/finalization-recovery-store.d.ts +18 -0
  221. package/dist/finalization-recovery-store.d.ts.map +1 -1
  222. package/dist/finalization-recovery-store.js +24 -0
  223. package/dist/finalization-recovery-store.js.map +1 -1
  224. package/dist/finalization-recovery-worker.js +1 -1
  225. package/dist/finalization-recovery-worker.js.map +1 -1
  226. package/dist/finalization-recovery.d.ts +2 -3
  227. package/dist/finalization-recovery.d.ts.map +1 -1
  228. package/dist/finalization-recovery.js +12 -9
  229. package/dist/finalization-recovery.js.map +1 -1
  230. package/dist/finalized-authority-cold-resolution.d.ts +6 -1
  231. package/dist/finalized-authority-cold-resolution.d.ts.map +1 -1
  232. package/dist/finalized-authority-cold-resolution.js +22 -3
  233. package/dist/finalized-authority-cold-resolution.js.map +1 -1
  234. package/dist/gossip-publish-handler.d.ts.map +1 -1
  235. package/dist/gossip-publish-handler.js +4 -2
  236. package/dist/gossip-publish-handler.js.map +1 -1
  237. package/dist/gossip-session.d.ts +29 -0
  238. package/dist/gossip-session.d.ts.map +1 -0
  239. package/dist/gossip-session.js +48 -0
  240. package/dist/gossip-session.js.map +1 -0
  241. package/dist/index.d.ts +4 -1
  242. package/dist/index.d.ts.map +1 -1
  243. package/dist/index.js +4 -0
  244. package/dist/index.js.map +1 -1
  245. package/dist/internal/context-graph-authority/approved-member-acceptance.d.ts +61 -0
  246. package/dist/internal/context-graph-authority/approved-member-acceptance.d.ts.map +1 -0
  247. package/dist/internal/context-graph-authority/approved-member-acceptance.js +75 -0
  248. package/dist/internal/context-graph-authority/approved-member-acceptance.js.map +1 -0
  249. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.d.ts +5 -5
  250. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.d.ts.map +1 -1
  251. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.js +59 -49
  252. package/dist/internal/context-graph-authority/context-graph-agent-gate-authority.js.map +1 -1
  253. package/dist/internal/context-graph-authority/context-graph-authority.d.ts +1 -0
  254. package/dist/internal/context-graph-authority/context-graph-authority.d.ts.map +1 -1
  255. package/dist/internal/context-graph-authority/context-graph-authority.js +25 -0
  256. package/dist/internal/context-graph-authority/context-graph-authority.js.map +1 -1
  257. package/dist/internal/context-graph-authority/finalized-target-projection.d.ts +17 -0
  258. package/dist/internal/context-graph-authority/finalized-target-projection.d.ts.map +1 -0
  259. package/dist/internal/context-graph-authority/finalized-target-projection.js +36 -0
  260. package/dist/internal/context-graph-authority/finalized-target-projection.js.map +1 -0
  261. package/dist/internal/context-graph-authority/swm-transport-authority.d.ts +84 -0
  262. package/dist/internal/context-graph-authority/swm-transport-authority.d.ts.map +1 -0
  263. package/dist/internal/context-graph-authority/swm-transport-authority.js +175 -0
  264. package/dist/internal/context-graph-authority/swm-transport-authority.js.map +1 -0
  265. package/dist/internal/context-graph-binding-abort.d.ts +3 -0
  266. package/dist/internal/context-graph-binding-abort.d.ts.map +1 -0
  267. package/dist/internal/context-graph-binding-abort.js +32 -0
  268. package/dist/internal/context-graph-binding-abort.js.map +1 -0
  269. package/dist/internal/context-graph-cache-invalidating-store.d.ts +3 -0
  270. package/dist/internal/context-graph-cache-invalidating-store.d.ts.map +1 -0
  271. package/dist/internal/context-graph-cache-invalidating-store.js +167 -0
  272. package/dist/internal/context-graph-cache-invalidating-store.js.map +1 -0
  273. package/dist/internal/context-graph-meta-record-copy.d.ts +3 -0
  274. package/dist/internal/context-graph-meta-record-copy.d.ts.map +1 -0
  275. package/dist/internal/context-graph-meta-record-copy.js +21 -0
  276. package/dist/internal/context-graph-meta-record-copy.js.map +1 -0
  277. package/dist/internal/gossip/host-mode-handler.d.ts +11 -0
  278. package/dist/internal/gossip/host-mode-handler.d.ts.map +1 -0
  279. package/dist/internal/gossip/host-mode-handler.js +41 -0
  280. package/dist/internal/gossip/host-mode-handler.js.map +1 -0
  281. package/dist/internal/join-encryption-key-bundle.d.ts +10 -0
  282. package/dist/internal/join-encryption-key-bundle.d.ts.map +1 -0
  283. package/dist/internal/join-encryption-key-bundle.js +72 -0
  284. package/dist/internal/join-encryption-key-bundle.js.map +1 -0
  285. package/dist/internal/knowledge-asset-vm-publish-request.d.ts +31 -0
  286. package/dist/internal/knowledge-asset-vm-publish-request.d.ts.map +1 -0
  287. package/dist/internal/knowledge-asset-vm-publish-request.js +91 -0
  288. package/dist/internal/knowledge-asset-vm-publish-request.js.map +1 -0
  289. package/dist/internal/lifecycle-sync-policy.d.ts +5 -0
  290. package/dist/internal/lifecycle-sync-policy.d.ts.map +1 -0
  291. package/dist/internal/lifecycle-sync-policy.js +12 -0
  292. package/dist/internal/lifecycle-sync-policy.js.map +1 -0
  293. package/dist/internal/local-private-member.d.ts +14 -0
  294. package/dist/internal/local-private-member.d.ts.map +1 -0
  295. package/dist/internal/local-private-member.js +21 -0
  296. package/dist/internal/local-private-member.js.map +1 -0
  297. package/dist/internal/promote/assertion-promote-precommit.d.ts +41 -1
  298. package/dist/internal/promote/assertion-promote-precommit.d.ts.map +1 -1
  299. package/dist/internal/promote/assertion-promote-precommit.js +79 -22
  300. package/dist/internal/promote/assertion-promote-precommit.js.map +1 -1
  301. package/dist/internal/storage-ack-owned-request.d.ts +16 -0
  302. package/dist/internal/storage-ack-owned-request.d.ts.map +1 -0
  303. package/dist/internal/storage-ack-owned-request.js +16 -0
  304. package/dist/internal/storage-ack-owned-request.js.map +1 -0
  305. package/dist/internal/vm-reconcile-local-admission-wait.d.ts +96 -0
  306. package/dist/internal/vm-reconcile-local-admission-wait.d.ts.map +1 -0
  307. package/dist/internal/vm-reconcile-local-admission-wait.js +226 -0
  308. package/dist/internal/vm-reconcile-local-admission-wait.js.map +1 -0
  309. package/dist/internal/vm-reconcile-read-authority.d.ts +27 -0
  310. package/dist/internal/vm-reconcile-read-authority.d.ts.map +1 -0
  311. package/dist/internal/vm-reconcile-read-authority.js +33 -0
  312. package/dist/internal/vm-reconcile-read-authority.js.map +1 -0
  313. package/dist/internal/vm-reconcile-sweep-admission.d.ts +2 -0
  314. package/dist/internal/vm-reconcile-sweep-admission.d.ts.map +1 -1
  315. package/dist/internal/vm-reconcile-sweep.d.ts +16 -4
  316. package/dist/internal/vm-reconcile-sweep.d.ts.map +1 -1
  317. package/dist/internal/vm-reconcile-sweep.js +91 -50
  318. package/dist/internal/vm-reconcile-sweep.js.map +1 -1
  319. package/dist/internal/workspace-projected-delegatees.d.ts +3 -0
  320. package/dist/internal/workspace-projected-delegatees.d.ts.map +1 -0
  321. package/dist/internal/workspace-projected-delegatees.js +34 -0
  322. package/dist/internal/workspace-projected-delegatees.js.map +1 -0
  323. package/dist/join-approval-restart-projection.d.ts +14 -0
  324. package/dist/join-approval-restart-projection.d.ts.map +1 -0
  325. package/dist/join-approval-restart-projection.js +32 -0
  326. package/dist/join-approval-restart-projection.js.map +1 -0
  327. package/dist/keyed-persist-scheduler.d.ts +72 -0
  328. package/dist/keyed-persist-scheduler.d.ts.map +1 -0
  329. package/dist/keyed-persist-scheduler.js +140 -0
  330. package/dist/keyed-persist-scheduler.js.map +1 -0
  331. package/dist/map-with-concurrency.d.ts +7 -0
  332. package/dist/map-with-concurrency.d.ts.map +1 -1
  333. package/dist/map-with-concurrency.js +36 -0
  334. package/dist/map-with-concurrency.js.map +1 -1
  335. package/dist/p2p/network-admission-coordinator.d.ts +15 -0
  336. package/dist/p2p/network-admission-coordinator.d.ts.map +1 -1
  337. package/dist/p2p/network-admission-coordinator.js +20 -2
  338. package/dist/p2p/network-admission-coordinator.js.map +1 -1
  339. package/dist/p2p/peer-connect.d.ts +10 -1
  340. package/dist/p2p/peer-connect.d.ts.map +1 -1
  341. package/dist/p2p/peer-connect.js +11 -2
  342. package/dist/p2p/peer-connect.js.map +1 -1
  343. package/dist/p2p/peer-selection.d.ts +8 -0
  344. package/dist/p2p/peer-selection.d.ts.map +1 -1
  345. package/dist/p2p/peer-selection.js +21 -12
  346. package/dist/p2p/peer-selection.js.map +1 -1
  347. package/dist/p2p/protocol-readiness.d.ts +3 -3
  348. package/dist/p2p/protocol-readiness.d.ts.map +1 -1
  349. package/dist/p2p/protocol-readiness.js +4 -3
  350. package/dist/p2p/protocol-readiness.js.map +1 -1
  351. package/dist/prepare-unscoped-context-graph-read-checks.d.ts.map +1 -1
  352. package/dist/prepare-unscoped-context-graph-read-checks.js +12 -0
  353. package/dist/prepare-unscoped-context-graph-read-checks.js.map +1 -1
  354. package/dist/registered-context-graph-authority.d.ts +19 -0
  355. package/dist/registered-context-graph-authority.d.ts.map +1 -1
  356. package/dist/registered-private-empty-vm-attempt-v1.d.ts +34 -0
  357. package/dist/registered-private-empty-vm-attempt-v1.d.ts.map +1 -0
  358. package/dist/registered-private-empty-vm-attempt-v1.js +120 -0
  359. package/dist/registered-private-empty-vm-attempt-v1.js.map +1 -0
  360. package/dist/reserved-ka-id-allocation.d.ts +12 -0
  361. package/dist/reserved-ka-id-allocation.d.ts.map +1 -0
  362. package/dist/reserved-ka-id-allocation.js +25 -0
  363. package/dist/reserved-ka-id-allocation.js.map +1 -0
  364. package/dist/rfc64/applied-catalog-authority-transition-v1.d.ts.map +1 -1
  365. package/dist/rfc64/applied-catalog-authority-transition-v1.js +15 -17
  366. package/dist/rfc64/applied-catalog-authority-transition-v1.js.map +1 -1
  367. package/dist/rfc64/authority-rpc-circuit-breaker-v1.d.ts +5 -3
  368. package/dist/rfc64/authority-rpc-circuit-breaker-v1.d.ts.map +1 -1
  369. package/dist/rfc64/authority-rpc-circuit-breaker-v1.js +9 -0
  370. package/dist/rfc64/authority-rpc-circuit-breaker-v1.js.map +1 -1
  371. package/dist/rfc64/catalog-completion-evidence-v1.d.ts +38 -0
  372. package/dist/rfc64/catalog-completion-evidence-v1.d.ts.map +1 -0
  373. package/dist/rfc64/catalog-completion-evidence-v1.js +49 -0
  374. package/dist/rfc64/catalog-completion-evidence-v1.js.map +1 -0
  375. package/dist/rfc64/catalog-operational-applied-heads-v1.d.ts +12 -13
  376. package/dist/rfc64/catalog-operational-applied-heads-v1.d.ts.map +1 -1
  377. package/dist/rfc64/catalog-operational-applied-heads-v1.js +17 -52
  378. package/dist/rfc64/catalog-operational-applied-heads-v1.js.map +1 -1
  379. package/dist/rfc64/catalog-operational-reads-v1.d.ts +13 -0
  380. package/dist/rfc64/catalog-operational-reads-v1.d.ts.map +1 -0
  381. package/dist/rfc64/catalog-operational-reads-v1.js +56 -0
  382. package/dist/rfc64/catalog-operational-reads-v1.js.map +1 -0
  383. package/dist/rfc64/catalog-operational-targets-v1.d.ts +55 -0
  384. package/dist/rfc64/catalog-operational-targets-v1.d.ts.map +1 -0
  385. package/dist/rfc64/catalog-operational-targets-v1.js +379 -0
  386. package/dist/rfc64/catalog-operational-targets-v1.js.map +1 -0
  387. package/dist/rfc64/catalog-repair-diagnostics-v1.d.ts +28 -0
  388. package/dist/rfc64/catalog-repair-diagnostics-v1.d.ts.map +1 -0
  389. package/dist/rfc64/catalog-repair-diagnostics-v1.js +93 -0
  390. package/dist/rfc64/catalog-repair-diagnostics-v1.js.map +1 -0
  391. package/dist/rfc64/catalog-repair-retry-v1.d.ts +13 -0
  392. package/dist/rfc64/catalog-repair-retry-v1.d.ts.map +1 -0
  393. package/dist/rfc64/catalog-repair-retry-v1.js +39 -0
  394. package/dist/rfc64/catalog-repair-retry-v1.js.map +1 -0
  395. package/dist/rfc64/catalog-replay-recovery-runtime-v1.d.ts +52 -0
  396. package/dist/rfc64/catalog-replay-recovery-runtime-v1.d.ts.map +1 -1
  397. package/dist/rfc64/catalog-replay-recovery-runtime-v1.js +188 -32
  398. package/dist/rfc64/catalog-replay-recovery-runtime-v1.js.map +1 -1
  399. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.d.ts +2 -8
  400. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.d.ts.map +1 -1
  401. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.js +10 -37
  402. package/dist/rfc64/catalog-replay-snapshot-runtime-v1.js.map +1 -1
  403. package/dist/rfc64/catalog-rollout-authority-v1.d.ts +13 -0
  404. package/dist/rfc64/catalog-rollout-authority-v1.d.ts.map +1 -1
  405. package/dist/rfc64/catalog-rollout-authority-v1.js +11 -0
  406. package/dist/rfc64/catalog-rollout-authority-v1.js.map +1 -1
  407. package/dist/rfc64/catalog-row-authorship.d.ts +12 -0
  408. package/dist/rfc64/catalog-row-authorship.d.ts.map +1 -1
  409. package/dist/rfc64/catalog-row-authorship.js +110 -57
  410. package/dist/rfc64/catalog-row-authorship.js.map +1 -1
  411. package/dist/rfc64/inventory-v1/candidate.d.ts +31 -10
  412. package/dist/rfc64/inventory-v1/candidate.d.ts.map +1 -1
  413. package/dist/rfc64/inventory-v1/candidate.js +51 -16
  414. package/dist/rfc64/inventory-v1/candidate.js.map +1 -1
  415. package/dist/rfc64/inventory-v1/index.d.ts +1 -1
  416. package/dist/rfc64/inventory-v1/index.d.ts.map +1 -1
  417. package/dist/rfc64/inventory-v1/index.js +1 -1
  418. package/dist/rfc64/inventory-v1/index.js.map +1 -1
  419. package/dist/rfc64/inventory-v1/open.d.ts.map +1 -1
  420. package/dist/rfc64/inventory-v1/open.js +7 -4
  421. package/dist/rfc64/inventory-v1/open.js.map +1 -1
  422. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.d.ts +3 -1
  423. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.d.ts.map +1 -1
  424. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.js +15 -0
  425. package/dist/rfc64/inventory-v1/swm-author-inventory-persistence.js.map +1 -1
  426. package/dist/rfc64/legacy-swm-boundary-codec-v1.d.ts +25 -0
  427. package/dist/rfc64/legacy-swm-boundary-codec-v1.d.ts.map +1 -0
  428. package/dist/rfc64/legacy-swm-boundary-codec-v1.js +127 -0
  429. package/dist/rfc64/legacy-swm-boundary-codec-v1.js.map +1 -0
  430. package/dist/rfc64/legacy-swm-boundary-v1.d.ts +12 -0
  431. package/dist/rfc64/legacy-swm-boundary-v1.d.ts.map +1 -1
  432. package/dist/rfc64/legacy-swm-boundary-v1.js +83 -144
  433. package/dist/rfc64/legacy-swm-boundary-v1.js.map +1 -1
  434. package/dist/rfc64/private-catalog-subscription-readiness-v1.d.ts +33 -0
  435. package/dist/rfc64/private-catalog-subscription-readiness-v1.d.ts.map +1 -0
  436. package/dist/rfc64/private-catalog-subscription-readiness-v1.js +97 -0
  437. package/dist/rfc64/private-catalog-subscription-readiness-v1.js.map +1 -0
  438. package/dist/rfc64/private-read-roster-v1.d.ts +14 -0
  439. package/dist/rfc64/private-read-roster-v1.d.ts.map +1 -0
  440. package/dist/rfc64/private-read-roster-v1.js +57 -0
  441. package/dist/rfc64/private-read-roster-v1.js.map +1 -0
  442. package/dist/rfc64/public-catalog-native-receiver-v1.d.ts.map +1 -1
  443. package/dist/rfc64/public-catalog-native-receiver-v1.js +26 -21
  444. package/dist/rfc64/public-catalog-native-receiver-v1.js.map +1 -1
  445. package/dist/rfc64/public-catalog-native-reconciler-v1.d.ts +17 -11
  446. package/dist/rfc64/public-catalog-native-reconciler-v1.d.ts.map +1 -1
  447. package/dist/rfc64/public-catalog-native-reconciler-v1.js +10 -8
  448. package/dist/rfc64/public-catalog-native-reconciler-v1.js.map +1 -1
  449. package/dist/rfc64/public-catalog-receiver-v1.d.ts +9 -0
  450. package/dist/rfc64/public-catalog-receiver-v1.d.ts.map +1 -1
  451. package/dist/rfc64/public-catalog-receiver-v1.js +11 -2
  452. package/dist/rfc64/public-catalog-receiver-v1.js.map +1 -1
  453. package/dist/rfc64/public-catalog-service-v1.d.ts.map +1 -1
  454. package/dist/rfc64/public-catalog-service-v1.js +21 -22
  455. package/dist/rfc64/public-catalog-service-v1.js.map +1 -1
  456. package/dist/rfc64/public-catalog-successor-producer-v1.d.ts.map +1 -1
  457. package/dist/rfc64/public-catalog-successor-producer-v1.js +5 -4
  458. package/dist/rfc64/public-catalog-successor-producer-v1.js.map +1 -1
  459. package/dist/rfc64/registered-private-empty-vm-proof-v1.d.ts +20 -0
  460. package/dist/rfc64/registered-private-empty-vm-proof-v1.d.ts.map +1 -0
  461. package/dist/rfc64/registered-private-empty-vm-proof-v1.js +26 -0
  462. package/dist/rfc64/registered-private-empty-vm-proof-v1.js.map +1 -0
  463. package/dist/rfc64/swm-catalog-durable-asset-resolver-v1.d.ts.map +1 -1
  464. package/dist/rfc64/swm-catalog-durable-asset-resolver-v1.js +60 -53
  465. package/dist/rfc64/swm-catalog-durable-asset-resolver-v1.js.map +1 -1
  466. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.d.ts +2 -1
  467. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.d.ts.map +1 -1
  468. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.js +44 -4
  469. package/dist/rfc64/swm-inventory-catalog-reconciler-v1.js.map +1 -1
  470. package/dist/rfc64/swm-inventory-shadow-runtime-v1.d.ts +3 -1
  471. package/dist/rfc64/swm-inventory-shadow-runtime-v1.d.ts.map +1 -1
  472. package/dist/rfc64/swm-inventory-shadow-runtime-v1.js +34 -0
  473. package/dist/rfc64/swm-inventory-shadow-runtime-v1.js.map +1 -1
  474. package/dist/sync/auth/pipe-request-tail.d.ts +5 -1
  475. package/dist/sync/auth/pipe-request-tail.d.ts.map +1 -1
  476. package/dist/sync/auth/pipe-request-tail.js +13 -3
  477. package/dist/sync/auth/pipe-request-tail.js.map +1 -1
  478. package/dist/sync/auth/request-build.d.ts +3 -0
  479. package/dist/sync/auth/request-build.d.ts.map +1 -1
  480. package/dist/sync/auth/request-build.js +11 -2
  481. package/dist/sync/auth/request-build.js.map +1 -1
  482. package/dist/sync/backpressure.d.ts +27 -16
  483. package/dist/sync/backpressure.d.ts.map +1 -1
  484. package/dist/sync/backpressure.js +66 -40
  485. package/dist/sync/backpressure.js.map +1 -1
  486. package/dist/sync/catchup-policy.d.ts +2 -0
  487. package/dist/sync/catchup-policy.d.ts.map +1 -1
  488. package/dist/sync/catchup-policy.js +2 -0
  489. package/dist/sync/catchup-policy.js.map +1 -1
  490. package/dist/sync/exact-asset-fetch.d.ts +22 -0
  491. package/dist/sync/exact-asset-fetch.d.ts.map +1 -1
  492. package/dist/sync/exact-asset-fetch.js +30 -3
  493. package/dist/sync/exact-asset-fetch.js.map +1 -1
  494. package/dist/sync/exact-assets.d.ts +7 -5
  495. package/dist/sync/exact-assets.d.ts.map +1 -1
  496. package/dist/sync/exact-assets.js +13 -8
  497. package/dist/sync/exact-assets.js.map +1 -1
  498. package/dist/sync/exact-batch-observation.d.ts +3 -0
  499. package/dist/sync/exact-batch-observation.d.ts.map +1 -0
  500. package/dist/sync/exact-batch-observation.js +13 -0
  501. package/dist/sync/exact-batch-observation.js.map +1 -0
  502. package/dist/sync/exact-batch-stream-capability.d.ts +24 -0
  503. package/dist/sync/exact-batch-stream-capability.d.ts.map +1 -0
  504. package/dist/sync/exact-batch-stream-capability.js +88 -0
  505. package/dist/sync/exact-batch-stream-capability.js.map +1 -0
  506. package/dist/sync/exact-batch-stream-contract.d.ts +78 -0
  507. package/dist/sync/exact-batch-stream-contract.d.ts.map +1 -0
  508. package/dist/sync/exact-batch-stream-contract.js +206 -0
  509. package/dist/sync/exact-batch-stream-contract.js.map +1 -0
  510. package/dist/sync/on-connect/sync-on-connect.d.ts +1 -1
  511. package/dist/sync/on-connect/sync-on-connect.d.ts.map +1 -1
  512. package/dist/sync/on-connect/sync-on-connect.js +3 -3
  513. package/dist/sync/on-connect/sync-on-connect.js.map +1 -1
  514. package/dist/sync/on-demand-agents-phonebook.d.ts +162 -0
  515. package/dist/sync/on-demand-agents-phonebook.d.ts.map +1 -0
  516. package/dist/sync/on-demand-agents-phonebook.js +571 -0
  517. package/dist/sync/on-demand-agents-phonebook.js.map +1 -0
  518. package/dist/sync/peer-connection.d.ts.map +1 -1
  519. package/dist/sync/peer-connection.js +11 -2
  520. package/dist/sync/peer-connection.js.map +1 -1
  521. package/dist/sync/priority-admission-queue.d.ts +17 -0
  522. package/dist/sync/priority-admission-queue.d.ts.map +1 -1
  523. package/dist/sync/priority-admission-queue.js +58 -37
  524. package/dist/sync/priority-admission-queue.js.map +1 -1
  525. package/dist/sync/requester/admission-boundary.d.ts +12 -0
  526. package/dist/sync/requester/admission-boundary.d.ts.map +1 -0
  527. package/dist/sync/requester/admission-boundary.js +22 -0
  528. package/dist/sync/requester/admission-boundary.js.map +1 -0
  529. package/dist/sync/requester/durable-sync.d.ts +2 -1
  530. package/dist/sync/requester/durable-sync.d.ts.map +1 -1
  531. package/dist/sync/requester/durable-sync.js +3 -188
  532. package/dist/sync/requester/durable-sync.js.map +1 -1
  533. package/dist/sync/requester/exact-batch-stream-driver.d.ts +83 -0
  534. package/dist/sync/requester/exact-batch-stream-driver.d.ts.map +1 -0
  535. package/dist/sync/requester/exact-batch-stream-driver.js +299 -0
  536. package/dist/sync/requester/exact-batch-stream-driver.js.map +1 -0
  537. package/dist/sync/requester/exact-batch-stream.d.ts +72 -0
  538. package/dist/sync/requester/exact-batch-stream.d.ts.map +1 -0
  539. package/dist/sync/requester/exact-batch-stream.js +267 -0
  540. package/dist/sync/requester/exact-batch-stream.js.map +1 -0
  541. package/dist/sync/requester/exact-recovery-transport.d.ts +19 -0
  542. package/dist/sync/requester/exact-recovery-transport.d.ts.map +1 -0
  543. package/dist/sync/requester/exact-recovery-transport.js +3 -0
  544. package/dist/sync/requester/exact-recovery-transport.js.map +1 -0
  545. package/dist/sync/requester/finalized-swm-twin-reconciliation.js +12 -3
  546. package/dist/sync/requester/finalized-swm-twin-reconciliation.js.map +1 -1
  547. package/dist/sync/requester/graph-scoped-materialization.d.ts.map +1 -1
  548. package/dist/sync/requester/graph-scoped-materialization.js +61 -27
  549. package/dist/sync/requester/graph-scoped-materialization.js.map +1 -1
  550. package/dist/sync/requester/page-fetch.d.ts +7 -0
  551. package/dist/sync/requester/page-fetch.d.ts.map +1 -1
  552. package/dist/sync/requester/page-fetch.js +103 -49
  553. package/dist/sync/requester/page-fetch.js.map +1 -1
  554. package/dist/sync/requester/shared-memory-sync.d.ts +10 -5
  555. package/dist/sync/requester/shared-memory-sync.d.ts.map +1 -1
  556. package/dist/sync/requester/shared-memory-sync.js +149 -150
  557. package/dist/sync/requester/shared-memory-sync.js.map +1 -1
  558. package/dist/sync/requester/swm-materialization-memo.d.ts +12 -0
  559. package/dist/sync/requester/swm-materialization-memo.d.ts.map +1 -0
  560. package/dist/sync/requester/swm-materialization-memo.js +54 -0
  561. package/dist/sync/requester/swm-materialization-memo.js.map +1 -0
  562. package/dist/sync/requester/swm-recovery.d.ts +3 -29
  563. package/dist/sync/requester/swm-recovery.d.ts.map +1 -1
  564. package/dist/sync/requester/swm-recovery.js +11 -10
  565. package/dist/sync/requester/swm-recovery.js.map +1 -1
  566. package/dist/sync/requester/swm-snapshot-materializer.d.ts.map +1 -1
  567. package/dist/sync/requester/swm-snapshot-materializer.js +18 -0
  568. package/dist/sync/requester/swm-snapshot-materializer.js.map +1 -1
  569. package/dist/sync/requester/swm-target-executor.d.ts +6 -0
  570. package/dist/sync/requester/swm-target-executor.d.ts.map +1 -1
  571. package/dist/sync/requester/swm-target-executor.js +24 -3
  572. package/dist/sync/requester/swm-target-executor.js.map +1 -1
  573. package/dist/sync/requester/verified-asset-preparation.d.ts +9 -0
  574. package/dist/sync/requester/verified-asset-preparation.d.ts.map +1 -0
  575. package/dist/sync/requester/verified-asset-preparation.js +190 -0
  576. package/dist/sync/requester/verified-asset-preparation.js.map +1 -0
  577. package/dist/sync/responder/asset-metadata.d.ts +18 -0
  578. package/dist/sync/responder/asset-metadata.d.ts.map +1 -0
  579. package/dist/sync/responder/asset-metadata.js +27 -0
  580. package/dist/sync/responder/asset-metadata.js.map +1 -0
  581. package/dist/sync/responder/durable-data-request-policy.d.ts +2 -16
  582. package/dist/sync/responder/durable-data-request-policy.d.ts.map +1 -1
  583. package/dist/sync/responder/durable-data-request-policy.js +1 -31
  584. package/dist/sync/responder/durable-data-request-policy.js.map +1 -1
  585. package/dist/sync/responder/exact-asset-export-cache.d.ts +89 -0
  586. package/dist/sync/responder/exact-asset-export-cache.d.ts.map +1 -0
  587. package/dist/sync/responder/exact-asset-export-cache.js +550 -0
  588. package/dist/sync/responder/exact-asset-export-cache.js.map +1 -0
  589. package/dist/sync/responder/exact-batch-stream.d.ts +47 -0
  590. package/dist/sync/responder/exact-batch-stream.d.ts.map +1 -0
  591. package/dist/sync/responder/exact-batch-stream.js +151 -0
  592. package/dist/sync/responder/exact-batch-stream.js.map +1 -0
  593. package/dist/sync/responder/exact-data-session.d.ts +67 -0
  594. package/dist/sync/responder/exact-data-session.d.ts.map +1 -0
  595. package/dist/sync/responder/exact-data-session.js +130 -0
  596. package/dist/sync/responder/exact-data-session.js.map +1 -0
  597. package/dist/sync/responder/exact-graph-cursor-filter.d.ts +9 -0
  598. package/dist/sync/responder/exact-graph-cursor-filter.d.ts.map +1 -0
  599. package/dist/sync/responder/exact-graph-cursor-filter.js +101 -0
  600. package/dist/sync/responder/exact-graph-cursor-filter.js.map +1 -0
  601. package/dist/sync/responder/exact-graph-reader.d.ts +95 -0
  602. package/dist/sync/responder/exact-graph-reader.d.ts.map +1 -0
  603. package/dist/sync/responder/exact-graph-reader.js +623 -0
  604. package/dist/sync/responder/exact-graph-reader.js.map +1 -0
  605. package/dist/sync/responder/exact-page-reader.d.ts +37 -0
  606. package/dist/sync/responder/exact-page-reader.d.ts.map +1 -0
  607. package/dist/sync/responder/exact-page-reader.js +130 -0
  608. package/dist/sync/responder/exact-page-reader.js.map +1 -0
  609. package/dist/sync/responder/graph-plan.d.ts +19 -85
  610. package/dist/sync/responder/graph-plan.d.ts.map +1 -1
  611. package/dist/sync/responder/graph-plan.js +51 -988
  612. package/dist/sync/responder/graph-plan.js.map +1 -1
  613. package/dist/sync/responder/page-framing-policy.d.ts +31 -0
  614. package/dist/sync/responder/page-framing-policy.d.ts.map +1 -0
  615. package/dist/sync/responder/page-framing-policy.js +41 -0
  616. package/dist/sync/responder/page-framing-policy.js.map +1 -0
  617. package/dist/sync/responder/responder-row-page.d.ts +85 -0
  618. package/dist/sync/responder/responder-row-page.d.ts.map +1 -0
  619. package/dist/sync/responder/responder-row-page.js +181 -0
  620. package/dist/sync/responder/responder-row-page.js.map +1 -0
  621. package/dist/sync/responder/row-serialization.d.ts +34 -0
  622. package/dist/sync/responder/row-serialization.d.ts.map +1 -0
  623. package/dist/sync/responder/row-serialization.js +69 -0
  624. package/dist/sync/responder/row-serialization.js.map +1 -0
  625. package/dist/sync/responder/session-plan-memo.d.ts +20 -0
  626. package/dist/sync/responder/session-plan-memo.d.ts.map +1 -0
  627. package/dist/sync/responder/session-plan-memo.js +135 -0
  628. package/dist/sync/responder/session-plan-memo.js.map +1 -0
  629. package/dist/sync/responder/sync-handler.d.ts +26 -1
  630. package/dist/sync/responder/sync-handler.d.ts.map +1 -1
  631. package/dist/sync/responder/sync-handler.js +107 -58
  632. package/dist/sync/responder/sync-handler.js.map +1 -1
  633. package/dist/sync/shared-memory-completion.d.ts +30 -0
  634. package/dist/sync/shared-memory-completion.d.ts.map +1 -1
  635. package/dist/sync/shared-memory-completion.js +13 -0
  636. package/dist/sync/shared-memory-completion.js.map +1 -1
  637. package/dist/sync/system-context-graph-policy.d.ts +10 -0
  638. package/dist/sync/system-context-graph-policy.d.ts.map +1 -1
  639. package/dist/sync/system-context-graph-policy.js +11 -0
  640. package/dist/sync/system-context-graph-policy.js.map +1 -1
  641. package/dist/sync/wire-compression.d.ts +47 -0
  642. package/dist/sync/wire-compression.d.ts.map +1 -0
  643. package/dist/sync/wire-compression.js +111 -0
  644. package/dist/sync/wire-compression.js.map +1 -0
  645. package/dist/unscoped-query-consistency.d.ts +12 -0
  646. package/dist/unscoped-query-consistency.d.ts.map +1 -1
  647. package/dist/unscoped-query-consistency.js +17 -1
  648. package/dist/unscoped-query-consistency.js.map +1 -1
  649. package/dist/vm-promotion-audit.d.ts +2 -2
  650. package/dist/vm-promotion-audit.d.ts.map +1 -1
  651. package/dist/vm-promotion-audit.js +26 -9
  652. package/dist/vm-promotion-audit.js.map +1 -1
  653. package/dist/vm-publish-snapshot-preflight.d.ts +13 -0
  654. package/dist/vm-publish-snapshot-preflight.d.ts.map +1 -0
  655. package/dist/vm-publish-snapshot-preflight.js +94 -0
  656. package/dist/vm-publish-snapshot-preflight.js.map +1 -0
  657. package/dist/vm-reconcile-dispatcher.d.ts +42 -1
  658. package/dist/vm-reconcile-dispatcher.d.ts.map +1 -1
  659. package/dist/vm-reconcile-dispatcher.js +103 -4
  660. package/dist/vm-reconcile-dispatcher.js.map +1 -1
  661. package/dist/vm-reconcile-peer-topology.d.ts +7 -9
  662. package/dist/vm-reconcile-peer-topology.d.ts.map +1 -1
  663. package/dist/vm-reconcile-peer-topology.js +1 -37
  664. package/dist/vm-reconcile-peer-topology.js.map +1 -1
  665. package/dist/vm-recovery-candidate-order.d.ts +16 -0
  666. package/dist/vm-recovery-candidate-order.d.ts.map +1 -0
  667. package/dist/vm-recovery-candidate-order.js +24 -0
  668. package/dist/vm-recovery-candidate-order.js.map +1 -0
  669. package/dist/vm-recovery-core-transport-preference.d.ts +69 -0
  670. package/dist/vm-recovery-core-transport-preference.d.ts.map +1 -0
  671. package/dist/vm-recovery-core-transport-preference.js +131 -0
  672. package/dist/vm-recovery-core-transport-preference.js.map +1 -0
  673. package/dist/vm-recovery-experiment-policy.d.ts +24 -0
  674. package/dist/vm-recovery-experiment-policy.d.ts.map +1 -0
  675. package/dist/vm-recovery-experiment-policy.js +18 -0
  676. package/dist/vm-recovery-experiment-policy.js.map +1 -0
  677. package/dist/vm-recovery-footprint.d.ts +54 -0
  678. package/dist/vm-recovery-footprint.d.ts.map +1 -1
  679. package/dist/vm-recovery-footprint.js +88 -24
  680. package/dist/vm-recovery-footprint.js.map +1 -1
  681. package/dist/vm-recovery-microbatch.d.ts +2 -0
  682. package/dist/vm-recovery-microbatch.d.ts.map +1 -1
  683. package/dist/vm-recovery-microbatch.js +7 -3
  684. package/dist/vm-recovery-microbatch.js.map +1 -1
  685. package/dist/vm-recovery-pass-authority.d.ts +84 -0
  686. package/dist/vm-recovery-pass-authority.d.ts.map +1 -0
  687. package/dist/vm-recovery-pass-authority.js +126 -0
  688. package/dist/vm-recovery-pass-authority.js.map +1 -0
  689. package/dist/vm-recovery-phase-timing.d.ts +75 -0
  690. package/dist/vm-recovery-phase-timing.d.ts.map +1 -0
  691. package/dist/vm-recovery-phase-timing.js +236 -0
  692. package/dist/vm-recovery-phase-timing.js.map +1 -0
  693. package/dist/vm-recovery-preparation.d.ts +143 -0
  694. package/dist/vm-recovery-preparation.d.ts.map +1 -0
  695. package/dist/vm-recovery-preparation.js +433 -0
  696. package/dist/vm-recovery-preparation.js.map +1 -0
  697. package/dist/vm-recovery-provider-policy.d.ts +13 -1
  698. package/dist/vm-recovery-provider-policy.d.ts.map +1 -1
  699. package/dist/vm-recovery-provider-policy.js +37 -5
  700. package/dist/vm-recovery-provider-policy.js.map +1 -1
  701. package/dist/vm-recovery-stream-profile.d.ts +15 -0
  702. package/dist/vm-recovery-stream-profile.d.ts.map +1 -0
  703. package/dist/vm-recovery-stream-profile.js +53 -0
  704. package/dist/vm-recovery-stream-profile.js.map +1 -0
  705. package/dist/vm-recovery-stream-setback-policy.d.ts +54 -0
  706. package/dist/vm-recovery-stream-setback-policy.d.ts.map +1 -0
  707. package/dist/vm-recovery-stream-setback-policy.js +85 -0
  708. package/dist/vm-recovery-stream-setback-policy.js.map +1 -0
  709. package/dist/vm-recovery-timing-observer.d.ts +27 -0
  710. package/dist/vm-recovery-timing-observer.d.ts.map +1 -0
  711. package/dist/vm-recovery-timing-observer.js +49 -0
  712. package/dist/vm-recovery-timing-observer.js.map +1 -0
  713. package/dist/vm-recovery-transport-budget-policy.d.ts +32 -0
  714. package/dist/vm-recovery-transport-budget-policy.d.ts.map +1 -0
  715. package/dist/vm-recovery-transport-budget-policy.js +55 -0
  716. package/dist/vm-recovery-transport-budget-policy.js.map +1 -0
  717. package/dist/vm-recovery-transport-plan.d.ts +83 -0
  718. package/dist/vm-recovery-transport-plan.d.ts.map +1 -0
  719. package/dist/vm-recovery-transport-plan.js +117 -0
  720. package/dist/vm-recovery-transport-plan.js.map +1 -0
  721. package/dist/vm-refresh.d.ts +138 -0
  722. package/dist/vm-refresh.d.ts.map +1 -0
  723. package/dist/vm-refresh.js +201 -0
  724. package/dist/vm-refresh.js.map +1 -0
  725. package/package.json +19 -9
  726. package/dist/finalization-annotations.d.ts +0 -5
  727. package/dist/finalization-annotations.d.ts.map +0 -1
  728. package/dist/finalization-annotations.js +0 -6
  729. package/dist/finalization-annotations.js.map +0 -1
  730. package/dist/swm-ka-bound.d.ts +0 -21
  731. package/dist/swm-ka-bound.d.ts.map +0 -1
  732. package/dist/swm-ka-bound.js +0 -36
  733. package/dist/swm-ka-bound.js.map +0 -1
@@ -1,68 +1,18 @@
1
- import { SWM_SNAPSHOT_CONTENT_DIGEST_PREDICATE, SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE, } from './finalization-annotations.js';
2
- import { decodeFinalizationMessage, contextGraphWorkspaceGraphUri, contextGraphWorkspaceMetaGraphUri, contextGraphDataUri, contextGraphMetaUri, contextGraphOnChainIdBindingQuery, contextGraphSubGraphUri, validateSubGraphName, validateContextGraphId, DKGEvent, Logger, createOperationContext, assertSafeIri, isSafeIri, GRAPH_KA_CONTENT_SCOPE_VERSION, MemoryLayer, createGraphKnowledgeAssetScope, knowledgeAssetLayerGraphUri, DKG_ENTITY, DKG_ROOT_ENTITY_LEGACY, ENTITY_PRED_ALT, getMetrics, sparqlString, } from '@origintrail-official/dkg-core';
3
- import { deleteByPatternWithoutCount, GraphManager, loadSelectedSharedMemoryQuads, loadSharedMemorySliceWithKaBoundFallback, asGraphWriteRevisionSource, resolveGraphScopedOrLegacyMetadata, resolveSharedMemoryScopeGraphs, tryReplaceGraphAtomically, tryReplaceGraphAndSubjectAtomically, StoreSchedulerBusyError, } from '@origintrail-official/dkg-storage';
1
+ import { decodeFinalizationMessage, contextGraphMetaUri, validateSubGraphName, validateContextGraphId, DKGEvent, Logger, createOperationContext, assertSafeIri, GRAPH_KA_CONTENT_SCOPE_VERSION, MemoryLayer, createGraphKnowledgeAssetScope, knowledgeAssetLayerGraphUri, sparqlString, } from '@origintrail-official/dkg-core';
2
+ import { GraphManager, resolveGraphScopedOrLegacyMetadata, resolveSharedMemoryScopeGraphs, tryReplaceGraphAtomically, tryReplaceGraphAndSubjectAtomically, StoreSchedulerBusyError, } from '@origintrail-official/dkg-storage';
4
3
  import { resolvePublicFinalizedMaterializationAuthority, } from '@origintrail-official/dkg-chain';
5
- import { computeFlatKCRootV10 as computeFlatKCRoot, skolemizeByEntity, generatedPrivateCatalogFloorQuads, generatedPrivateCatalogTripleKeys, generateConfirmedFullMetadata, generateGraphKnowledgeAssetMetadata, buildDeterministicTokenRows, compareRootIris, getTentativeStatusQuad, insertBoundedAgentRegistryMeta, generateSubGraphRegistration, splitTrustedGeneratedCatalogRootMap, compareMaterializedVersion, readMaterializedVersion, shouldApplyMaterialization, writeMaterializedVersion, materializedVersionQuad, withMaterializationLock, workspacePublicQuadsDigest, KnowledgeAssetWorkspaceHeadCorruptError, isKnowledgeAssetWorkspaceHeadCorruptError, resolveKnowledgeAssetWorkspaceHead, } from '@origintrail-official/dkg-publisher';
4
+ import { generateGraphKnowledgeAssetMetadata, compareMaterializedVersion, readMaterializedVersion, writeMaterializedVersion, materializedVersionQuad, withMaterializationLock, workspacePublicQuadsDigest, KnowledgeAssetWorkspaceHeadCorruptError, isKnowledgeAssetWorkspaceHeadCorruptError, resolveKnowledgeAssetWorkspaceHead, } from '@origintrail-official/dkg-publisher';
6
5
  const DKG_NS = 'http://dkg.io/ontology/';
7
6
  const PROV_NS = 'http://www.w3.org/ns/prov#';
8
7
  const CHAIN_FINALIZED_RECONCILE_PEER_ID = 'chain-finalized-reconcile-v1';
9
- // Slow-query / canary tags for the finalization SWM slice (#1549). A healthy fleet
10
- // sees `.fallbackUnbounded` at ~0 relative to `.bounded`; a spike means the bound is
11
- // mis-derived or recurrence is common, and `DKG_DISABLE_SWM_KA_BOUND=1` is the lever.
12
- const SWM_SLICE_SOURCE = 'agent.finalization.sharedMemorySlice';
13
- const SWM_SLICE_SOURCE_BOUNDED = `${SWM_SLICE_SOURCE}.bounded`;
14
- const SWM_SLICE_SOURCE_WIDENED = `${SWM_SLICE_SOURCE}.fallbackUnbounded`;
15
8
  import { ethers } from 'ethers';
16
- import { createHash } from 'node:crypto';
17
- import { deriveSwmKaGraphBound } from './swm-ka-bound.js';
18
9
  import { FinalizationLifecycleLogger, finalizationLifecycleDecision, } from './finalization-lifecycle-logger.js';
19
10
  import { FinalizationRecoveryCapacityError, FinalizationRecovery, } from './finalization-recovery.js';
20
11
  import { FinalizationRecoveryWorker, } from './finalization-recovery-worker.js';
21
12
  import { recoverReceiptBackedGraphScopedEvidence } from './receipt-backed-graph-scoped-evidence.js';
22
13
  import { resolveConfirmedGraphScopedVm, resolveLocallyConfirmedGraphScopedVm, } from './confirmed-graph-scoped-vm-resolver.js';
23
14
  import { verifyExactGraphContent, } from './exact-graph-content-verifier.js';
24
- import { protobufScalarToBigInt, protobufScalarToNumber } from './protobuf-scalars.js';
25
15
  import { createDurableFinalizationRecoveryEligibility, } from './finalization-recovery-eligibility.js';
26
- /**
27
- * Predicate for the durable per-root keep-root-copy signal the publisher
28
- * persists into SWM workspace meta at publish time (the chain-driven
29
- * reconcile path's equivalent of the gossip envelope's `keepRootCopyOnLabel`).
30
- * Shared with `DKGAgent` so the write and read sites can't drift.
31
- */
32
- export const KEEP_ROOT_COPY_PREDICATE = `${DKG_NS}keepRootCopyOnLabel`;
33
- /**
34
- * Reader-maintained memo (#1609): the flat-KC merkle root a WorkspaceOperation's
35
- * SWM snapshot hashes to, paired with `SWM_SNAPSHOT_CONTENT_DIGEST_PREDICATE` (a
36
- * cheap digest of the exact content that produced it), stamped onto the op subject
37
- * (`urn:dkg:share:<cg>:<id>`) the first time `findSwmSnapshotInNamespace` computes
38
- * it. Lets a chain-reconcile lookup (a) resolve a *present* KA's op by root
39
- * directly (fast path), and (b) skip the expensive `computeFlatKCRoot` recompute
40
- * for an op whose content is unchanged (the digest still matches) — the recompute
41
- * that dominates beacon reconcile load when a KA published elsewhere forces a full
42
- * O(#WorkspaceOperations) scan to conclude "not here".
43
- *
44
- * This memo is a bridge, NOT the durable fix (see OT-RFC-60): a WorkspaceOperation
45
- * is assembled incrementally (data quads and private roots arrive over time via
46
- * *entity-keyed* writes that do NOT rewrite the op subject), so the stamp can go
47
- * stale without a structural invalidation. Correctness therefore does NOT rely on
48
- * the stamp being fresh:
49
- * - `verifyMerkleMatch` stays authoritative on the fast path — a stale stamp can
50
- * only ever cause a *missed* promotion, never a wrong one.
51
- * - the fallback scan re-reads EVERY op (it never excludes on stamp-presence) and
52
- * trusts the memoized root only when the content digest still matches; any
53
- * content change flips the digest → full recompute → the op is re-evaluated and
54
- * re-stamped. An op can never be stranded by a stale stamp.
55
- * The durable fix (OT-RFC-60) makes the root a write-maintained, indexed property
56
- * stamped once when an op becomes complete-and-immutable, removing both the
57
- * recompute AND the staleness by construction.
58
- *
59
- * Deliberately invisible to the sibling VM-reconcile negative cache: its
60
- * `readVmReconcileSwmGen` / `vmReconcileWorkspaceOperationPattern` fingerprints
61
- * select only `rootEntity`/`publishedAt` on the op subject (plus the separate data
62
- * graph), so stamping these predicates into the meta graph does not perturb the
63
- * generation signal the negative cache keys on — the two mechanisms don't fight.
64
- */
65
- export { SWM_SNAPSHOT_CONTENT_DIGEST_PREDICATE, SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE, } from './finalization-annotations.js';
66
16
  function stripOptionalLiteral(value) {
67
17
  if (!value)
68
18
  return undefined;
@@ -101,45 +51,6 @@ function resolveGraphScopedAccessEnvelope(head, requestedAccess) {
101
51
  function normalizedHex(value) {
102
52
  return value.replace(/^0x/i, '').toLowerCase();
103
53
  }
104
- /**
105
- * Ops kill-switch for the #1549 bounded SWM read. Set `DKG_DISABLE_SWM_KA_BOUND=1`
106
- * to fall back to the unbounded read with no redeploy. Read here at the
107
- * orchestration boundary so `deriveSwmKaGraphBound` (in `swm-ka-bound.ts`) stays a
108
- * deterministic identity transform.
109
- */
110
- function swmKaBoundDisabled() {
111
- return process.env.DKG_DISABLE_SWM_KA_BOUND === '1';
112
- }
113
- /**
114
- * TTL cap on the in-memory negative reconcile memo (#1609) — the longest a
115
- * "no local SWM snapshot" verdict may be trusted without a fresh scan even
116
- * when no write-generation change was observed. Bounds the exposure to any
117
- * SWM writer invisible to the adapter's write-generation counter (e.g. a
118
- * second process mutating a shared oxigraph-server) to "≤ TTL late", never
119
- * "never". Read per call (like `swmKaBoundDisabled`) so ops and tests can
120
- * retune it without a redeploy.
121
- */
122
- const VM_RECONCILE_NEGATIVE_TTL_MS_DEFAULT = 600_000;
123
- function vmReconcileNegativeTtlMs() {
124
- const raw = Number(process.env['DKG_VM_RECONCILE_NEGATIVE_TTL_MS']);
125
- return Number.isFinite(raw) && raw > 0 ? raw : VM_RECONCILE_NEGATIVE_TTL_MS_DEFAULT;
126
- }
127
- /** LRU cap for the negative reconcile memo — bounds memory across CGs × roots. */
128
- const VM_RECONCILE_NEGATIVE_MEMO_MAX_ENTRIES = 4096;
129
- const FINALIZATION_SWM_PAGE_ROWS_DEFAULT = 1_000;
130
- const FINALIZATION_SWM_MAX_ROWS_DEFAULT = 250_000;
131
- const FINALIZATION_SWM_MAX_BYTES_DEFAULT = 128 * 1024 * 1024;
132
- function positiveIntegerEnv(name, fallback) {
133
- const parsed = Number(process.env[name]);
134
- return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
135
- }
136
- function finalizationSwmResultBudget() {
137
- return {
138
- pageRows: positiveIntegerEnv('DKG_FINALIZATION_SWM_PAGE_ROWS', FINALIZATION_SWM_PAGE_ROWS_DEFAULT),
139
- maxRows: positiveIntegerEnv('DKG_FINALIZATION_SWM_MAX_ROWS', FINALIZATION_SWM_MAX_ROWS_DEFAULT),
140
- maxBytesEstimate: positiveIntegerEnv('DKG_FINALIZATION_SWM_MAX_BYTES', FINALIZATION_SWM_MAX_BYTES_DEFAULT),
141
- };
142
- }
143
54
  function isLegacyFinalizationEventBus(value) {
144
55
  return value !== undefined
145
56
  && typeof value.emit === 'function';
@@ -172,32 +83,15 @@ export class FinalizationHandler {
172
83
  lifecycle;
173
84
  processedUals = new Set();
174
85
  // Forward-prevention for the cgId-resolution race (RS heal): chain-authoritative
175
- // Legacy batch-id or graph-scoped KA-id -> cgId bindings, cached
176
- // POSITIVE-ONLY. A 0/miss is NEVER cached: caching a miss before the on-chain
177
- // KA->CG binding lands would pin finalization to the legacy fallback forever.
86
+ // KA-id -> cgId bindings, cached POSITIVE-ONLY. A 0/miss is NEVER cached:
87
+ // caching a miss before the on-chain KA->CG binding lands would pin
88
+ // finalization to the local fallback forever.
178
89
  chainCgIdByLookupId = new Map();
179
- // #1609 (2026-07-11/12 testnet incident): the write-generation source backing
180
- // the negative reconcile memo below. `null` when the store's adapter doesn't
181
- // track write generations — the memo is then DISABLED and every reconcile
182
- // scans (fail-open), matching pre-memo behavior.
183
- graphWriteGen;
184
- // Negative memo for `findSwmSnapshotForMerkleRoot`: "this (cg, namespace,
185
- // root) had NO matching local SWM snapshot at write generation G". Unlike
186
- // `chainCgIdByLookupId` above, caching the negative here is sound BECAUSE it
187
- // is generation-gated: the verdict is only replayed while the store proves
188
- // no local write has touched the CG since the scan. LRU, in-memory only —
189
- // a restart clears it (fail-open).
190
- negativeSnapshotMemo = new Map();
191
- /** Legacy WorkspaceOperation presence per (cg, namespace), gated the same way. */
192
- legacySwmOperationsMemo = new Map();
193
- /** Equivalent finalization/reconcile reads share one promise until it settles. */
194
- scanSingleFlights = new Map();
195
90
  recoveryWorker;
196
91
  finalizationRecoveryEligibility;
197
92
  constructor(store, chain, optionsOrEventBus, legacyResolveContextGraphOnChainId, legacyMarkContextGraphMetaDirtyFromQuads, legacyLifecycleLogOptions) {
198
93
  const options = normalizeFinalizationHandlerOptions(optionsOrEventBus, legacyResolveContextGraphOnChainId, legacyMarkContextGraphMetaDirtyFromQuads, legacyLifecycleLogOptions);
199
94
  this.store = store;
200
- this.graphWriteGen = asGraphWriteRevisionSource(store);
201
95
  this.chain = chain;
202
96
  this.eventBus = options.eventBus;
203
97
  this.resolveContextGraphOnChainId = options.resolveContextGraphOnChainId;
@@ -256,7 +150,6 @@ export class FinalizationHandler {
256
150
  });
257
151
  if (liveAdmission.status === 'invalid')
258
152
  return;
259
- let envelope;
260
153
  let candidate;
261
154
  if (liveAdmission.status === 'admitted') {
262
155
  const liveCandidate = liveAdmission.input.candidate;
@@ -317,22 +210,16 @@ export class FinalizationHandler {
317
210
  throw new Error(`Unhandled finalization recovery result: ${JSON.stringify(exhaustive)}`);
318
211
  }
319
212
  }
320
- envelope = {
321
- rawMessage: data,
322
- msg: liveAdmission.message,
323
- graphAdmission: { ok: true, value: candidate },
324
- };
325
213
  }
326
214
  else {
327
- envelope = this.decodeFinalizationEnvelope(data);
328
- }
329
- if (!envelope)
215
+ this.ignoreUnscopedFinalization(data, contextGraphId);
330
216
  return;
331
- // Compatibility path for legacy envelopes and deployments without the
332
- // durable recovery inbox.
217
+ }
218
+ // A deployment without the durable recovery inbox applies the envelope
219
+ // unjournaled.
333
220
  for (let attempt = 0; attempt < 2; attempt += 1) {
334
221
  try {
335
- await this.processFinalizationEnvelope(envelope, contextGraphId, sourcePeerId);
222
+ await this.processUnjournaledFinalization(liveAdmission.input);
336
223
  return;
337
224
  }
338
225
  catch (error) {
@@ -350,13 +237,9 @@ export class FinalizationHandler {
350
237
  }
351
238
  }
352
239
  }
353
- decodeFinalizationEnvelope(rawMessage) {
240
+ decodeFinalizationMessageOrWarn(rawMessage) {
354
241
  try {
355
- const msg = decodeFinalizationMessage(rawMessage);
356
- return {
357
- rawMessage,
358
- msg,
359
- };
242
+ return decodeFinalizationMessage(rawMessage);
360
243
  }
361
244
  catch (error) {
362
245
  const message = error instanceof Error ? error.message : String(error);
@@ -443,276 +326,14 @@ export class FinalizationHandler {
443
326
  return undefined;
444
327
  }
445
328
  }
446
- async processFinalizationEnvelope(envelope, contextGraphId, sourcePeerId) {
447
- let ctx = createOperationContext('gossip');
448
- let resolvedTargetContextGraphId;
449
- const { rawMessage, msg, graphAdmission } = envelope;
329
+ /** Apply a graph-scoped envelope on a deployment without the durable recovery inbox. */
330
+ async processUnjournaledFinalization(input) {
331
+ const { msg } = input.candidate;
332
+ const ctx = msg.operationId
333
+ ? createOperationContext('gossip', msg.operationId)
334
+ : createOperationContext('gossip');
450
335
  try {
451
- resolvedTargetContextGraphId = msg.targetContextGraphId || undefined;
452
- if (msg.operationId) {
453
- ctx = createOperationContext('gossip', msg.operationId);
454
- }
455
- const isGraphScoped = msg.contentScopeVersion === GRAPH_KA_CONTENT_SCOPE_VERSION;
456
- if (isGraphScoped) {
457
- if (!graphAdmission?.ok) {
458
- this.log.warn(ctx, `Finalization: invalid graph-scoped envelope for ${msg.ual || '(missing UAL)'}: `
459
- + `${graphAdmission?.reason ?? 'decode-failed'}`);
460
- return 'deferred';
461
- }
462
- return await this.recovery.processUnjournaled({
463
- rawMessage,
464
- contextGraphId,
465
- ...(sourcePeerId ? { sourcePeerId } : {}),
466
- candidate: graphAdmission.value,
467
- });
468
- }
469
- if (msg.contextGraphId && msg.contextGraphId !== contextGraphId) {
470
- // #1100: same guard as GossipPublishHandler — frames of other gossip
471
- // message types decode "successfully" with garbage in this field, so
472
- // only WARN when the mismatched value is a plausible CG id.
473
- if (!validateContextGraphId(msg.contextGraphId).valid)
474
- return 'deferred';
475
- this.log.warn(ctx, `Finalization: contextGraphId "${msg.contextGraphId.slice(0, 120)}" does not match topic "${contextGraphId}", ignoring`);
476
- return 'deferred';
477
- }
478
- // Deduplicate: skip if we already successfully processed this UAL
479
- const dedupeKey = `${msg.ual}:${msg.txHash}`;
480
- if (this.processedUals.has(dedupeKey)) {
481
- this.log.info(ctx, `Finalization: already processed ${msg.ual}, skipping duplicate`);
482
- return 'already-confirmed';
483
- }
484
- if (msg.contentScopeVersion !== undefined
485
- && msg.contentScopeVersion !== 0) {
486
- this.log.warn(ctx, `Finalization: unsupported content scope version ${msg.contentScopeVersion}, ignoring`);
487
- return 'deferred';
488
- }
489
- if (!msg.ual || !msg.txHash || msg.rootEntities.length === 0) {
490
- this.log.warn(ctx, `Finalization: incomplete message (ual=${msg.ual}, txHash=${msg.txHash}, roots=${msg.rootEntities.length}, scope=${msg.contentScopeVersion ?? 0}), ignoring`);
491
- return 'deferred';
492
- }
493
- const blockNumber = protobufScalarToNumber(msg.blockNumber);
494
- const startKAId = protobufScalarToBigInt(msg.startKAId);
495
- const endKAId = protobufScalarToBigInt(msg.endKAId);
496
- let batchIdForResolve = 0n;
497
- try {
498
- batchIdForResolve = protobufScalarToBigInt(msg.batchId);
499
- }
500
- catch {
501
- batchIdForResolve = 0n;
502
- }
503
- const ctxGraphId = await this.resolveFinalizationContextGraphId(contextGraphId, msg.targetContextGraphId || undefined, batchIdForResolve, ctx);
504
- resolvedTargetContextGraphId = ctxGraphId;
505
- // Validate sub-graph name from gossip — reject invalid names entirely
506
- let subGraphName;
507
- if (msg.subGraphName) {
508
- const sgVal = validateSubGraphName(msg.subGraphName);
509
- if (sgVal.valid) {
510
- subGraphName = msg.subGraphName;
511
- }
512
- else {
513
- this.log.warn(ctx, `Finalization: rejected message with invalid subGraphName "${msg.subGraphName}": ${sgVal.reason}`);
514
- return 'deferred';
515
- }
516
- }
517
- // Dedup guard: skip if this batch was already promoted (e.g. by ChainEventPoller).
518
- // Read-both (review F5): also ASK the label `_meta` — the minimal
519
- // per-cgId partition shape carries no `dkg:status` row.
520
- const targetMetaGraph = ctxGraphId
521
- ? contextGraphMetaUri(contextGraphId, ctxGraphId)
522
- : `did:dkg:context-graph:${contextGraphId}/_meta`;
523
- const alreadyPromoted = await this.isAlreadyConfirmed(msg.ual, targetMetaGraph, `did:dkg:context-graph:${contextGraphId}/_meta`);
524
- if (alreadyPromoted) {
525
- this.markProcessed(dedupeKey);
526
- this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_already_confirmed', {
527
- ...msg,
528
- targetContextGraphId: ctxGraphId ?? msg.targetContextGraphId,
529
- }));
530
- this.log.info(ctx, `Finalization: ${msg.ual} already confirmed in ${ctxGraphId ? `context graph ${ctxGraphId}` : 'context graph'}, skipping`);
531
- return 'already-confirmed';
532
- }
533
- // #1549: read this KA's per-author SWM under-graphs first, widening to today's
534
- // unbounded read on empty-or-mismatch. All of the bound/widen policy — and the
535
- // reasoning for why it is safe — lives in storage's
536
- // `loadSharedMemorySliceWithKaBoundFallback`, which owns the widen.
537
- const { quads: sharedMemoryQuads, matched: merkleMatchedQuads } = await this.loadFinalizationSwmSlice(contextGraphId, msg.rootEntities, subGraphName, swmKaBoundDisabled() ? undefined : deriveSwmKaGraphBound(startKAId, endKAId), msg.kcMerkleRoot, async () => {
538
- const privateRoots = await this.getPrivateRootsFromMeta(contextGraphId, msg.rootEntities, subGraphName);
539
- const allowGeneratedCatalogFloor = await this.allowsGeneratedCatalogFloor(contextGraphId, ctxGraphId);
540
- return (quads) => this.sharedMemoryQuadsMatchingMerkle(contextGraphId, quads, privateRoots, msg.kcMerkleRoot, allowGeneratedCatalogFloor);
541
- });
542
- if (sharedMemoryQuads.length > 0) {
543
- if (merkleMatchedQuads) {
544
- const batchId = protobufScalarToBigInt(msg.batchId);
545
- // PR #845 review #9: derive `txIndex` from the verified receipt
546
- // (via `verifyOnChain`), NOT from gossip-supplied `msg.txIndex`.
547
- // The latter is trust-based; a peer can forge an inflated index
548
- // for a real publish `txHash` and lock out a legitimate
549
- // same-block update on the receiver. The verified value comes
550
- // from the on-chain log we matched (`log.transactionIndex`).
551
- const { verified, authorAddress, txIndex: verifiedTxIndex } = await this.verifyOnChain(msg.txHash, blockNumber, msg.kcMerkleRoot, msg.publisherAddress, startKAId, endKAId, ctx, ctxGraphId, batchId);
552
- if (verified) {
553
- // Codex r5b — drop the rolling-upgrade legacy-publisher
554
- // fallback. Earlier rounds inferred same-graph intent from
555
- // `targetContextGraphId === local-on-chain-id-for(contextGraphId)`,
556
- // but Codex r5b correctly observed that signal is ambiguous:
557
- // it ALSO matches an explicit-remap-to-self publish (one where
558
- // the legacy publisher passed `subContextGraphId === ownCG's
559
- // own on-chain id` to deliberately drop the root copy). Both
560
- // shapes hit `targetContextGraphId === local id` on the wire,
561
- // so the fallback would re-add a root copy that the publisher
562
- // had intentionally removed — a data-isolation regression.
563
- //
564
- // The cure is worse than the disease: trading a hard
565
- // data-isolation bug for a soft query-discoverability gap is
566
- // unacceptable. Without an unambiguous version/intent signal
567
- // on the wire, a legacy publisher's same-graph publish stays
568
- // queryable on receivers via per-cgId partitions but not via
569
- // the bare `<cg>` label until the publisher upgrades to a
570
- // tristate-emitting build and re-emits. New publishers always
571
- // set the tristate (encoded with explicit KEEP/DROP) so the
572
- // gap is bounded by the upgrade window. PR #779 has not
573
- // shipped to any production peer yet, so this is the right
574
- // moment to harden the contract.
575
- const requestedKeepRootCopyOnLabel = msg.keepRootCopyOnLabel === true;
576
- // PR #845 review #9: tiebreaker comes from chain-truth.
577
- // verifyOnChain may not yield a txIndex if the matched event
578
- // shape didn't carry it (e.g. mocks). Fall back to 0 in that
579
- // case — matches pre-#845 ordering.
580
- const finalizationVersion = {
581
- blockNumber,
582
- txIndex: typeof verifiedTxIndex === 'number' ? verifiedTxIndex : 0,
583
- };
584
- // PR #845 review #10: when same-graph dual-write is requested,
585
- // BOTH the per-cgId target meta and the root label meta
586
- // (`<cg>/_meta`) get rewritten. The pre-#845 code only guarded
587
- // the per-cgId target, so a stale finalization could pass that
588
- // check while an update had already stamped a newer version in
589
- // the root label meta — the dual-write then re-inserted the
590
- // old root-label data + meta on top of the update. Acquire the
591
- // label-meta lock too (when dual-writing), and downgrade to
592
- // per-cgId-only if the label projection is newer.
593
- const isDualWrite = requestedKeepRootCopyOnLabel
594
- && !!ctxGraphId
595
- && !subGraphName;
596
- const defaultMeta = `did:dkg:context-graph:${contextGraphId}/_meta`;
597
- // PR #845 review #7: TOCTOU — serialise check + promotion +
598
- // version stamp under the per-KA materialization lock so a
599
- // concurrent stale writer cannot interleave between our
600
- // `shouldApplyMaterialization` and `writeMaterializedVersion`.
601
- const outcome = await this.applyVerifiedFinalization({
602
- contextGraphId,
603
- sharedMemoryQuads: merkleMatchedQuads,
604
- ual: msg.ual,
605
- rootEntities: msg.rootEntities,
606
- publisherAddress: msg.publisherAddress,
607
- txHash: msg.txHash,
608
- blockNumber,
609
- startKAId,
610
- endKAId,
611
- batchId: protobufScalarToBigInt(msg.batchId),
612
- ctxGraphId,
613
- subGraphName,
614
- authorAddress,
615
- finalizationVersion,
616
- targetMetaGraph,
617
- defaultMeta,
618
- isDualWrite,
619
- ctx,
620
- });
621
- if (outcome === 'stale-target') {
622
- this.markProcessed(dedupeKey);
623
- this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_stale_target', {
624
- ...msg,
625
- targetContextGraphId: ctxGraphId ?? msg.targetContextGraphId,
626
- rootEntityCount: msg.rootEntities.length,
627
- swmStatementCount: merkleMatchedQuads.length,
628
- subGraphName,
629
- blockNumber,
630
- batchId,
631
- outcome,
632
- reason: 'newer update already materialized',
633
- }));
634
- this.log.info(ctx, `Finalization: a newer update is already materialised for ${msg.ual}, skipping stale publish promotion`);
635
- return 'already-confirmed';
636
- }
637
- this.markProcessed(dedupeKey);
638
- this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_applied', {
639
- ...msg,
640
- targetContextGraphId: ctxGraphId ?? msg.targetContextGraphId,
641
- rootEntityCount: msg.rootEntities.length,
642
- swmStatementCount: merkleMatchedQuads.length,
643
- subGraphName,
644
- blockNumber,
645
- batchId,
646
- outcome,
647
- retryable: false,
648
- }));
649
- this.log.info(ctx, `Finalization: promoted SWM snapshot to ${ctxGraphId ? `context graph ${ctxGraphId}` : 'canonical'} for ${msg.ual} (tx=${msg.txHash.slice(0, 10)}…)`);
650
- return 'applied';
651
- }
652
- this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_verification_failed', {
653
- ...msg,
654
- targetContextGraphId: ctxGraphId ?? msg.targetContextGraphId,
655
- rootEntityCount: msg.rootEntities.length,
656
- swmStatementCount: merkleMatchedQuads.length,
657
- subGraphName,
658
- blockNumber,
659
- batchId,
660
- outcome: 'deferred',
661
- retryable: true,
662
- reason: 'on-chain verification failed',
663
- level: 'warn',
664
- }));
665
- this.log.info(ctx, `Finalization: on-chain verification failed for ${msg.ual}, will retry via ChainEventPoller`);
666
- return 'deferred';
667
- }
668
- this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_merkle_mismatch', {
669
- ...msg,
670
- targetContextGraphId: ctxGraphId ?? msg.targetContextGraphId,
671
- rootEntityCount: msg.rootEntities.length,
672
- swmStatementCount: sharedMemoryQuads.length,
673
- subGraphName,
674
- blockNumber,
675
- batchId: protobufScalarToBigInt(msg.batchId),
676
- outcome: 'deferred',
677
- retryable: true,
678
- reason: 'shared memory merkle root mismatch',
679
- level: 'warn',
680
- }));
681
- this.log.info(ctx, `Finalization: merkle mismatch for ${msg.ual}, shared memory data differs from published`);
682
- }
683
- else {
684
- this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_no_data', {
685
- ...msg,
686
- targetContextGraphId: ctxGraphId ?? msg.targetContextGraphId,
687
- rootEntityCount: msg.rootEntities.length,
688
- swmStatementCount: 0,
689
- subGraphName,
690
- blockNumber,
691
- batchId: protobufScalarToBigInt(msg.batchId),
692
- outcome: 'deferred',
693
- retryable: true,
694
- reason: 'no shared memory data',
695
- level: 'warn',
696
- }));
697
- this.log.info(ctx, `Finalization: no shared memory data for ${msg.ual}, peer missed SWM sharing`);
698
- }
699
- // Fallback: no matching shared memory data. The data will arrive via
700
- // the regular publish topic broadcast or ChainEventPoller sync.
701
- this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_payload_sync_required', {
702
- ...msg,
703
- targetContextGraphId: ctxGraphId ?? msg.targetContextGraphId,
704
- rootEntityCount: msg.rootEntities.length,
705
- swmStatementCount: sharedMemoryQuads.length,
706
- subGraphName,
707
- blockNumber,
708
- batchId: protobufScalarToBigInt(msg.batchId),
709
- outcome: 'deferred',
710
- retryable: true,
711
- reason: 'no matching SWM snapshot',
712
- level: 'warn',
713
- }));
714
- this.log.info(ctx, `Finalization: ${msg.ual} requires full payload sync (no matching SWM snapshot)`);
715
- return 'deferred';
336
+ return await this.recovery.processUnjournaled(input);
716
337
  }
717
338
  catch (err) {
718
339
  if (err instanceof StoreSchedulerBusyError)
@@ -720,8 +341,7 @@ export class FinalizationHandler {
720
341
  const errMsg = err instanceof Error ? err.message : String(err);
721
342
  this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_failed', {
722
343
  ...msg,
723
- contextGraphId: msg.contextGraphId || contextGraphId,
724
- targetContextGraphId: resolvedTargetContextGraphId ?? msg.targetContextGraphId,
344
+ contextGraphId: msg.contextGraphId || input.contextGraphId,
725
345
  rootEntityCount: msg.rootEntities.length,
726
346
  outcome: 'failed',
727
347
  retryable: true,
@@ -732,6 +352,36 @@ export class FinalizationHandler {
732
352
  return 'deferred';
733
353
  }
734
354
  }
355
+ /**
356
+ * Only graph-scoped finalization is materialized. A message without that
357
+ * scope names root entities instead of the KA's own graph, so this node
358
+ * holds no exact copy to verify it against. Its KA reaches Verified Memory
359
+ * through chain reconcile, which fetches it from peers.
360
+ */
361
+ ignoreUnscopedFinalization(data, contextGraphId) {
362
+ const msg = this.decodeFinalizationMessageOrWarn(data);
363
+ // Frames of other gossip message types decode "successfully" with garbage
364
+ // fields (#1100), so only report what plausibly is a finalization.
365
+ if (!msg
366
+ || !msg.ual
367
+ || !msg.txHash
368
+ || (msg.contextGraphId && !validateContextGraphId(msg.contextGraphId).valid)) {
369
+ return;
370
+ }
371
+ const ctx = msg.operationId
372
+ ? createOperationContext('gossip', msg.operationId)
373
+ : createOperationContext('gossip');
374
+ const reason = `content scope ${msg.contentScopeVersion ?? 0} is not graph-scoped`;
375
+ this.lifecycle.record(ctx, finalizationLifecycleDecision('finalization_unsupported_scope', {
376
+ ...msg,
377
+ contextGraphId: msg.contextGraphId || contextGraphId,
378
+ rootEntityCount: msg.rootEntities.length,
379
+ outcome: 'ignored',
380
+ retryable: false,
381
+ reason,
382
+ }));
383
+ this.log.info(ctx, `Finalization: ignoring ${msg.ual}: ${reason}`);
384
+ }
735
385
  /** Resolve and verify the exact RDF state that a graph-scoped command may apply. */
736
386
  async prepareGraphScopedMaterialization(input) {
737
387
  const { candidate: parsed, contextGraphId, sourcePeerId } = input;
@@ -1017,8 +667,14 @@ export class FinalizationHandler {
1017
667
  if (resolution.status === 'absent')
1018
668
  return undefined;
1019
669
  if (resolution.status === 'invalid') {
1020
- this.log.warn(ctx, `Chain-reconcile: confirmed graph-scoped VM is invalid for ${input.ual} `
1021
- + `(${resolution.reason})`);
670
+ if (resolution.reason === 'not-current') {
671
+ // An intact copy of an earlier version: the caller fetches the current one.
672
+ this.log.info(ctx, `Chain-reconcile: confirmed graph-scoped VM for ${input.ual} is not the current version`);
673
+ }
674
+ else {
675
+ this.log.warn(ctx, `Chain-reconcile: confirmed graph-scoped VM is invalid for ${input.ual} `
676
+ + `(${resolution.reason})`);
677
+ }
1022
678
  return 'no-swm';
1023
679
  }
1024
680
  await this.advanceExactGraphScopedVersion({
@@ -1124,14 +780,13 @@ export class FinalizationHandler {
1124
780
  }
1125
781
  /**
1126
782
  * Resolve and promote the exact graph-scoped SWM assertion for a chain-known
1127
- * KA. `undefined` means no V2 head exists and the caller may try the legacy
1128
- * root-operation recovery path; every other result is authoritative for V2.
783
+ * KA. `undefined` means no V2 head exists and the caller answers `no-swm`;
784
+ * every other result is authoritative for V2.
1129
785
  */
1130
786
  async reconcileGraphScopedKC(input, ctx) {
1131
787
  const { contextGraphId, onChainCgId, ual, assertionVersion, merkleRoot, publisherAddress, kaId, batchId, versionBlock, authorAddress, versionSnapshot, signal, subGraphName, trustedAssertionEvidence, } = input;
1132
- // Historical UAL shapes can be valid inputs to the legacy root-scoped
1133
- // recovery code but cannot name a V2 per-KA graph. Do not let the strict
1134
- // V2 parser turn those into a terminal "corrupt head" result.
788
+ // Historical UAL shapes cannot name a V2 per-KA graph. Do not let the
789
+ // strict V2 parser turn those into a terminal "corrupt head" result.
1135
790
  try {
1136
791
  createGraphKnowledgeAssetScope(ual, 1);
1137
792
  }
@@ -1160,8 +815,7 @@ export class FinalizationHandler {
1160
815
  // post-fetch check runs. Re-read the immutable confirmed envelope and
1161
816
  // verify the exact VM graph against current chain truth. This remains
1162
817
  // fail-closed: absent, invalid, stale, or root-mismatched VM state is
1163
- // still reported as no-swm, and the legacy all-workspace scan stays
1164
- // disabled for exact fetch callers.
818
+ // still reported as no-swm.
1165
819
  return (await this.reconcileConfirmedGraphScopedVmWithoutWorkspaceHead({
1166
820
  contextGraphId,
1167
821
  ual,
@@ -2044,353 +1698,6 @@ export class FinalizationHandler {
2044
1698
  return false;
2045
1699
  }
2046
1700
  }
2047
- finalizationSwmBucketUri(contextGraphId, subGraphName) {
2048
- return subGraphName
2049
- ? new GraphManager(this.store).sharedMemoryUri(contextGraphId, subGraphName)
2050
- : contextGraphWorkspaceGraphUri(contextGraphId);
2051
- }
2052
- /**
2053
- * Read the finalization SWM slice, preferring this KA's per-author under-graphs
2054
- * and widening to the complete read on empty-or-mismatch (#1549). The widen — and
2055
- * the reasoning for why the bound is a safe pure accelerator (INV-1 is refuted
2056
- * under root recurrence, so the bounded read may miss and must widen before the
2057
- * caller records anything) — lives in storage's
2058
- * `loadSharedMemorySliceWithKaBoundFallback`. This method only resolves the bucket
2059
- * URI and the accept predicate; it is a thin finalization-specific adapter.
2060
- *
2061
- * #1098/#1099: replicas store gossiped SWM shares in the PER-KA graphs
2062
- * `…/_shared_memory/{author}/{number}`, not the bare bucket, so the read must span
2063
- * bucket + per-KA graphs or a replica reports "no shared memory data" and never
2064
- * materialises the KA into VM.
2065
- */
2066
- async loadFinalizationSwmSlice(contextGraphId, rootEntities, subGraphName, kaGraphBound, expectedMerkleRoot, createAccept) {
2067
- const safeRoots = rootEntities.filter(isSafeIri);
2068
- if (safeRoots.length === 0)
2069
- return { quads: [], matched: null };
2070
- const writeRevision = this.graphWriteGen?.getWriteRevision(`${contextGraphDataUri(contextGraphId)}/`);
2071
- const key = [
2072
- 'finalization',
2073
- contextGraphId,
2074
- subGraphName ?? '',
2075
- safeRoots.slice().sort().join('\u0001'),
2076
- kaGraphBound ? `${kaGraphBound.agentAddress}:${kaGraphBound.startNumber}:${kaGraphBound.endNumber}` : '*',
2077
- ethers.hexlify(expectedMerkleRoot),
2078
- writeRevision
2079
- ? `${writeRevision.generation}:${writeRevision.stable ? 'stable' : 'unstable'}`
2080
- : 'unknown',
2081
- ].join('\u0000');
2082
- return this.runScanSingleFlight(key, async () => {
2083
- const { quads, accepted } = await loadSharedMemorySliceWithKaBoundFallback(this.store, this.finalizationSwmBucketUri(contextGraphId, subGraphName), { rootEntities: safeRoots }, kaGraphBound, {
2084
- sources: {
2085
- bounded: SWM_SLICE_SOURCE_BOUNDED,
2086
- widened: SWM_SLICE_SOURCE_WIDENED,
2087
- unbounded: SWM_SLICE_SOURCE,
2088
- },
2089
- createAccept,
2090
- queryOptions: { priority: 'background' },
2091
- resultBudget: finalizationSwmResultBudget(),
2092
- });
2093
- return { quads, matched: accepted };
2094
- });
2095
- }
2096
- /** Complete (unbounded) SWM read for the chain-reconcile backstop. */
2097
- async getSharedMemoryQuadsForRoots(contextGraphId, rootEntities, subGraphName) {
2098
- const safeRoots = rootEntities.filter(isSafeIri);
2099
- if (safeRoots.length === 0)
2100
- return [];
2101
- return loadSelectedSharedMemoryQuads(this.store, this.finalizationSwmBucketUri(contextGraphId, subGraphName), { rootEntities: safeRoots }, {
2102
- querySource: SWM_SLICE_SOURCE,
2103
- queryOptions: { priority: 'background' },
2104
- resultBudget: finalizationSwmResultBudget(),
2105
- });
2106
- }
2107
- runScanSingleFlight(key, work) {
2108
- const scope = key.startsWith('finalization\u0000') ? 'finalization' : 'reconcile';
2109
- const existing = this.scanSingleFlights.get(key);
2110
- if (existing) {
2111
- getMetrics().storeScanSingleFlightJoinsTotal.add(1, { scope });
2112
- return existing;
2113
- }
2114
- getMetrics().storeScanSingleFlightActive.add(1, { scope });
2115
- const running = work().finally(() => {
2116
- if (this.scanSingleFlights.get(key) === running)
2117
- this.scanSingleFlights.delete(key);
2118
- getMetrics().storeScanSingleFlightActive.add(-1, { scope });
2119
- });
2120
- this.scanSingleFlights.set(key, running);
2121
- return running;
2122
- }
2123
- verifyMerkleMatch(sharedMemoryQuads, privateRoots, expectedMerkleRoot) {
2124
- const computedRoot = computeFlatKCRoot(sharedMemoryQuads, privateRoots);
2125
- return ethers.hexlify(computedRoot) === ethers.hexlify(expectedMerkleRoot);
2126
- }
2127
- sharedMemoryQuadsMatchingMerkle(contextGraphId, sharedMemoryQuads, privateRoots, expectedMerkleRoot, allowGeneratedCatalogFloor) {
2128
- if (this.verifyMerkleMatch(sharedMemoryQuads, privateRoots, expectedMerkleRoot)) {
2129
- return sharedMemoryQuads;
2130
- }
2131
- if (!allowGeneratedCatalogFloor)
2132
- return null;
2133
- const withGeneratedCatalog = [
2134
- ...sharedMemoryQuads,
2135
- ...generatedPrivateCatalogFloorQuads(contextGraphId),
2136
- ];
2137
- if (this.verifyMerkleMatch(withGeneratedCatalog, privateRoots, expectedMerkleRoot)) {
2138
- return withGeneratedCatalog;
2139
- }
2140
- return null;
2141
- }
2142
- async storedOnChainContextGraphId(contextGraphId) {
2143
- const result = await this.store.query(contextGraphOnChainIdBindingQuery(contextGraphId), { source: 'agent.finalization.contextGraphOnChainId' });
2144
- if (result.type !== 'bindings' || result.bindings.length === 0)
2145
- return undefined;
2146
- return stripOptionalLiteral(result.bindings[0]?.['id'])?.trim();
2147
- }
2148
- async onChainContextGraphMatchesLocalId(contextGraphId, onChainCgId) {
2149
- if (onChainCgId === undefined || onChainCgId === null)
2150
- return false;
2151
- const normalizedOnChainId = String(onChainCgId).trim();
2152
- const normalizedContextGraphId = contextGraphId.trim();
2153
- if (/^\d+$/.test(normalizedContextGraphId) && normalizedContextGraphId === normalizedOnChainId)
2154
- return true;
2155
- const liveNameHashMatches = async () => {
2156
- if (typeof this.chain?.getContextGraphNameHash !== 'function')
2157
- return false;
2158
- try {
2159
- const nameHash = await this.chain.getContextGraphNameHash(BigInt(normalizedOnChainId));
2160
- return typeof nameHash === 'string' &&
2161
- nameHash.toLowerCase() === ethers.keccak256(ethers.toUtf8Bytes(normalizedContextGraphId)).toLowerCase();
2162
- }
2163
- catch {
2164
- return false;
2165
- }
2166
- };
2167
- let resolvedOnChainId;
2168
- try {
2169
- resolvedOnChainId = await this.resolveContextGraphOnChainId?.(contextGraphId);
2170
- }
2171
- catch {
2172
- resolvedOnChainId = undefined;
2173
- }
2174
- if (sameBigIntLiteral(resolvedOnChainId, normalizedOnChainId)) {
2175
- return typeof this.chain?.getContextGraphNameHash === 'function'
2176
- ? liveNameHashMatches()
2177
- : true;
2178
- }
2179
- const storedOnChainId = await this.storedOnChainContextGraphId(contextGraphId);
2180
- if (sameBigIntLiteral(storedOnChainId, normalizedOnChainId)) {
2181
- return typeof this.chain?.getContextGraphNameHash === 'function'
2182
- ? liveNameHashMatches()
2183
- : true;
2184
- }
2185
- return liveNameHashMatches();
2186
- }
2187
- async allowsGeneratedCatalogFloor(contextGraphId, onChainCgId) {
2188
- if (onChainCgId === undefined || onChainCgId === null)
2189
- return false;
2190
- if (!this.chain || this.chain.chainId === 'none')
2191
- return false;
2192
- const normalizedContextGraphId = contextGraphId.trim();
2193
- const normalizedOnChainId = String(onChainCgId).trim();
2194
- const readFinalizedCreation = this.chain.getContextGraphFinalizedCreation;
2195
- if (typeof readFinalizedCreation === 'function') {
2196
- try {
2197
- const creation = await readFinalizedCreation.call(this.chain, BigInt(normalizedOnChainId));
2198
- if (creation !== undefined) {
2199
- const idMatches = /^\d+$/.test(normalizedContextGraphId)
2200
- ? normalizedContextGraphId === normalizedOnChainId
2201
- : creation.nameHash.toLowerCase() === ethers.keccak256(ethers.toUtf8Bytes(normalizedContextGraphId)).toLowerCase();
2202
- return idMatches && creation.accessPolicy === 1;
2203
- }
2204
- }
2205
- catch {
2206
- // Never mix a partial/failing finalized creation proof with a latest
2207
- // point read: that can splice two forks into a false-private result.
2208
- return false;
2209
- }
2210
- }
2211
- if (typeof this.chain.getContextGraphAccessPolicy !== 'function')
2212
- return false;
2213
- if (!await this.onChainContextGraphMatchesLocalId(contextGraphId, onChainCgId))
2214
- return false;
2215
- try {
2216
- return Number(await this.chain.getContextGraphAccessPolicy(BigInt(onChainCgId))) === 1;
2217
- }
2218
- catch {
2219
- return false;
2220
- }
2221
- }
2222
- async getPrivateRootsFromMeta(contextGraphId, rootEntities, subGraphName) {
2223
- const graphManager = new GraphManager(this.store);
2224
- const wsMetaGraph = subGraphName
2225
- ? graphManager.sharedMemoryMetaUri(contextGraphId, subGraphName)
2226
- : contextGraphWorkspaceMetaGraphUri(contextGraphId);
2227
- const safeRoots = rootEntities.filter(isSafeIri);
2228
- if (safeRoots.length === 0)
2229
- return [];
2230
- const values = safeRoots.map(r => `<${r}>`).join(' ');
2231
- const sparql = `SELECT ?entity ?root WHERE {
2232
- GRAPH <${wsMetaGraph}> {
2233
- VALUES ?entity { ${values} }
2234
- ?entity <${DKG_NS}privateMerkleRoot> ?root .
2235
- }
2236
- }`;
2237
- const roots = [];
2238
- try {
2239
- const result = await this.store.query(sparql, { source: 'agent.finalization.privateRoots' });
2240
- if (result.type === 'bindings') {
2241
- for (const row of result.bindings) {
2242
- const hex = row['root'].replace(/^"(.*)".*$/, '$1').replace(/^0x/, '');
2243
- if (hex.length === 64) {
2244
- const bytes = new Uint8Array(32);
2245
- for (let i = 0; i < 32; i++)
2246
- bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
2247
- roots.push(bytes);
2248
- }
2249
- }
2250
- }
2251
- }
2252
- catch { /* metadata may not exist */ }
2253
- return roots;
2254
- }
2255
- /**
2256
- * Recover the publisher's `keepRootCopyOnLabel` decision for these roots from
2257
- * SWM workspace meta. The publisher persists `<root> dkg:keepRootCopyOnLabel
2258
- * "true"|"false"` at publish time — the durable equivalent of the gossip
2259
- * envelope flag — and it replicates to subscribers alongside the per-root
2260
- * `privateMerkleRoot`. Returns:
2261
- * - `true` — a matched root explicitly kept the root-label copy,
2262
- * - `false` — explicitly dropped (remap / explicit-subCG publish),
2263
- * - `undefined` — no signal persisted (legacy publish); the caller defaults
2264
- * to per-cgId-only so a dropped root copy is never re-added.
2265
- * An explicit `true` wins over `false` across the matched roots: a same-graph
2266
- * publish demands the root copy exist.
2267
- */
2268
- async getKeepRootCopySignal(contextGraphId, rootEntities, subGraphName) {
2269
- const graphManager = new GraphManager(this.store);
2270
- const wsMetaGraph = subGraphName
2271
- ? graphManager.sharedMemoryMetaUri(contextGraphId, subGraphName)
2272
- : contextGraphWorkspaceMetaGraphUri(contextGraphId);
2273
- const safeRoots = rootEntities.filter(isSafeIri);
2274
- if (safeRoots.length === 0)
2275
- return undefined;
2276
- const values = safeRoots.map(r => `<${r}>`).join(' ');
2277
- const sparql = `SELECT ?v WHERE {
2278
- GRAPH <${assertSafeIri(wsMetaGraph)}> {
2279
- VALUES ?root { ${values} }
2280
- ?root <${KEEP_ROOT_COPY_PREDICATE}> ?v .
2281
- }
2282
- }`;
2283
- try {
2284
- const result = await this.store.query(sparql, { source: 'agent.finalization.keepRootCopySignal' });
2285
- if (result.type !== 'bindings' || result.bindings.length === 0)
2286
- return undefined;
2287
- let sawFalse = false;
2288
- for (const row of result.bindings) {
2289
- const v = String(row['v']).replace(/^"(.*)".*$/, '$1');
2290
- if (v === 'true')
2291
- return true;
2292
- if (v === 'false')
2293
- sawFalse = true;
2294
- }
2295
- return sawFalse ? false : undefined;
2296
- }
2297
- catch {
2298
- return undefined;
2299
- }
2300
- }
2301
- async getPublisherPeerIdFromMeta(contextGraphId, rootEntities, subGraphName) {
2302
- const graphManager = new GraphManager(this.store);
2303
- const wsMetaGraph = subGraphName
2304
- ? graphManager.sharedMemoryMetaUri(contextGraphId, subGraphName)
2305
- : contextGraphWorkspaceMetaGraphUri(contextGraphId);
2306
- const safeRoots = rootEntities.filter(isSafeIri);
2307
- if (safeRoots.length === 0)
2308
- return undefined;
2309
- const values = safeRoots.map(r => `<${r}>`).join(' ');
2310
- const PROV = 'http://www.w3.org/ns/prov#';
2311
- // GH #748: prefer the dedicated `dkg:publisherPeerId` field (peer-ID
2312
- // literal); fall back to literal-form `prov:wasAttributedTo` for legacy
2313
- // un-migrated SWM rows. Skip URI form — that's an agent DID, not a
2314
- // peer ID, and downstream dials a libp2p peer with this value.
2315
- //
2316
- // `FILTER(BOUND(?peerId))` guards the LIMIT 1: without it, an op with
2317
- // `rootEntity` but neither peer-ID source produces an unbound `?peerId`
2318
- // that LIMIT could pick. The caller's `wsPeerId || publisherAddress`
2319
- // fallback would then store an EVM address where a libp2p peer ID is
2320
- // expected. With BOUND, only ops carrying a real peer-ID match.
2321
- const sparql = `SELECT ?peerId WHERE {
2322
- GRAPH <${wsMetaGraph}> {
2323
- VALUES ?root { ${values} }
2324
- ?op <${DKG_NS}rootEntity> ?root .
2325
- OPTIONAL { ?op <${DKG_NS}publisherPeerId> ?pidField }
2326
- OPTIONAL { ?op <${PROV}wasAttributedTo> ?attrField . FILTER(isLiteral(?attrField)) }
2327
- BIND(COALESCE(?pidField, ?attrField) AS ?peerId)
2328
- FILTER(BOUND(?peerId))
2329
- }
2330
- } LIMIT 1`;
2331
- try {
2332
- const result = await this.store.query(sparql, { source: 'agent.finalization.publisherPeerId' });
2333
- if (result.type === 'bindings' && result.bindings.length > 0) {
2334
- const raw = result.bindings[0]['peerId'];
2335
- const peerId = raw.replace(/^"(.*)".*$/, '$1');
2336
- if (peerId && peerId !== 'unknown')
2337
- return peerId;
2338
- }
2339
- }
2340
- catch { /* shared memory metadata may not exist */ }
2341
- return undefined;
2342
- }
2343
- /**
2344
- * Shared SWM→VM promotion under the per-KA materialization lock(s).
2345
- *
2346
- * Extracted verbatim from the former `promoteUnderLocks`/`runUnderLocks`
2347
- * inline closure in `handleFinalizationMessage` (PR #845's TOCTOU-safe
2348
- * promotion) so BOTH the gossip path and the chain-driven reconciliation
2349
- * path (`handleChainReconciledKC`) share one implementation. Behavior is
2350
- * identical to the gossip path; the only change is that the captured locals
2351
- * are now explicit params.
2352
- *
2353
- * Serialises check + promotion + version stamp under the per-KA lock so a
2354
- * concurrent stale writer cannot interleave between `shouldApplyMaterialization`
2355
- * and `writeMaterializedVersion`. When dual-writing (same-graph keep-root),
2356
- * both the per-cgId target meta and the root-label meta are guarded; if the
2357
- * root label has a newer projection (an applied update), the dual-write
2358
- * portion is skipped so we don't clobber it.
2359
- */
2360
- async applyVerifiedFinalization(input) {
2361
- const { contextGraphId, sharedMemoryQuads, ual, rootEntities, publisherAddress, txHash, blockNumber, startKAId, endKAId, batchId, ctxGraphId, subGraphName, authorAddress, finalizationVersion, targetMetaGraph, defaultMeta, isDualWrite, ctx, } = input;
2362
- const promoteUnderLocks = async () => {
2363
- if (!(await shouldApplyMaterialization(this.store, targetMetaGraph, ual, finalizationVersion))) {
2364
- return 'stale-target';
2365
- }
2366
- let effectiveKeepRoot = isDualWrite;
2367
- if (isDualWrite) {
2368
- if (!(await shouldApplyMaterialization(this.store, defaultMeta, ual, finalizationVersion))) {
2369
- // Per-cgId is stale-or-equal but ROOT label has a
2370
- // newer projection (an applied update). Skip the
2371
- // dual-write portion so we don't clobber it.
2372
- effectiveKeepRoot = false;
2373
- this.log.info(ctx, `Finalization: root-label projection is newer for ${ual}; downgrading to per-cgId-only promotion`);
2374
- }
2375
- }
2376
- await this.promoteSharedMemoryToCanonical(contextGraphId, sharedMemoryQuads, ual, rootEntities, publisherAddress, txHash, blockNumber, startKAId, endKAId, batchId, ctx, ctxGraphId, subGraphName, authorAddress, effectiveKeepRoot);
2377
- await writeMaterializedVersion(this.store, targetMetaGraph, ual, finalizationVersion);
2378
- if (effectiveKeepRoot) {
2379
- await writeMaterializedVersion(this.store, defaultMeta, ual, finalizationVersion);
2380
- }
2381
- return 'promoted';
2382
- };
2383
- // Nested per-graph locks. Acquired in sorted order to prevent
2384
- // cross-deadlock with any other call site that might one day
2385
- // also lock multiple metas.
2386
- const lockOrder = isDualWrite
2387
- ? [defaultMeta, targetMetaGraph].sort()
2388
- : [targetMetaGraph];
2389
- if (lockOrder.length === 1) {
2390
- return withMaterializationLock(lockOrder[0], ual, promoteUnderLocks);
2391
- }
2392
- return withMaterializationLock(lockOrder[0], ual, () => withMaterializationLock(lockOrder[1], ual, promoteUnderLocks));
2393
- }
2394
1701
  /**
2395
1702
  * Resolve the exact graph namespace from canonical graph-scoped metadata.
2396
1703
  * A named assertion stores its namespace in the root metadata graph, so this
@@ -2448,30 +1755,27 @@ export class FinalizationHandler {
2448
1755
  return null;
2449
1756
  }
2450
1757
  }
2451
- /**
2452
- * Constant-time exact graph-scoped reconciliation. This method never enters
2453
- * the legacy workspace-operation scan.
2454
- */
1758
+ /** Constant-time exact graph-scoped reconciliation. */
2455
1759
  async reconcileExactChainRegisteredKC(rawInput, ctx) {
2456
1760
  const resolvedInput = await this.resolveExactChainReconcileInput(rawInput, ctx);
2457
1761
  if (!resolvedInput) {
2458
- return { outcome: 'no-swm', legacyEligible: false, input: rawInput };
1762
+ return { outcome: 'no-swm', legacyMarkerEligible: false, input: rawInput };
2459
1763
  }
2460
1764
  const input = resolvedInput;
2461
1765
  const { contextGraphId, onChainCgId, ual, merkleRoot, publisherAddress, kaId, batchId, versionBlock, authorAddress, subGraphName, trustedAssertionEvidence, assertionVersion, versionSnapshot, signal, } = input;
2462
1766
  if (!(await this.verifyChainCgBinding(kaId, onChainCgId, ctx))) {
2463
1767
  this.log.info(ctx, `Chain-reconcile: chain CG binding for ${ual} (ka=${kaId}) not confirmed against cg ${onChainCgId}; deferring to sweep retry`);
2464
- return { outcome: 'unverified', legacyEligible: false, input };
1768
+ return { outcome: 'unverified', legacyMarkerEligible: false, input };
2465
1769
  }
2466
1770
  const journalReplay = await this.replayMatchingRecoveryEntries(input, ctx);
2467
1771
  // The recovery index predates exact chain-rootCount evidence. Exact asset
2468
1772
  // inspection must therefore verify the resulting local assertion version
2469
1773
  // below instead of treating a same-root replay as sufficient on its own.
2470
1774
  if (journalReplay === 'recovered' && assertionVersion === undefined) {
2471
- return { outcome: 'already-confirmed', legacyEligible: false, input };
1775
+ return { outcome: 'already-confirmed', legacyMarkerEligible: false, input };
2472
1776
  }
2473
1777
  if (journalReplay === 'retry-pending' && assertionVersion === undefined) {
2474
- return { outcome: 'receipt-revalidation-pending', legacyEligible: false, input };
1778
+ return { outcome: 'receipt-revalidation-pending', legacyMarkerEligible: false, input };
2475
1779
  }
2476
1780
  if (journalReplay === 'invalidated') {
2477
1781
  this.log.info(ctx, `Chain-reconcile: stale finalization evidence for ${ual} was invalidated; `
@@ -2494,14 +1798,14 @@ export class FinalizationHandler {
2494
1798
  trustedAssertionEvidence,
2495
1799
  }, ctx);
2496
1800
  if (graphScopedOutcome !== undefined) {
2497
- return { outcome: graphScopedOutcome, legacyEligible: false, input };
1801
+ return { outcome: graphScopedOutcome, legacyMarkerEligible: false, input };
2498
1802
  }
2499
1803
  if (await this.hasGraphScopedMetadata(contextGraphId, ual)) {
2500
1804
  this.log.info(ctx, `Chain-reconcile: graph-scoped metadata exists for ${ual} but its durable workspace head is missing`);
2501
- return { outcome: 'no-swm', legacyEligible: false, input };
1805
+ return { outcome: 'no-swm', legacyMarkerEligible: false, input };
2502
1806
  }
2503
- this.log.info(ctx, `Chain-reconcile: exact graph-scoped state is absent for ${ual}; legacy scan is not part of the exact operation`);
2504
- return { outcome: 'no-swm', legacyEligible: true, input };
1807
+ this.log.info(ctx, `Chain-reconcile: no local graph-scoped state for ${ual}`);
1808
+ return { outcome: 'no-swm', legacyMarkerEligible: true, input };
2505
1809
  }
2506
1810
  /**
2507
1811
  * Reconcile only the exact graph-scoped state named by one UAL. This is the
@@ -2511,64 +1815,28 @@ export class FinalizationHandler {
2511
1815
  return (await this.reconcileExactChainRegisteredKC(input, ctx)).outcome;
2512
1816
  }
2513
1817
  /**
2514
- * Normal chain reconciliation composes the exact operation with the legacy
2515
- * workspace scan. The scan remains available only through this ordinary path.
1818
+ * Normal chain reconciliation: the exact operation, then the historical
1819
+ * confirmed marker of a KA materialized before per-KA graphs. A KA with no
1820
+ * local graph-scoped state answers `no-swm` and the caller fetches it from
1821
+ * peers; historical workspace operations are never searched for it.
2516
1822
  */
2517
1823
  async handleChainReconciledKC(rawInput, ctx) {
2518
1824
  const exact = await this.reconcileExactChainRegisteredKC(rawInput, ctx);
2519
- if (!exact.legacyEligible)
1825
+ if (!exact.legacyMarkerEligible)
2520
1826
  return exact.outcome;
2521
- const { contextGraphId, onChainCgId, ual, merkleRoot, publisherAddress, kaId, batchId, versionBlock, authorAddress, subGraphName, } = exact.input;
2522
- const ctxGraphId = onChainCgId.length > 0 ? onChainCgId : undefined;
2523
- const targetMetaGraph = ctxGraphId
2524
- ? contextGraphMetaUri(contextGraphId, ctxGraphId)
2525
- : `did:dkg:context-graph:${contextGraphId}/_meta`;
1827
+ const { contextGraphId, onChainCgId, ual } = exact.input;
1828
+ const rootMetaGraph = `did:dkg:context-graph:${contextGraphId}/_meta`;
1829
+ const targetMetaGraph = onChainCgId.length > 0
1830
+ ? contextGraphMetaUri(contextGraphId, onChainCgId)
1831
+ : rootMetaGraph;
2526
1832
  // The ordinary compatibility path may retain the historical confirmed
2527
1833
  // marker shortcut. Exact RFC-64 fetch cannot use this marker because it
2528
1834
  // proves neither the current assertion version nor the current chain root.
2529
- if (await this.isAlreadyConfirmed(ual, targetMetaGraph, `did:dkg:context-graph:${contextGraphId}/_meta`)) {
1835
+ if (await this.isAlreadyConfirmed(ual, targetMetaGraph, rootMetaGraph)) {
2530
1836
  this.log.info(ctx, `Chain-reconcile: legacy ${ual} already confirmed in VM, skipping`);
2531
1837
  return 'already-confirmed';
2532
1838
  }
2533
- // Recover the published roots from the legacy local SWM snapshot. This is
2534
- // the only operation that may scan historical workspace operations.
2535
- const snapshot = await this.findSwmSnapshotForMerkleRoot(contextGraphId, merkleRoot, subGraphName, onChainCgId);
2536
- if (!snapshot) {
2537
- this.log.info(ctx, `Chain-reconcile: no local SWM snapshot matches the published merkleRoot for ${ual}; deferring to sweep retry`);
2538
- return 'no-swm';
2539
- }
2540
- const { rootEntities, sharedMemoryQuads } = snapshot;
2541
- const resolvedSubGraphName = snapshot.subGraphName ?? subGraphName;
2542
- const finalizationVersion = { blockNumber: versionBlock, txIndex: 0 };
2543
- const keepRootCopyOnLabel = await this.getKeepRootCopySignal(contextGraphId, rootEntities, resolvedSubGraphName);
2544
- const isDualWrite = keepRootCopyOnLabel === true && !!ctxGraphId && !resolvedSubGraphName;
2545
- const defaultMeta = `did:dkg:context-graph:${contextGraphId}/_meta`;
2546
- const outcome = await this.applyVerifiedFinalization({
2547
- contextGraphId,
2548
- sharedMemoryQuads,
2549
- ual,
2550
- rootEntities,
2551
- publisherAddress,
2552
- txHash: '',
2553
- blockNumber: versionBlock,
2554
- startKAId: kaId,
2555
- endKAId: kaId,
2556
- batchId,
2557
- ctxGraphId,
2558
- subGraphName: resolvedSubGraphName,
2559
- authorAddress,
2560
- finalizationVersion,
2561
- targetMetaGraph,
2562
- defaultMeta,
2563
- isDualWrite,
2564
- ctx,
2565
- });
2566
- if (outcome === 'stale-target') {
2567
- this.log.info(ctx, `Chain-reconcile: a newer update is already materialised for ${ual}, skipping`);
2568
- return 'stale-target';
2569
- }
2570
- this.log.info(ctx, `Chain-reconcile: promoted SWM snapshot to VM for ${ual} (ka=${kaId}, cg=${onChainCgId})`);
2571
- return 'promoted';
1839
+ return exact.outcome;
2572
1840
  }
2573
1841
  /**
2574
1842
  * Decide from local state alone whether an ordinary chain reconcile of one
@@ -2587,14 +1855,16 @@ export class FinalizationHandler {
2587
1855
  * 4. graph-scoped metadata without a head or confirmed copy;
2588
1856
  * 5. the legacy confirmed marker, which that path answers
2589
1857
  * `already-confirmed` without reading the root;
2590
- * 6. legacy workspace operations, the root-matched scan: with none in the
2591
- * namespaces it searches, nothing local can match any root, so `none`.
1858
+ * 6. nothing else is searched, so everything left is `none`.
2592
1859
  *
2593
1860
  * `confirmed-vm` trusts the root the local copy was confirmed at; a newer
2594
- * on-chain version is not looked for here. The ordinal walk never revisits a
2595
- * settled ordinal, so an update already reaches VM through finalization
2596
- * gossip, the StorageACK pending-update lane, or, when its SWM head is local,
2597
- * the chain-backed path this method routes it to (`present`).
1861
+ * on-chain version is not looked for here, which keeps the walk free of
1862
+ * chain reads for copies it already holds. The walk never revisits a settled
1863
+ * ordinal either, so an update reaches a held copy through finalization
1864
+ * gossip, the StorageACK pending-update lane, the chain-backed path this
1865
+ * method routes a local SWM head to (`present`) while its ordinal is still
1866
+ * walked, and, for any confirmed copy, the `KnowledgeAssetUpdated` refresh
1867
+ * (`handleKAUpdatedNudge` in the agent's SWM host).
2598
1868
  *
2599
1869
  * Any read failure answers `present`, keeping the caller on its chain path.
2600
1870
  */
@@ -2662,9 +1932,7 @@ export class FinalizationHandler {
2662
1932
  if (await this.isAlreadyConfirmed(ual, targetMetaGraph, rootMetaGraph)) {
2663
1933
  return { kind: 'confirmed-vm', layout: 'legacy' };
2664
1934
  }
2665
- return await this.hasLegacySwmOperations(contextGraphId, subGraphName)
2666
- ? LOCAL_CANDIDATE_PRESENT
2667
- : { kind: 'none' };
1935
+ return { kind: 'none' };
2668
1936
  }
2669
1937
  /**
2670
1938
  * Whether the headless-VM retirement in the chain-backed path would find an
@@ -2681,53 +1949,6 @@ export class FinalizationHandler {
2681
1949
  const result = await this.store.query(`ASK { ${graphs.map((graph) => `{ GRAPH <${assertSafeIri(graph)}> { ?s ?p ?o } }`).join(' UNION ')} }`, { source: 'agent.finalization.localCandidate.swmTwin' });
2682
1950
  return result.type !== 'boolean' || result.value;
2683
1951
  }
2684
- /**
2685
- * Whether the root-matched legacy scan (`findSwmSnapshotForMerkleRoot`) has
2686
- * any WorkspaceOperation to look at: the given namespace, or the root and
2687
- * every listed sub-graph when none is known. Memoized per CG write
2688
- * generation, like that scan's negative memo, so a quiet graph answers from
2689
- * memory for the whole sweep.
2690
- */
2691
- async hasLegacySwmOperations(contextGraphId, subGraphName) {
2692
- const memoKey = `${contextGraphId}\0${subGraphName ?? ''}`;
2693
- const revision = this.graphWriteGen?.getWriteRevision(`${contextGraphDataUri(contextGraphId)}/`);
2694
- if (revision?.stable) {
2695
- const memo = this.legacySwmOperationsMemo.get(memoKey);
2696
- if (memo
2697
- && memo.writeGen === revision.generation
2698
- && Date.now() - memo.recordedAt < vmReconcileNegativeTtlMs()) {
2699
- return memo.present;
2700
- }
2701
- }
2702
- const graphManager = new GraphManager(this.store);
2703
- const metaGraphs = subGraphName
2704
- ? [graphManager.sharedMemoryMetaUri(contextGraphId, subGraphName)]
2705
- : [
2706
- contextGraphWorkspaceMetaGraphUri(contextGraphId),
2707
- ...(await graphManager.listSubGraphs(contextGraphId))
2708
- .map((name) => graphManager.sharedMemoryMetaUri(contextGraphId, name)),
2709
- ];
2710
- const result = await this.store.query(`ASK { ${metaGraphs
2711
- .map((graph) => `{ GRAPH <${assertSafeIri(graph)}> { ?op <${DKG_NS}rootEntity> ?root } }`)
2712
- .join(' UNION ')} }`, { source: 'agent.finalization.localCandidate.legacySwmOperations' });
2713
- const present = result.type !== 'boolean' || result.value;
2714
- if (revision?.stable) {
2715
- // Recorded at the pre-probe generation: a racing write flips the gate.
2716
- this.legacySwmOperationsMemo.delete(memoKey);
2717
- this.legacySwmOperationsMemo.set(memoKey, {
2718
- writeGen: revision.generation,
2719
- recordedAt: Date.now(),
2720
- present,
2721
- });
2722
- while (this.legacySwmOperationsMemo.size > VM_RECONCILE_NEGATIVE_MEMO_MAX_ENTRIES) {
2723
- const oldest = this.legacySwmOperationsMemo.keys().next().value;
2724
- if (oldest === undefined)
2725
- break;
2726
- this.legacySwmOperationsMemo.delete(oldest);
2727
- }
2728
- }
2729
- return present;
2730
- }
2731
1952
  async verifyChainCgBinding(kaId, onChainCgId, ctx) {
2732
1953
  if (!this.chain || this.chain.chainId === 'none' || typeof this.chain.getKAContextGraphId !== 'function') {
2733
1954
  return false;
@@ -2741,784 +1962,5 @@ export class FinalizationHandler {
2741
1962
  return false;
2742
1963
  }
2743
1964
  }
2744
- /**
2745
- * Find the local SWM snapshot whose KC merkle root matches the chain
2746
- * `merkleRoot`, returning its root entities + shared-memory quads.
2747
- *
2748
- * SWM workspace meta is written at share-time (before publish), so it carries
2749
- * no merkle root to look up by — only `?op a dkg:WorkspaceOperation ;
2750
- * dkg:rootEntity <root>`. We therefore enumerate the candidate operations,
2751
- * gather each one's SWM quads + private roots, recompute the flat-KC root
2752
- * (`computeFlatKCRoot`, the same function the gossip path verifies against),
2753
- * and return the first operation whose computed root equals the chain root.
2754
- * A match is an authoritative merkle verification.
2755
- *
2756
- * Returns `null` when no local operation matches — either the snapshot hasn't
2757
- * been synced yet (the caller's active-fetch missed / is in flight) or this
2758
- * KA belongs to a publish this node never shared. Either way the B.2 sweep
2759
- * retries later.
2760
- *
2761
- * Cost note (#1609): the recompute is memoized (`SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE`
2762
- * + content digest). A *present* KA is resolved by its stamped root directly (fast
2763
- * path, no scan); the fallback still enumerates every op — it must, because ops
2764
- * assemble incrementally — but reuses each op's memoized root whenever its content
2765
- * digest is unchanged, skipping the expensive `computeFlatKCRoot`. So steady-state
2766
- * reconcile pays one bounded read + a cheap digest per op instead of a full merkle
2767
- * recompute per op. This is a bridge; OT-RFC-60 makes the root a write-maintained,
2768
- * indexed property (stamped once at op completion) so the fallback disappears
2769
- * entirely. The generated-catalog-floor variant keeps the exhaustive recompute
2770
- * (its match is over quads+floor, not the op's intrinsic stamped root).
2771
- *
2772
- * READ memo (#1609, 2026-07-11/12 testnet incident): the #1612 digest memo skips
2773
- * only the merkle recompute — a never-match KA (a publish this node never shared,
2774
- * exactly the beacon shape) still paid O(#ops) unbounded SWM CONSTRUCTs on EVERY
2775
- * sweep tick, forever, stalling the event loop and dropping storage-ACK streams
2776
- * on big stores. This wrapper adds a write-generation-gated NEGATIVE memo over
2777
- * the whole scan (floor retry included): a "no match" verdict is replayed
2778
- * without touching the store while (a) the adapter's write generation for the
2779
- * CG's graph prefix is unchanged — new SWM only arrives via local writes
2780
- * (gossip receive, publish share, active fetch), all of which pass the adapter
2781
- * choke points and bump the generation, so the next call rescans — (b) the
2782
- * catalog-floor eligibility is unchanged, and (c) the entry is younger than
2783
- * `vmReconcileNegativeTtlMs()`. A MATCH is never memoized. Stores without the
2784
- * write-generation capability disable the memo entirely (always scan), and a
2785
- * restart clears it — every failure mode degrades to a rescan, never a miss.
2786
- */
2787
- async findSwmSnapshotForMerkleRoot(contextGraphId, merkleRoot, subGraphName, onChainCgId) {
2788
- const allowGeneratedCatalogFloor = await this.allowsGeneratedCatalogFloor(contextGraphId, onChainCgId);
2789
- // Every graph the scan reads — root/sub-graph SWM buckets, their per-KA
2790
- // under-graphs and `_shared_memory_meta` (op rows, `privateMerkleRoot`,
2791
- // stamps) — lives under the CG's URI subtree, so one prefix covers all
2792
- // namespaces of this call. Broader than strictly needed (any CG-local
2793
- // write invalidates) — that only costs an extra rescan.
2794
- const memoKey = `${contextGraphId}\0${subGraphName ?? ''}\0${ethers.hexlify(merkleRoot)}`;
2795
- const swmWritePrefix = `${contextGraphDataUri(contextGraphId)}/`;
2796
- const preScanRevision = this.graphWriteGen?.getWriteRevision(swmWritePrefix);
2797
- const preScanGen = preScanRevision?.generation;
2798
- if (preScanRevision?.stable) {
2799
- const memo = this.negativeSnapshotMemo.get(memoKey);
2800
- if (memo) {
2801
- if (memo.writeGen === preScanGen &&
2802
- memo.allowGeneratedCatalogFloor === allowGeneratedCatalogFloor &&
2803
- Date.now() - memo.recordedAt < vmReconcileNegativeTtlMs()) {
2804
- // Refresh LRU recency; recordedAt stays — the TTL runs from the scan.
2805
- this.negativeSnapshotMemo.delete(memoKey);
2806
- this.negativeSnapshotMemo.set(memoKey, memo);
2807
- return null;
2808
- }
2809
- this.negativeSnapshotMemo.delete(memoKey);
2810
- }
2811
- }
2812
- const hit = await this.runScanSingleFlight(['reconcile', memoKey, String(allowGeneratedCatalogFloor), String(preScanGen ?? 'unknown')].join('\u0000'), () => this.scanForSwmSnapshot(contextGraphId, merkleRoot, subGraphName, allowGeneratedCatalogFloor));
2813
- if (hit)
2814
- return hit;
2815
- if (preScanRevision?.stable) {
2816
- // Record at the PRE-scan generation: any write that raced the scan (or
2817
- // the scan's own best-effort restamps) flips the gate above, so the next
2818
- // call rescans rather than replaying a verdict that may predate the write.
2819
- this.negativeSnapshotMemo.set(memoKey, {
2820
- writeGen: preScanRevision.generation,
2821
- recordedAt: Date.now(),
2822
- allowGeneratedCatalogFloor,
2823
- });
2824
- while (this.negativeSnapshotMemo.size > VM_RECONCILE_NEGATIVE_MEMO_MAX_ENTRIES) {
2825
- const oldest = this.negativeSnapshotMemo.keys().next().value;
2826
- if (oldest === undefined)
2827
- break;
2828
- this.negativeSnapshotMemo.delete(oldest);
2829
- }
2830
- }
2831
- return null;
2832
- }
2833
- /** The authoritative full scan behind {@link findSwmSnapshotForMerkleRoot}. */
2834
- async scanForSwmSnapshot(contextGraphId, merkleRoot, subGraphName, allowGeneratedCatalogFloor) {
2835
- // Caller knows the exact namespace → search only that one.
2836
- if (subGraphName) {
2837
- const hit = await this.findSwmSnapshotInNamespace(contextGraphId, merkleRoot, subGraphName, allowGeneratedCatalogFloor);
2838
- return hit ? { ...hit, subGraphName } : null;
2839
- }
2840
- // No namespace supplied (the chain-driven path never knows it). Try the
2841
- // root workspace first, then fall back to every registered sub-graph —
2842
- // otherwise a KA published into a named sub-graph would stay `no-swm`
2843
- // forever because its SWM snapshot lives under a sub-graph meta graph,
2844
- // not the root workspace meta. Return the namespace we matched in so the
2845
- // caller promotes into the correct data graph.
2846
- const rootHit = await this.findSwmSnapshotInNamespace(contextGraphId, merkleRoot, undefined, allowGeneratedCatalogFloor);
2847
- if (rootHit)
2848
- return { ...rootHit, subGraphName: undefined };
2849
- let subGraphNames = [];
2850
- try {
2851
- subGraphNames = await new GraphManager(this.store).listSubGraphs(contextGraphId);
2852
- }
2853
- catch { /* no sub-graphs / store can't enumerate */ }
2854
- for (const sg of subGraphNames) {
2855
- const hit = await this.findSwmSnapshotInNamespace(contextGraphId, merkleRoot, sg, allowGeneratedCatalogFloor);
2856
- if (hit)
2857
- return { ...hit, subGraphName: sg };
2858
- }
2859
- return null;
2860
- }
2861
- /**
2862
- * Search a single SWM namespace (root workspace when `subGraphName` is
2863
- * undefined, otherwise the named sub-graph's shared-memory meta) for a
2864
- * WorkspaceOperation whose recomputed flat-KC root matches `merkleRoot`.
2865
- */
2866
- async findSwmSnapshotInNamespace(contextGraphId, merkleRoot, subGraphName, allowGeneratedCatalogFloor = false) {
2867
- const graphManager = new GraphManager(this.store);
2868
- const wsMetaGraph = subGraphName
2869
- ? graphManager.sharedMemoryMetaUri(contextGraphId, subGraphName)
2870
- : contextGraphWorkspaceMetaGraphUri(contextGraphId);
2871
- // The generated-catalog-floor variant matches over quads+floor rather than an
2872
- // op's intrinsic root, so it cannot be resolved by the stamped intrinsic root —
2873
- // those CGs (a stable per-CG access policy) keep the exhaustive recompute scan.
2874
- const useStampIndex = !allowGeneratedCatalogFloor;
2875
- // FAST PATH — resolve a *present* KA whose op is stamped with the target root via
2876
- // one indexed lookup (verified authoritatively), instead of recomputing every op's
2877
- // root. On a miss it falls through to the memoized fallback scan below.
2878
- if (useStampIndex) {
2879
- const stamped = await this.findStampedSwmSnapshot(contextGraphId, wsMetaGraph, merkleRoot, subGraphName);
2880
- if (stamped)
2881
- return stamped;
2882
- }
2883
- const opsBySubject = new Map();
2884
- try {
2885
- const memoPatterns = useStampIndex
2886
- ? `OPTIONAL { ?op <${SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE}> ?memoRoot . }
2887
- OPTIONAL { ?op <${SWM_SNAPSHOT_CONTENT_DIGEST_PREDICATE}> ?memoDigest . }`
2888
- : '';
2889
- const result = await this.store.query(`SELECT ?op ?root ?memoRoot ?memoDigest WHERE {
2890
- GRAPH <${assertSafeIri(wsMetaGraph)}> {
2891
- ?op <${DKG_NS}rootEntity> ?root .
2892
- ${memoPatterns}
2893
- }
2894
- }`, { source: 'agent.finalization.swmSnapshotCandidates' });
2895
- if (result.type === 'bindings') {
2896
- for (const row of result.bindings) {
2897
- const op = typeof row['op'] === 'string' ? row['op'].replace(/^<(.*)>$/, '$1') : '';
2898
- const root = typeof row['root'] === 'string' ? row['root'].replace(/^<(.*)>$/, '$1') : '';
2899
- if (!op || !isSafeIri(root))
2900
- continue;
2901
- const memo = opsBySubject.get(op) ?? { roots: [] };
2902
- if (!memo.roots.includes(root))
2903
- memo.roots.push(root);
2904
- if (memo.memoRoot === undefined && typeof row['memoRoot'] === 'string') {
2905
- memo.memoRoot = row['memoRoot'].replace(/^"(.*)".*$/, '$1');
2906
- }
2907
- if (memo.memoDigest === undefined && typeof row['memoDigest'] === 'string') {
2908
- memo.memoDigest = row['memoDigest'].replace(/^"(.*)".*$/, '$1');
2909
- }
2910
- opsBySubject.set(op, memo);
2911
- }
2912
- }
2913
- }
2914
- catch { /* SWM meta may not exist yet */ }
2915
- if (opsBySubject.size === 0)
2916
- return null;
2917
- const opsSorted = [...opsBySubject.entries()].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
2918
- // Ops whose content changed (or were never stamped) get a fresh (root, digest)
2919
- // memo written after the loop — best-effort: a store hiccup on the memo must
2920
- // never fail reconcile (correctness comes from the recompute here).
2921
- const restamp = new Map();
2922
- const targetHex = ethers.hexlify(merkleRoot);
2923
- let hit = null;
2924
- for (const [op, memo] of opsSorted) {
2925
- const roots = memo.roots;
2926
- const sharedMemoryQuads = await this.getSharedMemoryQuadsForRoots(contextGraphId, roots, subGraphName);
2927
- if (sharedMemoryQuads.length === 0)
2928
- continue;
2929
- const privateRoots = await this.getPrivateRootsFromMeta(contextGraphId, roots, subGraphName);
2930
- if (useStampIndex) {
2931
- const digest = this.swmContentDigest(sharedMemoryQuads, privateRoots);
2932
- let computedHex;
2933
- if (memo.memoRoot !== undefined && memo.memoDigest === digest) {
2934
- // Content unchanged since the memo was written → reuse the root and skip
2935
- // the expensive computeFlatKCRoot. The digest is a pure function of the
2936
- // same (quads, privateRoots) computeFlatKCRoot consumes, so digest-equal
2937
- // ⇒ root-equal.
2938
- computedHex = memo.memoRoot;
2939
- }
2940
- else {
2941
- computedHex = this.computeOpMerkleRoot(sharedMemoryQuads, privateRoots);
2942
- restamp.set(op, { root: computedHex, digest });
2943
- }
2944
- if (computedHex === targetHex) {
2945
- hit = { rootEntities: roots, sharedMemoryQuads };
2946
- break;
2947
- }
2948
- }
2949
- else {
2950
- const merkleMatchedQuads = this.sharedMemoryQuadsMatchingMerkle(contextGraphId, sharedMemoryQuads, privateRoots, merkleRoot, allowGeneratedCatalogFloor);
2951
- if (merkleMatchedQuads) {
2952
- return { rootEntities: roots, sharedMemoryQuads: merkleMatchedQuads };
2953
- }
2954
- }
2955
- }
2956
- await this.persistSwmStamps(wsMetaGraph, restamp);
2957
- return hit;
2958
- }
2959
- /**
2960
- * Cheap content fingerprint of an op's SWM snapshot — a pure function of the same
2961
- * `(sharedMemoryQuads, privateRoots)` that `computeFlatKCRoot` consumes, but a
2962
- * plain sorted-sha256 rather than the full skolemize + merkle construction. Used
2963
- * only to decide whether a memoized root is still valid (digest-equal ⇒ the
2964
- * content, hence its flat-KC root, is unchanged), never as an authoritative root.
2965
- */
2966
- /**
2967
- * The op's intrinsic flat-KC merkle root (hex) — the expensive recompute the
2968
- * content-digest memo lets us skip for unchanged ops. A named seam so callers and
2969
- * tests can attribute the cost.
2970
- */
2971
- computeOpMerkleRoot(sharedMemoryQuads, privateRoots) {
2972
- return ethers.hexlify(computeFlatKCRoot(sharedMemoryQuads, privateRoots));
2973
- }
2974
- swmContentDigest(sharedMemoryQuads, privateRoots) {
2975
- // Unambiguous encoding (NUL field-sep, NL row-sep) matching the SWM-generation
2976
- // fingerprint convention in `readVmReconcileSwmGen`, so distinct contents cannot
2977
- // collide to the same digest and cause a wrong memoized-root reuse.
2978
- const quadLines = sharedMemoryQuads
2979
- .map((q) => [q.subject, q.predicate, typeof q.object === 'string' ? q.object : String(q.object), q.graph ?? ''].join('\0'))
2980
- .sort();
2981
- const privateLines = privateRoots.map((r) => ethers.hexlify(r)).sort();
2982
- const payload = `${quadLines.join('\n')}\0\0private\0\0${privateLines.join('\n')}`;
2983
- return createHash('sha256').update(payload, 'utf8').digest('hex');
2984
- }
2985
- /**
2986
- * Replace the (root, content-digest) memo for each op — delete-then-insert so an
2987
- * op never accumulates duplicate/stale stamp triples. Best-effort; a failure here
2988
- * leaves the memo absent (next pass recomputes), never wrong.
2989
- */
2990
- async persistSwmStamps(wsMetaGraph, restamp) {
2991
- if (restamp.size === 0)
2992
- return;
2993
- try {
2994
- const quads = [];
2995
- for (const [op, { root, digest }] of restamp) {
2996
- await deleteByPatternWithoutCount(this.store, { graph: wsMetaGraph, subject: op, predicate: SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE });
2997
- await deleteByPatternWithoutCount(this.store, { graph: wsMetaGraph, subject: op, predicate: SWM_SNAPSHOT_CONTENT_DIGEST_PREDICATE });
2998
- quads.push({ subject: op, predicate: SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE, object: `"${root}"`, graph: wsMetaGraph }, { subject: op, predicate: SWM_SNAPSHOT_CONTENT_DIGEST_PREDICATE, object: `"${digest}"`, graph: wsMetaGraph });
2999
- }
3000
- await this.store.insert(quads);
3001
- }
3002
- catch { /* memo is best-effort; the recompute is the source of truth */ }
3003
- }
3004
- /**
3005
- * Fast path for `findSwmSnapshotInNamespace`: resolve the WorkspaceOperation
3006
- * whose stamped intrinsic root equals `merkleRoot` without recomputing every
3007
- * op's root. Re-verifies with `verifyMerkleMatch` (authoritative) so a stale
3008
- * stamp can never promote the wrong snapshot; a stamp that no longer verifies is
3009
- * dropped so the op falls back into the recompute scan this same pass.
3010
- */
3011
- async findStampedSwmSnapshot(contextGraphId, wsMetaGraph, merkleRoot, subGraphName) {
3012
- const targetHex = ethers.hexlify(merkleRoot);
3013
- const rootsByOp = new Map();
3014
- try {
3015
- const result = await this.store.query(`SELECT ?op ?root WHERE {
3016
- GRAPH <${assertSafeIri(wsMetaGraph)}> {
3017
- ?op <${SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE}> "${targetHex}" .
3018
- ?op <${DKG_NS}rootEntity> ?root .
3019
- }
3020
- }`, { source: 'agent.finalization.stampedSwmSnapshot' });
3021
- if (result.type === 'bindings') {
3022
- for (const row of result.bindings) {
3023
- const op = typeof row['op'] === 'string' ? row['op'].replace(/^<(.*)>$/, '$1') : '';
3024
- const root = typeof row['root'] === 'string' ? row['root'].replace(/^<(.*)>$/, '$1') : '';
3025
- if (!op || !isSafeIri(root))
3026
- continue;
3027
- const list = rootsByOp.get(op) ?? [];
3028
- list.push(root);
3029
- rootsByOp.set(op, list);
3030
- }
3031
- }
3032
- }
3033
- catch {
3034
- return null;
3035
- }
3036
- for (const [op, roots] of rootsByOp) {
3037
- const sharedMemoryQuads = await this.getSharedMemoryQuadsForRoots(contextGraphId, roots, subGraphName);
3038
- if (sharedMemoryQuads.length > 0) {
3039
- const privateRoots = await this.getPrivateRootsFromMeta(contextGraphId, roots, subGraphName);
3040
- if (this.verifyMerkleMatch(sharedMemoryQuads, privateRoots, merkleRoot)) {
3041
- return { rootEntities: roots, sharedMemoryQuads };
3042
- }
3043
- }
3044
- // The stamp no longer reflects the op's content — drop the whole (root, digest)
3045
- // memo so the recompute scan re-evaluates and re-stamps it this pass.
3046
- try {
3047
- await deleteByPatternWithoutCount(this.store, { graph: wsMetaGraph, subject: op, predicate: SWM_SNAPSHOT_MERKLE_ROOT_PREDICATE });
3048
- await deleteByPatternWithoutCount(this.store, { graph: wsMetaGraph, subject: op, predicate: SWM_SNAPSHOT_CONTENT_DIGEST_PREDICATE });
3049
- }
3050
- catch { /* best-effort self-heal */ }
3051
- }
3052
- return null;
3053
- }
3054
- async verifyOnChain(txHash, blockNumber, expectedMerkleRoot, expectedPublisher, expectedStartKAId, expectedEndKAId, ctx, ctxGraphId, expectedBatchId) {
3055
- if (!this.chain || this.chain.chainId === 'none')
3056
- return { verified: false };
3057
- if (blockNumber <= 0)
3058
- return { verified: false };
3059
- try {
3060
- // Verify KnowledgeBatchCreated or KCCreated (V10) at the specific block
3061
- const batchFilter = {
3062
- eventTypes: ['KnowledgeBatchCreated', 'KCCreated'],
3063
- fromBlock: blockNumber,
3064
- toBlock: blockNumber,
3065
- };
3066
- let batchVerified = false;
3067
- // Round 5 review §10 — capture the indexed `author` from the matched
3068
- // KCCreated event so the caller can populate `dkg:Publication` /
3069
- // `dkg:authoredBy` provenance on the replica side, mirroring the
3070
- // originator. `address(0)` here is the unattributed-publish sentinel
3071
- // (RFC-001 §3.6) and is correctly preserved.
3072
- let authorAddress;
3073
- // PR #845 review #9: capture the chain-truth `transactionIndex` from
3074
- // the matched event so the materialization-version guard does not
3075
- // have to trust the gossip-supplied `msg.txIndex` (which a peer can
3076
- // inflate to lock out a legitimate same-block update).
3077
- let verifiedTxIndex;
3078
- for await (const event of this.chain.listenForEvents(batchFilter)) {
3079
- if (event.blockNumber !== blockNumber)
3080
- continue;
3081
- if (txHash && (!event.data['txHash'] || event.data['txHash'].toLowerCase() !== txHash.toLowerCase())) {
3082
- continue;
3083
- }
3084
- const eventMerkle = typeof event.data['merkleRoot'] === 'string'
3085
- ? ethers.getBytes(event.data['merkleRoot'])
3086
- : event.data['merkleRoot'];
3087
- const eventPublisher = event.data['publisherAddress'] ?? '';
3088
- const eventStartKAId = BigInt(event.data['startKAId'] ?? '0');
3089
- const eventEndKAId = BigInt(event.data['endKAId'] ?? '0');
3090
- const merkleMatch = ethers.hexlify(eventMerkle) === ethers.hexlify(expectedMerkleRoot);
3091
- const publisherMatch = eventPublisher.toLowerCase() === expectedPublisher.toLowerCase();
3092
- const rangeMatch = eventStartKAId === expectedStartKAId && eventEndKAId === expectedEndKAId;
3093
- if (merkleMatch && publisherMatch && rangeMatch) {
3094
- batchVerified = true;
3095
- const eventAuthor = event.data['author'] ?? '';
3096
- if (eventAuthor)
3097
- authorAddress = eventAuthor;
3098
- const rawTxIdx = event.data['txIndex'];
3099
- if (typeof rawTxIdx === 'number' && Number.isFinite(rawTxIdx) && rawTxIdx >= 0) {
3100
- verifiedTxIndex = rawTxIdx;
3101
- }
3102
- break;
3103
- }
3104
- }
3105
- if (!batchVerified)
3106
- return { verified: false };
3107
- // V10 publish registers the KC to the context graph internally
3108
- // (no separate addBatchToContextGraph tx / ContextGraphExpanded event).
3109
- // Skip the legacy ContextGraphExpanded check — the batch verification
3110
- // above is sufficient for V10.
3111
- if (ctxGraphId) {
3112
- if (typeof this.chain.isV10Ready === 'function' && this.chain.isV10Ready()) {
3113
- return { verified: true, authorAddress, txIndex: verifiedTxIndex };
3114
- }
3115
- try {
3116
- const scanWindow = 256;
3117
- const headBlock = typeof this.chain.getBlockNumber === 'function'
3118
- ? await this.chain.getBlockNumber()
3119
- : blockNumber + scanWindow;
3120
- const cgFilter = {
3121
- eventTypes: ['ContextGraphExpanded'],
3122
- fromBlock: blockNumber,
3123
- toBlock: Math.min(blockNumber + scanWindow, headBlock),
3124
- };
3125
- for await (const event of this.chain.listenForEvents(cgFilter)) {
3126
- const eventCGId = String(event.data['contextGraphId'] ?? '');
3127
- const eventBatchId = BigInt(event.data['batchId'] ?? '0');
3128
- if (eventCGId === ctxGraphId && (expectedBatchId === undefined || eventBatchId === expectedBatchId)) {
3129
- return { verified: true, authorAddress, txIndex: verifiedTxIndex };
3130
- }
3131
- }
3132
- return { verified: false };
3133
- }
3134
- catch {
3135
- return { verified: true, authorAddress, txIndex: verifiedTxIndex };
3136
- }
3137
- }
3138
- return { verified: true, authorAddress, txIndex: verifiedTxIndex };
3139
- }
3140
- catch (err) {
3141
- this.log.info(ctx, `Finalization on-chain verification pending (RPC may be lagging): ${err instanceof Error ? err.message : String(err)}`);
3142
- }
3143
- return { verified: false };
3144
- }
3145
- async promoteSharedMemoryToCanonical(contextGraphId, sharedMemoryQuads, ual, msgRootEntities, publisherAddress, txHash, blockNumber, startKAId, endKAId, batchId, ctx, ctxGraphId, subGraphName,
3146
- /**
3147
- * EIP-712-attested author recovered from `KnowledgeAssetCreated.author`.
3148
- * Round 5 review §10 — when set, the replica emits matching
3149
- * `dkg:Publication` / `dkg:authoredBy` triples so agent-provenance via the
3150
- * `_meta` triplestore is consistent across the originator and every replica.
3151
- * `address(0)` and missing/empty values are skipped (preserves the
3152
- * unattributed-publish path's no-author behaviour from RFC-001 §3.6).
3153
- */
3154
- authorAddress,
3155
- /**
3156
- * PR #779 same-graph signal: when `true` the publisher kept a root-graph
3157
- * copy of the canonical quads, so receivers mirror the dual-write so
3158
- * label-scoped queries resolve. When `false` (or omitted on older
3159
- * publishers) the publisher used the explicit-`subContextGraphId` /
3160
- * remap path and deleted its own root copy on purpose — receivers
3161
- * MUST NOT dual-write or they re-expose the KC under the source CG
3162
- * label and double-count it in unscoped queries.
3163
- */
3164
- keepRootCopyOnLabel) {
3165
- const graphManager = new GraphManager(this.store);
3166
- await graphManager.ensureContextGraph(contextGraphId);
3167
- if (subGraphName) {
3168
- await graphManager.ensureSubGraph(contextGraphId, subGraphName);
3169
- const sgUri = contextGraphSubGraphUri(contextGraphId, subGraphName);
3170
- const metaGraph = `did:dkg:context-graph:${assertSafeIri(contextGraphId)}/_meta`;
3171
- const alreadyRegistered = await this.store.query(`ASK { GRAPH <${metaGraph}> {
3172
- <${assertSafeIri(sgUri)}> a <http://dkg.io/ontology/SubGraph> ;
3173
- <http://schema.org/name> ${JSON.stringify(subGraphName)} ;
3174
- <http://dkg.io/ontology/createdBy> ?createdBy .
3175
- } }`, { source: 'agent.finalization.subGraphRegistration' });
3176
- if (alreadyRegistered.type !== 'boolean' || !alreadyRegistered.value) {
3177
- const regQuads = generateSubGraphRegistration({
3178
- contextGraphId,
3179
- subGraphName,
3180
- createdBy: publisherAddress || 'finalization-discovery',
3181
- timestamp: new Date(),
3182
- });
3183
- await this.store.insert(regQuads);
3184
- this.markContextGraphMetaDirtyFromQuads?.(regQuads);
3185
- this.log.info(ctx, `Finalization: auto-registered sub-graph "${subGraphName}" in context graph "${contextGraphId}"`);
3186
- }
3187
- }
3188
- const dataGraph = subGraphName
3189
- ? contextGraphSubGraphUri(contextGraphId, subGraphName)
3190
- : ctxGraphId
3191
- ? contextGraphDataUri(contextGraphId, ctxGraphId)
3192
- : graphManager.dataGraphUri(contextGraphId);
3193
- // Devnet test #774-followup (v10-rc-validation §5 gossip replication):
3194
- // when `ctxGraphId` is set on a non-sub-graph publish, the canonical
3195
- // data lands in the per-on-chain-id partition
3196
- // `<cg>/context/<ctxGraphId>` only. The publisher path
3197
- // (`dkg-publisher.ts` ~line 1382) intentionally ALSO writes the same
3198
- // quads to the root `<cg>` graph "so `agent.query(label)` (which
3199
- // resolves to `did:dkg:context-graph:<label>` without a
3200
- // `/context/<id>` suffix) still finds the just-published triples"
3201
- // (commit c2abbc9a). Replicas were never updated to mirror that
3202
- // dual-write — so a CG-scoped query against a label on a recipient
3203
- // node finds 0 bindings even though the data is local in
3204
- // `<cg>/context/<ctxGraphId>`. The query engine cannot widen its
3205
- // allow set to `<cg>/context/<num>` without a CG-registry lookup
3206
- // (id-prefix collisions, see PR #776 r6 in dkg-query-engine.ts).
3207
- // Mirroring the publisher's same-graph dual-write fixes the
3208
- // visibility asymmetry without re-introducing that ambiguity.
3209
- //
3210
- // Critical scoping (Codex review on PR #779): the recipient dual-write
3211
- // MUST only fire for same-graph publishes (the publisher kept the
3212
- // root copy too). Explicit-`subContextGraphId` / remap publishes
3213
- // delete the root copy on purpose (`dkg-publisher.ts` ~line 1393),
3214
- // and a recipient that re-adds it would re-expose the KC under the
3215
- // source CG's label on every replica — leaking remap intent and
3216
- // double-counting the same triples in unscoped queries. The
3217
- // publisher signals same-graph vs remap on the wire via
3218
- // `keepRootCopyOnLabel`; missing/false (older publishers, or any
3219
- // remap publish) → no dual-write.
3220
- const rootDataGraphForLabel = (!subGraphName && ctxGraphId && keepRootCopyOnLabel === true)
3221
- ? graphManager.dataGraphUri(contextGraphId)
3222
- : null;
3223
- // Compute canonical quads now, but defer the `store.insert` until AFTER
3224
- // the confirmed-meta write and SWM cleanup (see bottom of this method).
3225
- //
3226
- // Rationale: on a replica the three store mutations (canonical insert,
3227
- // confirmed-meta insert, SWM cleanup) happen as three sequential awaits.
3228
- // Readers polling the canonical graph (e.g. downstream consumers waiting
3229
- // for "KC landed") can observe the canonical insert before the meta flip
3230
- // to `confirmed` or before SWM has been drained, producing a visible
3231
- // "data-without-confirmed-meta" intermediate state that is wrong from a
3232
- // causal-consistency standpoint (the whole point of the finalization
3233
- // gossip is that by the time data is canonical on a replica, the chain
3234
- // proof is durable too). On fast dev machines the window is sub-
3235
- // millisecond and invisible; on slower CI runners it widens to ~70 ms
3236
- // and a poll that happens to land there sees `tentative` instead of
3237
- // `confirmed` (flipped the `Tornado EVM integration: agent`
3238
- // e2e-finalization suite red on every PR-224 run since the
3239
- // sync-refactor merge at `bc65c3ae`).
3240
- //
3241
- // Ordering meta+cleanup BEFORE canonical insert makes the public state
3242
- // transition single-stepped from an observer's point of view: either
3243
- // you don't see the data yet, or you see data + confirmed meta + empty
3244
- // SWM. The only user-visible partial state that remains (confirmed
3245
- // meta + no data) is naturally recovered by `isAlreadyConfirmed` on the
3246
- // next retry path, and it's strictly less broken than the converse.
3247
- const canonicalQuads = sharedMemoryQuads.map(q => ({ ...q, graph: dataGraph }));
3248
- const privateRoots = await this.getPrivateRootsFromMeta(contextGraphId, msgRootEntities, subGraphName);
3249
- const merkleRoot = computeFlatKCRoot(canonicalQuads, privateRoots);
3250
- const partitioned = skolemizeByEntity(canonicalQuads);
3251
- const localRootSet = new Set(partitioned.keys());
3252
- const rootEntities = msgRootEntities.length > 0
3253
- ? msgRootEntities
3254
- : [...partitioned.keys()];
3255
- if (msgRootEntities.length > 0) {
3256
- const msgSet = new Set(msgRootEntities);
3257
- const extraInMsg = msgRootEntities.filter(r => !localRootSet.has(r));
3258
- let generatedCatalogRootSet = new Set();
3259
- try {
3260
- generatedCatalogRootSet = new Set(splitTrustedGeneratedCatalogRootMap(partitioned, generatedPrivateCatalogTripleKeys(contextGraphId)).generatedCatalogRootEntities);
3261
- }
3262
- catch {
3263
- generatedCatalogRootSet = new Set();
3264
- }
3265
- const missingInMsg = [...localRootSet].filter(r => !msgSet.has(r) && !generatedCatalogRootSet.has(r));
3266
- if (extraInMsg.length > 0 || missingInMsg.length > 0) {
3267
- this.log.warn(ctx, `Finalization: root entity set mismatch — extra in msg: [${extraInMsg.join(', ')}], missing: [${missingInMsg.join(', ')}]`);
3268
- }
3269
- }
3270
- const kaMetadata = [];
3271
- // GH #936 — assign per-root tokenIds over a CANONICAL (lexicographic) root
3272
- // order, NOT the SPARQL/gossip binding order. oxigraph binding order is
3273
- // store-history-dependent, so two replicas reconciling the same KC from
3274
- // chain would otherwise mint divergent root→tokenId maps. These tokenIds are
3275
- // local compatibility labels (the on-chain KA count is 1, no on-chain
3276
- // dependency — see dkg-publisher.ts), so a content-derived sort makes the
3277
- // map a pure function of the root SET: identical on every replica and on
3278
- // both the gossip and chain-reconcile promotion paths.
3279
- const orderedRoots = [...rootEntities].sort(compareRootIris);
3280
- for (let tokenIdx = 0; tokenIdx < orderedRoots.length; tokenIdx++) {
3281
- const rootEntity = orderedRoots[tokenIdx];
3282
- const entityQuads = partitioned.get(rootEntity) ?? [];
3283
- if (entityQuads.length === 0)
3284
- continue;
3285
- kaMetadata.push({
3286
- rootEntity,
3287
- kcUal: ual,
3288
- tokenId: BigInt(tokenIdx + 1),
3289
- publicTripleCount: entityQuads.length,
3290
- privateTripleCount: 0,
3291
- privateMerkleRoot: undefined,
3292
- });
3293
- }
3294
- const wsPeerId = await this.getPublisherPeerIdFromMeta(contextGraphId, msgRootEntities, subGraphName);
3295
- // Round 5 review §10 — propagate the on-chain-attested author into the
3296
- // confirmed `_meta` block so replicas emit a `prov:wasAttributedTo`
3297
- // matching the originator's. We treat `address(0)` (the
3298
- // unattributed-publish sentinel) as "no author" by skipping the field,
3299
- // so the legacy no-author behaviour is preserved verbatim. (The former
3300
- // `dkg:Publication` / `dkg:authoredBy` mirror was dropped — RFC
3301
- // ka-metadata-trim Phase 1, zero readers.)
3302
- const isUnattributed = !authorAddress
3303
- || authorAddress === '0x0000000000000000000000000000000000000000'
3304
- || authorAddress.toLowerCase() === '0x0000000000000000000000000000000000000000';
3305
- const kcMeta = {
3306
- ual,
3307
- contextGraphId,
3308
- merkleRoot,
3309
- publisherPeerId: wsPeerId || publisherAddress,
3310
- timestamp: new Date(),
3311
- subGraphName,
3312
- ...(isUnattributed
3313
- ? {}
3314
- : { authorAddress }),
3315
- };
3316
- let blockTimestamp = Math.floor(Date.now() / 1000);
3317
- if (this.chain && typeof this.chain.getBlockTimestamp === 'function') {
3318
- try {
3319
- blockTimestamp = await this.chain.getBlockTimestamp(blockNumber);
3320
- }
3321
- catch {
3322
- this.log.info(ctx, `Could not fetch block timestamp for block ${blockNumber}, using local time`);
3323
- }
3324
- }
3325
- const provenance = {
3326
- txHash,
3327
- blockNumber,
3328
- blockTimestamp,
3329
- publisherAddress,
3330
- batchId,
3331
- chainId: this.chain?.chainId ?? 'unknown',
3332
- };
3333
- // Remove any existing tentative status for this UAL before inserting
3334
- // confirmed metadata. Two graph locations can carry it on this replica:
3335
- // 1. Root `<cg>/_meta` — gossip-publish-handler ALWAYS writes
3336
- // `generateTentativeMetadata(...)` here (via `getTentativeStatusQuad`,
3337
- // which hardcodes the root `_meta` graph). This applies to every
3338
- // gossip-replicated KC regardless of `ctxGraphId` / dual-write mode.
3339
- // 2. Per-cgId `<cg>/context/<id>/_meta` — older code paths (and any
3340
- // future writer that respects the same partition split as canonical
3341
- // data) may park a tentative quad here when `ctxGraphId` is set.
3342
- //
3343
- // Codex r5 on PR #779: the previous form mutated `tentativeQuad.graph`
3344
- // to the per-cgId URI when `ctxGraphId` was set and deleted ONLY that
3345
- // copy. The root tentative survived. With the same-graph dual-write
3346
- // path (`keepRootCopyOnLabel === true`) we then re-inserted confirmed
3347
- // `_meta` into root `<cg>/_meta`, leaving `tentative` AND `confirmed`
3348
- // status quads coexisting on the same UAL in the root meta graph —
3349
- // label-scoped status reads were non-deterministic. Even on the
3350
- // `keepRootCopyOnLabel === false` path the leftover root tentative was
3351
- // wrong (the publisher had moved/dropped its root copy on remap).
3352
- //
3353
- // Fix: always queue the root tentative for deletion AND, when ctxGraphId
3354
- // is set, also queue the per-cgId variant. Single `store.delete` call so
3355
- // all stale tentative copies are reaped in one shot — `delete` no-ops on
3356
- // missing quads, so it's safe to enumerate both regardless of which
3357
- // writer actually populated them.
3358
- const rootTentativeQuad = getTentativeStatusQuad(ual, contextGraphId);
3359
- const tentativesToDelete = [rootTentativeQuad];
3360
- if (ctxGraphId) {
3361
- tentativesToDelete.push({
3362
- ...rootTentativeQuad,
3363
- graph: contextGraphMetaUri(contextGraphId, ctxGraphId),
3364
- });
3365
- }
3366
- try {
3367
- await this.store.delete(tentativesToDelete);
3368
- }
3369
- catch { /* tentative status may not exist */ }
3370
- let metaQuads = generateConfirmedFullMetadata(kcMeta, kaMetadata, provenance);
3371
- // GH #936 — append the SHARED deterministic per-root token rows (no-op for
3372
- // single-root). This is the SAME helper the publisher uses on the originator
3373
- // path, so a locally-published and a chain-reconciled multi-root KC expose
3374
- // an identical, queryable rootEntity→tokenId map. graph = the default
3375
- // `<cg>/_meta` so the ctxGraphId remap below routes them to the per-cgId
3376
- // `_meta` (and dual-writes a root copy when keepRootCopyOnLabel).
3377
- metaQuads.push(...buildDeterministicTokenRows(ual, kaMetadata, `did:dkg:context-graph:${contextGraphId}/_meta`));
3378
- if (ctxGraphId) {
3379
- const defaultMeta = `did:dkg:context-graph:${contextGraphId}/_meta`;
3380
- const targetMeta = contextGraphMetaUri(contextGraphId, ctxGraphId);
3381
- // Codex r3 on PR #779: the publisher's same-graph path keeps the
3382
- // confirmed `_meta` triples in BOTH the root `<cg>/_meta` and
3383
- // the per-cgId `<cg>/context/<cgId>/_meta` graphs (see the
3384
- // matching dual-write in `dkg-publisher.ts` ~line 1419, comment
3385
- // "on remap publishes the original copy at `<NAME>/_meta` is
3386
- // also moved; on same-graph publishes we leave the default copy
3387
- // in place"). Replicas were only writing the per-cgId copy, so
3388
- // label-only `_meta` reads (status / UAL / authoredBy lookups
3389
- // that don't know the on-chain id) diverged between publisher
3390
- // and recipients. Mirror the publisher's same-graph dual-write
3391
- // here too — gated on the same `keepRootCopyOnLabel` signal as
3392
- // the data-graph dual-write below, and folded into a single
3393
- // `store.insert` for the same retry-safety reason (`_meta`
3394
- // tentative→confirmed flip is supposed to be the durable point
3395
- // post-this-call; splitting the writes would re-introduce a
3396
- // partial-state window).
3397
- if (keepRootCopyOnLabel === true) {
3398
- const rootCopies = metaQuads
3399
- .filter((q) => q.graph === defaultMeta)
3400
- .map((q) => ({ ...q }));
3401
- const perCgIdCopies = metaQuads.map((q) => q.graph === defaultMeta ? { ...q, graph: targetMeta } : q);
3402
- metaQuads = [...perCgIdCopies, ...rootCopies];
3403
- }
3404
- else {
3405
- metaQuads = metaQuads.map((q) => q.graph === defaultMeta ? { ...q, graph: targetMeta } : q);
3406
- }
3407
- }
3408
- // #1233 follow-up — bound agents/_meta: this confirmed-metadata restatement
3409
- // is load-bearing (prior-root cleanup + the tentative→confirmed flip), so it
3410
- // cannot be skipped for the agents CG. INSERT then PRUNE (insert-first) via
3411
- // the helper: the just-inserted UAL is `recordUal` so the prune protects it,
3412
- // and a post-insert prune failure is swallowed (warned) inside the helper so
3413
- // it can never abort this promotion. agents/_meta
3414
- // stays O(agents), not O(agents × heartbeats); no-op prune for every other CG
3415
- // (so it just inserts). For the agents CG `ctxGraphId` is always undefined
3416
- // (never on-chain), so `metaQuads` land in the default `<cg>/_meta` graph —
3417
- // the graph bounded here.
3418
- // NOTE: the agents CG is always-tentative and never confirms on-chain, so in
3419
- // practice this promotion is not reached for it (see report); this is a
3420
- // defensive, lifecycle-preserving bound that keeps the invariant robust.
3421
- // The bound derives its lock + prune roots from `metaQuads` itself, so the
3422
- // dropped zero-public-triple roots (the `continue` above) are naturally excluded
3423
- // from the prune — it can only evict superseded records for roots THIS record
3424
- // covers, never zero a root the record omits. (Previously this call passed a
3425
- // separate rootEntities list, which risked exactly that drift.)
3426
- await insertBoundedAgentRegistryMeta({
3427
- store: this.store,
3428
- contextGraphId,
3429
- metaGraph: `did:dkg:context-graph:${contextGraphId}/_meta`,
3430
- recordUal: ual,
3431
- metadataQuads: metaQuads,
3432
- });
3433
- // Clean up promoted shared memory entries
3434
- const sharedMemoryGraph = subGraphName
3435
- ? graphManager.sharedMemoryUri(contextGraphId, subGraphName)
3436
- : contextGraphWorkspaceGraphUri(contextGraphId);
3437
- const swmMetaGraph = subGraphName
3438
- ? graphManager.sharedMemoryMetaUri(contextGraphId, subGraphName)
3439
- : contextGraphWorkspaceMetaGraphUri(contextGraphId);
3440
- // #1099: replicas hold the gossiped SWM copy in PER-KA graphs
3441
- // `…/_shared_memory/{author}/{number}` (workspace-handler.ts ~line 987),
3442
- // but this cleanup only drained the bare bucket. The stale per-KA copy
3443
- // survived every publish, kept being served to late subscribers via the
3444
- // PROTOCOL_SYNC SWM responder (which reads the whole `…/_shared_memory/`
3445
- // prefix), and re-poisoned even the publisher's own SWM on resync —
3446
- // publisher and replicas permanently disagreed about SWM content.
3447
- // Mirror DKGPublisher's `swmGraphsUnder`: drain the bucket AND every
3448
- // graph under its `/` prefix.
3449
- const allGraphs = await this.store.listGraphs();
3450
- const swmGraphsForClear = allGraphs.filter((g) => g === sharedMemoryGraph || g.startsWith(`${sharedMemoryGraph}/`));
3451
- for (const rootEntity of rootEntities) {
3452
- for (const g of swmGraphsForClear) {
3453
- await deleteByPatternWithoutCount(this.store, { graph: g, subject: rootEntity });
3454
- await this.store.deleteBySubjectPrefix(g, rootEntity + '/.well-known/genid/');
3455
- await deleteByPatternWithoutCount(this.store, {
3456
- graph: g, subject: rootEntity, predicate: 'http://dkg.io/ontology/workspaceOwner',
3457
- });
3458
- }
3459
- await deleteByPatternWithoutCount(this.store, {
3460
- graph: swmMetaGraph, subject: rootEntity, predicate: 'http://dkg.io/ontology/workspaceOwner',
3461
- });
3462
- await this.deleteMetaForRoot(swmMetaGraph, rootEntity);
3463
- }
3464
- // Canonical insert LAST — see the comment above `const canonicalQuads`.
3465
- // By the time any reader observes these quads in the canonical graph,
3466
- // `_meta` already carries `confirmed` status + chain provenance and the
3467
- // matching SWM entries have been drained.
3468
- //
3469
- // Codex r2 on PR #779: when same-graph dual-write is in play, both
3470
- // copies (per-cgId partition + root label graph) MUST land in a single
3471
- // `store.insert` so a crash or store-write failure between them
3472
- // cannot leave the replica with the per-cgId copy but no root copy.
3473
- // The previous split form would be skipped on retry by
3474
- // `isAlreadyConfirmed()` (`_meta` already confirmed) and the root
3475
- // copy would never be back-filled — a permanent label-scoped query
3476
- // miss on that replica. Folding both into one insert call ties their
3477
- // durability to the same store-write transaction (Oxigraph's `load`
3478
- // and SPARQL-backend bulk insert are both atomic at the call level).
3479
- const allCanonicalQuads = rootDataGraphForLabel
3480
- ? [
3481
- ...canonicalQuads,
3482
- ...canonicalQuads.map(q => ({ ...q, graph: rootDataGraphForLabel })),
3483
- ]
3484
- : canonicalQuads;
3485
- await this.store.insert(allCanonicalQuads);
3486
- this.log.info(ctx, `Promoted ${canonicalQuads.length} quads from shared memory to canonical for ${ual}`);
3487
- this.eventBus?.emit(DKGEvent.MEMORY_GRAPH_CHANGED, {
3488
- contextGraphId,
3489
- layers: ['swm', 'vm'],
3490
- subGraphName,
3491
- operation: 'verifiable_memory_finalized',
3492
- source: 'finalization',
3493
- counts: {
3494
- roots: rootEntities.length,
3495
- triples: canonicalQuads.length,
3496
- },
3497
- });
3498
- }
3499
- async deleteMetaForRoot(metaGraph, rootEntity) {
3500
- const result = await this.store.query(`SELECT DISTINCT ?op WHERE { GRAPH <${assertSafeIri(metaGraph)}> { ?op ${ENTITY_PRED_ALT} <${assertSafeIri(rootEntity)}> } }`, { source: 'agent.finalization.rootMetadataOperations' });
3501
- if (result.type !== 'bindings')
3502
- return;
3503
- for (const row of result.bindings) {
3504
- const op = row['op'];
3505
- if (!op)
3506
- continue;
3507
- // OT-RFC-43 §10.1 — dual-write migration: remove BOTH the legacy
3508
- // dkg:rootEntity and the new dkg:entity for this op/entity pair.
3509
- await this.store.delete([
3510
- { subject: op, predicate: DKG_ROOT_ENTITY_LEGACY, object: rootEntity, graph: metaGraph },
3511
- { subject: op, predicate: DKG_ENTITY, object: rootEntity, graph: metaGraph },
3512
- ]);
3513
- const remaining = await this.store.query(`SELECT (COUNT(DISTINCT ?r) AS ?c) WHERE { GRAPH <${assertSafeIri(metaGraph)}> { <${assertSafeIri(op)}> ${ENTITY_PRED_ALT} ?r } }`, { source: 'agent.finalization.remainingOperationRoots' });
3514
- const rawCount = remaining.type === 'bindings' && remaining.bindings[0]?.['c'];
3515
- const countVal = typeof rawCount === 'string'
3516
- ? Number(rawCount.replace(/^"/, '').replace(/"(\^\^<[^>]+>)?$/, ''))
3517
- : NaN;
3518
- if (countVal === 0) {
3519
- await deleteByPatternWithoutCount(this.store, { graph: metaGraph, subject: op });
3520
- }
3521
- }
3522
- }
3523
1965
  }
3524
1966
  //# sourceMappingURL=finalization-handler.js.map