chainlesschain 0.166.17 → 0.166.18

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 (210) hide show
  1. package/README.md +14 -7
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-CVW2n2rh.js → AIOps-CQSBl3hY.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-DtuM163O.js → ActionButton-IQt-vRLt.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-BXvl_qHu.js → Analytics-DkHC8O7k.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-VDBTFKOp.js → AppLayout-CSti2P2T.js} +3 -3
  7. package/src/assets/web-panel/assets/{Artifacts-BNz2xCiG.js → Artifacts-C57hxn3v.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DTu9Hn9P.js → Audit-DByLntcf.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-D2OCPzLe.js → BackgroundAgents-D1Bd2EOa.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-C9M-vG7G.js → Backup-VstHzHng.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-BUkCNiUQ.js → BaseInput-CLhdexIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-OJ2ajF7l.js → Chat-BefC_JZS.js} +6 -6
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BdZt76Ab.js → ChatBubbleRenderer-DbXMvgmn.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-C1gXKDsc.js → Checkbox-CEY982vx.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-BXbznLg7.js → Codegen-Dcm_DTvJ.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-CbCq5N0i.js → Col-C8SSu4KA.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-V8Ks6Yun.js → Community-BVV9vwRR.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DkeHQTpQ.js → Compact-B7c5Vo18.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-JeLKwn4Q.js → Compliance-Tq9jSZ5a.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-azfetcBz.js → Cowork-BJUjT09Q.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-Q691i_Gp.js → Cron-CjV9PEaS.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-BLjDRbr_.js → Crosschain-Dl7ReL8F.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D8ptXplK.js → DID-CG8PjWmM.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-Ctj2VVZL.js → Dashboard-CDBM6wmF.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-D8VgkMJ8.js → Dropdown-8_55bXTD.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-CQPe5S6q.js → EmailListRenderer-D3qOU1Cm.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-ySA-7SiN.js → FamilyGuardDashboard-Bv5oWMZF.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-1PMD-fBf.js → Federation-hpZ1xkKd.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-C_jr6U4Q.js → FormItemContext-BN7GT191.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-Bu3bKf2B.js → GenericCardRenderer-PCRhfA7M.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Dv4Fa_T5.js → Git-CIlP2vy7.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-DOEy1n1k.js → Governance-81lgm7YL.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-DkvqzWcJ.js → Inference-Cs24xMOV.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-DdUJK949.js → KnowledgeGraph-CrJLVCZo.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-CRelcdUZ.js → Logs-DLyO8RKT.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-0AHbbTA4.js → MarkdownRenderer-DBOqijrP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BuuBKsev.js → Marketplace-Dz7AbQZc.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DlgpEmA1.js → McpTools-BM0aFiWv.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-DTfdqUGy.js → Memory-C9SJzENX.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-CXLE5ZFO.js → MobileBridge-BO2HnNRk.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-Dz25OB0n.js → MobileProjects-CK_jMz0l.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-kEL0fhgD.js → Mtc-CfhrJsdO.js} +2 -2
  43. package/src/assets/web-panel/assets/{MtcAudit-BE4UvFJU.js → MtcAudit-BE2ELxgI.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-CSApSn8c.js → Multisig-CgR_E3Jd.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-D11FpKWx.js → NLProgramming-Cw9445_K.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-CDL-D2CS.js → Notes-DZimkTrb.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-C0Q6lO-c.js → NotificationSettings-DxHVh4uT.js} +1 -1
  48. package/src/assets/web-panel/assets/OrderTableRenderer-Iy-pnX56.js +1 -0
  49. package/src/assets/web-panel/assets/{Organization-Dc-maVAq.js → Organization-pPXJtWo4.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-B5mUpSvi.js → Overflow-YamdTJwA.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-TjXV53wq.js → P2P-BvqP53x7.js} +2 -2
  52. package/src/assets/web-panel/assets/PdhVaultBrowser-Blz1Xn2n.js +7 -0
  53. package/src/assets/web-panel/assets/{Permissions-DKRzQ2O6.js → Permissions-CgFRQqFJ.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-Dx2eqft8.js → PersonalDataHub-CFeo3-6O.js} +4 -4
  55. package/src/assets/web-panel/assets/{Pipeline-CnYZMB5p.js → Pipeline-BkaRojEK.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-BonKpPnp.js → Privacy-BNZEx2Qp.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-DWO0Du3J.js → ProjectInit-HUBOgEEK.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-C9jqyYRv.js → ProjectSettings-CFMmhROS.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-CYpKwXbz.js → Projects-Dc517BXp.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-CW-fkwJq.js → Providers-DTLf8bgj.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-Cw0J3Zud.js → QrScannerModal-BBNjPszk.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-BH4A4IpR.js → QuickAsk-DCsHvk3G.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-CDwMwJus.js → Recommend-Dpr5YSop.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-DKIPwzTf.js → RemoteSession-DmKnvqGg.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-CklDj7qS.js → Reputation-CSRfuurX.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-DJWZKsH0.js → Row-CDj3pQ_w.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-BfSLCewo.js → RssFeed-DI0a_kNq.js} +2 -2
  68. package/src/assets/web-panel/assets/{Search-B0IST--x.js → Search-jAy7B2nU.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-h1sYNWtt.js → Security-CkHTqYhc.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-Gh0-oxI_.js → Services-CP-0Nzga.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-CNDV_jOs.js → Skeleton-BkF5-p3n.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-ByCLTh1n.js → Skills-BDu-utDE.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-BfyrJTJz.js → Sla-CQvq_2Qb.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-BQzo9kNX.js → SpeechSettings-T7Ap512g.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-B6fS6z_1.js → SyncSettings-Bt-PLvot.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-C-uKCP-l.js → Tasks-yLEcCogg.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-D6oDy7wL.js → Templates-ByN3fmbr.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-D3LT2wNQ.js → Tenant-DBI7hITH.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-BteLcv_O.js → Terminal-B77_DlGX.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-DHHuxfqH.js → TimelineRenderer-CsLTB_QO.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BRQeykXw.js → Tokens-BV2N6cR8.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-p2XaFWEu.js → Trigger-CjXWGH3p.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-BxadBMft.js → Trust-uqXIq3WC.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-DRBP7LDk.js → UkeySign-D-6qu4vY.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-CZ3NZkh7.js → VideoEditing-CxGmx_2e.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-C3NTBN7G.js → Wallet-DSq7WlAg.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-C7LVgMlb.js → WebAuthn-CDBiD57O.js} +2 -2
  88. package/src/assets/web-panel/assets/{WorkflowEditor-0_Iveog7.js → WorkflowEditor-Z8f63TSb.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DzzluYo3.js → chat-B-UZFBjy.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DSMYXpaj.js → colors-CFk7K-7Q.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-W76u1VSV.js → compact-item-X0IVMvgi.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-otsESjb5.js → createContext-DWg4j2n6.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-B2IW1J_J.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-3sNLrvug.js → hasIn-CkVCwNNF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BdtmEKat.js → index-5OcZHdzc.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DS9WYDMf.js → index-B273IY-E.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-NaO9AE-F.js → index-B3-B3FWD.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BcGJtmHM.js → index-BB4KHHcv.js} +1 -1
  99. package/src/assets/web-panel/assets/index-BCp2ir-1.js +1 -0
  100. package/src/assets/web-panel/assets/{index-pVm_iUre.js → index-BG-GaZri.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BpcQYzP7.js → index-BPBia4b-.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BXLx9HfA.js → index-BipwEbTA.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-uSCkbpZH.js → index-BoskgPt9.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DMmdIpLA.js → index-Btqk6zWb.js} +1 -1
  105. package/src/assets/web-panel/assets/index-Bw4iuzRD.js +1 -0
  106. package/src/assets/web-panel/assets/{index-DLDh1OW3.js → index-BzXjYUmd.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-B9X_jqXe.js → index-C1ZAOJRW.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-vBKPcmAP.js → index-CCLwoATF.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-vUmYkqmu.js → index-CDfSD07S.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D7A5U2IH.js → index-CLlP1E4X.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-ClOFeZ-t.js → index-CMCEXBRh.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Cg86EzNp.js → index-CN8HZlLH.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Ddd4mird.js → index-CNKFsBlz.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CE7tSow-.js → index-CUBkvFPH.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-GlIOE4ja.js → index-Ca0mij1n.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DdU7IkKX.js → index-CbIAWbma.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-UUHCwfNq.js → index-CbihMThv.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BRsD1PT2.js → index-CvOa-IFV.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-C2aht9-M.js → index-Cvwu_rA_.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BJsQio5O.js → index-D-EJNxgR.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-q7ftLqNt.js → index-D8uEL8Uw.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B1I1AYJs.js → index-D92g4l3n.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DZKAzEge.js → index-DCqpl_E_.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CKoFyHYQ.js → index-DLSBks8h.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BDlDO2px.js → index-Db_5xhrU.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CENWwjef.js → index-DcDggpWR.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DH4cl52p.js → index-DeWKPQGs.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DTA8Iavv.js → index-DhVHoqGL.js} +3 -3
  129. package/src/assets/web-panel/assets/{index-DmpaC2yk.js → index-DyWlOuak.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BA8mZxd-.js → index-LU54bChK.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CtFOt5x1.js → index-OjnAwUJo.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B5LOYdYm.js → index-P83LDnCz.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-MhQQ3h8q.js → index-_-9k3Tna.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DF6llUXV.js → initDefaultProps-CFNgY8lJ.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-vtDV8_5K.js → motion-D-5RrDzn.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-B6c0bdy2.js → move-DN-L0Bd-.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-DlLYWuBK.js → mtc-parser-6mgLSeCK.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BH0zOxLN.js → omit-ClWW8eTP.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-D9di8_In.js → pickAttrs-Vystq3R8.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-BDSngufM.js → placementArrow-D0H9hK4W.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-C_EawMvP.js → responsiveObserve-B3iNRU-a.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-B_4wShxA.js → slide-CiMXe6am.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-CbQu6qJ-.js → statusUtils-CGDZJ1uT.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-CvXJWYXb.js → styleChecker-D2zA6NkY.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-jjY1XknO.js → useFlexGapSupport-C1sYU6QE.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-CMXBdsK_.js → useFs-BzUHSjg2.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-YbAhhPXx.js → usePersonalDataHub-CxB5yZCq.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BFCTKc0H.js → vnode-BfUfMwtc.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CY9aBl5O.js → zoom-CFYmj1TO.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +1 -1
  152. package/src/commands/agent.js +80 -2
  153. package/src/commands/evolution.js +33 -27
  154. package/src/commands/serve.js +11 -2
  155. package/src/data/changelog.json +5 -5
  156. package/src/gateways/ws/session-protocol.js +1 -0
  157. package/src/gateways/ws/ws-agent-handler.js +70 -2
  158. package/src/gateways/ws/ws-server.js +8 -0
  159. package/src/lib/app-server/cli-agent-kernel-adapter.js +4 -0
  160. package/src/lib/app-server/graph-runtime.js +115 -8
  161. package/src/lib/app-server/server.js +21 -2
  162. package/src/lib/app-server/websocket-transport.js +2 -0
  163. package/src/lib/evolution/agent-evolution-ingress.js +300 -0
  164. package/src/lib/evolution/agent-evolution-runtime-composition-brand.js +22 -0
  165. package/src/lib/evolution/agent-evolution-runtime-composition.js +369 -0
  166. package/src/lib/evolution/evidence-backed-wiki-maintainer.js +752 -0
  167. package/src/lib/evolution/evolution-artifact-ports.js +48 -0
  168. package/src/lib/evolution/evolution-eval-gate.js +11 -4
  169. package/src/lib/evolution/evolution-evidence-artifact-adapter.js +499 -0
  170. package/src/lib/evolution/evolution-evidence-projector.js +61 -1
  171. package/src/lib/evolution/evolution-file-witness.js +601 -0
  172. package/src/lib/evolution/evolution-ledger-file-backend.js +176 -0
  173. package/src/lib/evolution/evolution-ledger-ports.js +353 -16
  174. package/src/lib/evolution/evolution-ledger.js +1355 -54
  175. package/src/lib/evolution/evolution-run-ledger-adapter.js +409 -0
  176. package/src/lib/evolution/evolution-run-wiki-maintenance-source.js +300 -0
  177. package/src/lib/evolution/scheduled-batch-wiki-maintenance-source.js +368 -0
  178. package/src/lib/evolution/skill-candidate-registry.js +649 -0
  179. package/src/lib/evolution/skill-promotion-controller.js +109 -38
  180. package/src/lib/evolution/skill-promotion-review-ledger-adapter.js +451 -0
  181. package/src/lib/evolution/skill-promotion-review.js +793 -0
  182. package/src/lib/evolution/skill-registry-transition-capability.js +55 -0
  183. package/src/lib/evolution/skill-registry-transition-ledger-adapter.js +1280 -0
  184. package/src/lib/evolution/skill-registry-transition-source.js +372 -0
  185. package/src/lib/evolution/skill-release-registry.js +2191 -11
  186. package/src/lib/evolution/skill-target-matrix-eval.js +133 -10
  187. package/src/lib/evolution/structured-memory-agent-control-plane.js +222 -0
  188. package/src/lib/evolution/structured-memory-authority-ledger-adapter.js +351 -0
  189. package/src/lib/evolution/structured-memory-ledger-adapter.js +220 -0
  190. package/src/lib/evolution/structured-memory-policy-receipt-writer.js +164 -0
  191. package/src/lib/evolution/structured-memory-post-compact-hook.js +87 -0
  192. package/src/lib/evolution/structured-memory-promotion-receipt-writer.js +221 -0
  193. package/src/lib/evolution/structured-memory-semantic-review-pipeline.js +313 -0
  194. package/src/lib/evolution/wiki-maintainer-ledger-adapter.js +200 -0
  195. package/src/lib/evolution/wiki-maintenance-trigger-ledger-adapter.js +687 -0
  196. package/src/lib/evolution-system.js +65 -30
  197. package/src/lib/mcp-lifecycle-authority.js +21 -2
  198. package/src/lib/remote-approval-bridge.js +24 -0
  199. package/src/lib/scheduler-kernel/store.js +62 -14
  200. package/src/repl/agent-repl.js +45 -0
  201. package/src/runtime/agent-runtime.js +114 -1
  202. package/src/runtime/headless-runner.js +19 -0
  203. package/src/runtime/headless-stream.js +43 -0
  204. package/src/runtime/runtime-factory.js +19 -1
  205. package/src/assets/web-panel/assets/OrderTableRenderer-ZRE0OKbj.js +0 -1
  206. package/src/assets/web-panel/assets/PdhVaultBrowser-DvV2btIr.js +0 -7
  207. package/src/assets/web-panel/assets/devWarning-BztaXF84.js +0 -1
  208. package/src/assets/web-panel/assets/index-4jP_hG_4.js +0 -1
  209. package/src/assets/web-panel/assets/index-zxwuAXL5.js +0 -1
  210. package/src/lib/learning/learning-hooks.js +0 -123
@@ -0,0 +1,176 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createEvolutionFileWitness } from "./evolution-file-witness.js";
4
+ import { EvolutionLedger } from "./evolution-ledger.js";
5
+
6
+ export const EVOLUTION_LEDGER_FILE_BACKEND_SCHEMA =
7
+ "chainlesschain.evolution-ledger-file-backend/v1";
8
+
9
+ const BACKENDS = new WeakSet();
10
+
11
+ function requiredString(value, label) {
12
+ if (typeof value !== "string" || value.trim() === "") {
13
+ throw new TypeError(`${label} is required`);
14
+ }
15
+ return value;
16
+ }
17
+
18
+ function capture(owner, name, label) {
19
+ if (typeof owner?.[name] !== "function") {
20
+ throw new TypeError(`${label}.${name} port is required`);
21
+ }
22
+ const operation = owner[name].bind(owner);
23
+ return Object.freeze((...args) => operation(...args));
24
+ }
25
+
26
+ function normalizeAuthority(value, label) {
27
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
28
+ throw new TypeError(`${label} authority is required`);
29
+ }
30
+ const trust = value.trust;
31
+ return Object.freeze({
32
+ trust,
33
+ signerIdentity: value.signer,
34
+ verifierIdentity: value.verifier,
35
+ sign: capture(value.signer, "sign", `${label}.signer`),
36
+ verify: capture(value.verifier, "verify", `${label}.verifier`),
37
+ });
38
+ }
39
+
40
+ function contained(parent, candidate) {
41
+ const relative = path.relative(parent, candidate);
42
+ return (
43
+ relative === "" ||
44
+ (!relative.startsWith(`..${path.sep}`) &&
45
+ relative !== ".." &&
46
+ !path.isAbsolute(relative))
47
+ );
48
+ }
49
+
50
+ function assertIndependentStorage(rootDir, authorityRootDir, witnessFilePath) {
51
+ const eventRoot = path.resolve(rootDir);
52
+ const authorityRoot = path.resolve(authorityRootDir);
53
+ const witnessPath = path.resolve(witnessFilePath);
54
+ if (
55
+ contained(eventRoot, authorityRoot) ||
56
+ contained(authorityRoot, eventRoot) ||
57
+ contained(eventRoot, witnessPath) ||
58
+ contained(authorityRoot, witnessPath)
59
+ ) {
60
+ throw new Error(
61
+ "event, authority, and witness storage must be independent and non-overlapping",
62
+ );
63
+ }
64
+ return Object.freeze({ eventRoot, authorityRoot, witnessPath });
65
+ }
66
+
67
+ function assertIndependentAuthorities(ledgerAuthority, witnessAuthority) {
68
+ const ledgerTrust = ledgerAuthority.trust;
69
+ const witnessTrust = witnessAuthority.trust;
70
+ if (
71
+ !ledgerTrust ||
72
+ !witnessTrust ||
73
+ ledgerAuthority.signerIdentity === witnessAuthority.signerIdentity ||
74
+ ledgerAuthority.verifierIdentity === witnessAuthority.verifierIdentity ||
75
+ ledgerTrust === witnessTrust ||
76
+ ledgerTrust.keyId === witnessTrust.keyId ||
77
+ ledgerTrust.trustPolicyDigest === witnessTrust.trustPolicyDigest
78
+ ) {
79
+ throw new Error(
80
+ "ledger and witness must use independent trust, signer, verifier, keyId, and policy roots",
81
+ );
82
+ }
83
+ }
84
+
85
+ export function createEvolutionLedgerFileBackend({
86
+ rootDir,
87
+ authorityRootDir,
88
+ witnessFilePath,
89
+ witnessId,
90
+ ledgerAuthority: ledgerAuthorityInput,
91
+ witnessAuthority: witnessAuthorityInput,
92
+ artifactResolver,
93
+ secure = true,
94
+ fsImpl = fs,
95
+ clock = Date.now,
96
+ lockClock = Date.now,
97
+ random,
98
+ lock,
99
+ lockTimeoutMs,
100
+ crashHook = null,
101
+ witnessMaximumBytes,
102
+ } = {}) {
103
+ if (typeof artifactResolver !== "function") {
104
+ throw new TypeError("artifactResolver port is required");
105
+ }
106
+ const paths = assertIndependentStorage(
107
+ requiredString(rootDir, "rootDir"),
108
+ requiredString(authorityRootDir, "authorityRootDir"),
109
+ requiredString(witnessFilePath, "witnessFilePath"),
110
+ );
111
+ const ledgerAuthority = normalizeAuthority(
112
+ ledgerAuthorityInput,
113
+ "ledgerAuthority",
114
+ );
115
+ const witnessAuthority = normalizeAuthority(
116
+ witnessAuthorityInput,
117
+ "witnessAuthority",
118
+ );
119
+ assertIndependentAuthorities(ledgerAuthority, witnessAuthority);
120
+
121
+ const witnessOptions = {
122
+ id: requiredString(witnessId, "witnessId"),
123
+ filePath: paths.witnessPath,
124
+ trust: witnessAuthority.trust,
125
+ signer: { sign: witnessAuthority.sign },
126
+ verifier: { verify: witnessAuthority.verify },
127
+ fsImpl,
128
+ ...(lock === undefined ? {} : { lock }),
129
+ ...(random === undefined ? {} : { random }),
130
+ ...(witnessMaximumBytes === undefined
131
+ ? {}
132
+ : { maximumBytes: witnessMaximumBytes }),
133
+ };
134
+ const witness = createEvolutionFileWitness(witnessOptions);
135
+ const ledger = new EvolutionLedger({
136
+ rootDir: paths.eventRoot,
137
+ authorityRootDir: paths.authorityRoot,
138
+ secure,
139
+ fsImpl,
140
+ clock,
141
+ lockClock,
142
+ trust: ledgerAuthority.trust,
143
+ sign: ledgerAuthority.sign,
144
+ verifySignature: ledgerAuthority.verify,
145
+ verifyWitnessSignature: witnessAuthority.verify,
146
+ artifactResolver,
147
+ witness,
148
+ witnessTrust: witnessAuthority.trust,
149
+ ...(random === undefined ? {} : { random }),
150
+ ...(lock === undefined ? {} : { lock }),
151
+ ...(lockTimeoutMs === undefined ? {} : { lockTimeoutMs }),
152
+ crashHook,
153
+ });
154
+ const backend = Object.freeze({
155
+ schema: EVOLUTION_LEDGER_FILE_BACKEND_SCHEMA,
156
+ descriptor: Object.freeze({
157
+ rootDir: paths.eventRoot,
158
+ authorityRootDir: paths.authorityRoot,
159
+ witnessFilePath: paths.witnessPath,
160
+ witnessId: witness.id,
161
+ ledgerTrust: Object.freeze({ ...ledgerAuthority.trust }),
162
+ witnessTrust: Object.freeze({ ...witnessAuthority.trust }),
163
+ }),
164
+ ledger,
165
+ witness,
166
+ });
167
+ BACKENDS.add(backend);
168
+ return backend;
169
+ }
170
+
171
+ export function captureEvolutionLedgerFileBackend(value) {
172
+ if (!BACKENDS.has(value)) {
173
+ throw new TypeError("a branded EvolutionLedger file backend is required");
174
+ }
175
+ return value;
176
+ }
@@ -31,7 +31,13 @@ import {
31
31
  verifySkillMutationNonceClaim,
32
32
  verifySkillMutationRequest,
33
33
  } from "./skill-mutation-authority.js";
34
- import { SKILL_RELEASE_LEDGER_PROJECTION_SCHEMA } from "./skill-release-registry.js";
34
+ import {
35
+ SKILL_RELEASE_LEDGER_PROJECTION_SCHEMA,
36
+ SKILL_RELEASE_STATE_LEDGER_MIGRATION_SCHEMA,
37
+ SKILL_RELEASE_STATE_MIGRATION_RECEIPT_SCHEMA,
38
+ verifySkillReleaseState,
39
+ verifySkillReleaseStateMigrationPlan,
40
+ } from "./skill-release-registry.js";
35
41
 
36
42
  export const EVOLUTION_LEDGER_PORTS_INVALID_CODE =
37
43
  "CC_EVOLUTION_LEDGER_PORTS_INVALID";
@@ -61,27 +67,33 @@ const PROJECTION_PREPARE_RECEIPT_DOMAIN =
61
67
  "chainlesschain.evolution-ledger-release-prepare-projection/v1\0";
62
68
  const PROJECTION_FINALIZE_RECEIPT_DOMAIN =
63
69
  "chainlesschain.evolution-ledger-release-finalize-projection/v1\0";
70
+ const PROJECTION_MIGRATION_RECEIPT_DOMAIN =
71
+ "chainlesschain.evolution-ledger-release-migration-projection/v1\0";
64
72
  const EVENT_ID_DOMAINS = Object.freeze({
65
73
  audit: "chainlesschain.evolution-ledger-event-id/mutation.audit/v1\0",
66
74
  finalize: "chainlesschain.evolution-ledger-event-id/release.finalize/v1\0",
75
+ migration: "chainlesschain.evolution-ledger-event-id/release.migration/v1\0",
67
76
  nonce: "chainlesschain.evolution-ledger-event-id/mutation.nonce/v1\0",
68
77
  prepare: "chainlesschain.evolution-ledger-event-id/release.prepare/v1\0",
69
78
  });
70
79
  const EVENT_PREFIXES = Object.freeze({
71
80
  audit: "mutation.audit",
72
81
  finalize: "release.finalize",
82
+ migration: "release.migration",
73
83
  nonce: "mutation.nonce",
74
84
  prepare: "release.prepare",
75
85
  });
76
86
  const EVENT_TYPES = Object.freeze({
77
87
  audit: "skill.mutation.audit",
78
88
  finalize: "skill.release.finalize",
89
+ migration: "skill.release.state-migration",
79
90
  nonce: "skill.mutation.nonce",
80
91
  prepare: "skill.release.prepare",
81
92
  });
82
93
  const ARTIFACT_TYPES = Object.freeze({
83
94
  audit: "skill-mutation-audit",
84
95
  finalize: "skill-release-finalization",
96
+ migration: "skill-release-state-migration",
85
97
  nonce: "skill-mutation-nonce-claim",
86
98
  prepare: "skill-release-transition-intent",
87
99
  });
@@ -216,6 +228,17 @@ const FINALIZE_KEYS = new Set([
216
228
  "stateDigest",
217
229
  "transactionId",
218
230
  ]);
231
+ const STATE_MIGRATION_KEYS = new Set(["plan", "receipt", "schema", "state"]);
232
+ const STATE_MIGRATION_RECEIPT_KEYS = new Set([
233
+ "authenticated",
234
+ "authorityId",
235
+ "durable",
236
+ "handlerArtifactDigest",
237
+ "receiptDigest",
238
+ "schema",
239
+ "stateMigrationDigest",
240
+ "trust",
241
+ ]);
219
242
  const RECEIPT_DIGEST_KEYS = new Set([
220
243
  "actor",
221
244
  "candidate",
@@ -995,6 +1018,86 @@ function normalizeFinalize(input) {
995
1018
  return normalized;
996
1019
  }
997
1020
 
1021
+ function normalizeStateMigration(input) {
1022
+ const value = frozenCanonicalClone(input);
1023
+ assertAllExactRecord(
1024
+ value,
1025
+ STATE_MIGRATION_KEYS,
1026
+ "release state ledger migration",
1027
+ );
1028
+ if (value.schema !== SKILL_RELEASE_STATE_LEDGER_MIGRATION_SCHEMA) {
1029
+ throw portsError(
1030
+ EVOLUTION_LEDGER_PORTS_INVALID_CODE,
1031
+ "release state ledger migration schema is unsupported",
1032
+ );
1033
+ }
1034
+ let plan;
1035
+ let state;
1036
+ try {
1037
+ plan = verifySkillReleaseStateMigrationPlan(value.plan);
1038
+ state = verifySkillReleaseState(value.state);
1039
+ } catch (cause) {
1040
+ throw portsError(
1041
+ EVOLUTION_LEDGER_PORTS_INVALID_CODE,
1042
+ "release state ledger migration contains an invalid plan or state",
1043
+ { cause },
1044
+ );
1045
+ }
1046
+ assertAllExactRecord(
1047
+ value.receipt,
1048
+ STATE_MIGRATION_RECEIPT_KEYS,
1049
+ "release state migration receipt",
1050
+ );
1051
+ const receipt = deepFreeze({
1052
+ authenticated: value.receipt.authenticated,
1053
+ authorityId: identifier(
1054
+ value.receipt.authorityId,
1055
+ "state migration receipt authorityId",
1056
+ ),
1057
+ durable: value.receipt.durable,
1058
+ handlerArtifactDigest: digest(
1059
+ value.receipt.handlerArtifactDigest,
1060
+ "state migration receipt handlerArtifactDigest",
1061
+ ),
1062
+ receiptDigest: digest(
1063
+ value.receipt.receiptDigest,
1064
+ "state migration receipt receiptDigest",
1065
+ ),
1066
+ schema: value.receipt.schema,
1067
+ stateMigrationDigest: digest(
1068
+ value.receipt.stateMigrationDigest,
1069
+ "state migration receipt stateMigrationDigest",
1070
+ ),
1071
+ trust: value.receipt.trust,
1072
+ });
1073
+ if (
1074
+ receipt.schema !== SKILL_RELEASE_STATE_MIGRATION_RECEIPT_SCHEMA ||
1075
+ receipt.authenticated !== true ||
1076
+ receipt.durable !== true ||
1077
+ receipt.trust !== "trusted" ||
1078
+ receipt.stateMigrationDigest !== plan.stateMigrationDigest ||
1079
+ state.transactionId !== plan.stateMigrationDigest ||
1080
+ state.tenantId !== plan.tenantId ||
1081
+ state.skillName !== plan.skillName ||
1082
+ state.activeReleaseDigest !== plan.activeReleaseDigest ||
1083
+ state.lastKnownGoodReleaseDigest !== plan.lastKnownGoodReleaseDigest ||
1084
+ state.dependencyLockDigest !== plan.dependencyLockDigest ||
1085
+ state.revision !== plan.legacyRevision ||
1086
+ state.fence !== plan.legacyFence
1087
+ ) {
1088
+ throw portsError(
1089
+ EVOLUTION_LEDGER_PORTS_INVALID_CODE,
1090
+ "release state ledger migration bindings are invalid",
1091
+ );
1092
+ }
1093
+ return deepFreeze({
1094
+ plan,
1095
+ receipt,
1096
+ schema: SKILL_RELEASE_STATE_LEDGER_MIGRATION_SCHEMA,
1097
+ state,
1098
+ });
1099
+ }
1100
+
998
1101
  function logicalFinalizeDigest(value) {
999
1102
  return domainDigest(RELEASE_FINALIZATION_DOMAIN, value);
1000
1103
  }
@@ -1011,12 +1114,13 @@ function projectionReceiptDigest(kind, projection) {
1011
1114
  const core = { ...projection };
1012
1115
  delete core.current;
1013
1116
  delete core.receiptDigest;
1014
- return domainDigest(
1117
+ const domain =
1015
1118
  kind === "prepare"
1016
1119
  ? PROJECTION_PREPARE_RECEIPT_DOMAIN
1017
- : PROJECTION_FINALIZE_RECEIPT_DOMAIN,
1018
- core,
1019
- );
1120
+ : kind === "migration"
1121
+ ? PROJECTION_MIGRATION_RECEIPT_DOMAIN
1122
+ : PROJECTION_FINALIZE_RECEIPT_DOMAIN;
1123
+ return domainDigest(domain, core);
1020
1124
  }
1021
1125
 
1022
1126
  class EvolutionLedgerDomainPorts {
@@ -1845,6 +1949,80 @@ class EvolutionLedgerDomainPorts {
1845
1949
  });
1846
1950
  }
1847
1951
 
1952
+ #migrationFromEvent(event, record, expected = null) {
1953
+ const migration = normalizeStateMigration(record.value);
1954
+ const eventId = deterministicEventId("migration", {
1955
+ transactionId: migration.plan.stateMigrationDigest,
1956
+ });
1957
+ const sourceRefs = this.#assertDomainEvent(
1958
+ event,
1959
+ "migration",
1960
+ eventId,
1961
+ migration.plan.stateMigrationDigest,
1962
+ );
1963
+ if (
1964
+ sourceRefs.length !== 0 ||
1965
+ event.decision !== "committed" ||
1966
+ event.correlationId !== migration.plan.stateMigrationDigest ||
1967
+ event.tenantId !== migration.plan.tenantId ||
1968
+ event.skillName !== migration.plan.skillName ||
1969
+ record.audience !== this.#audience
1970
+ ) {
1971
+ throw portsError(
1972
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
1973
+ "release state migration event differs from its authenticated plan",
1974
+ );
1975
+ }
1976
+ if (
1977
+ expected !== null &&
1978
+ (expected.transactionId !== migration.plan.stateMigrationDigest ||
1979
+ (expected.stateDigest !== undefined &&
1980
+ expected.stateDigest !== migration.state.stateDigest))
1981
+ ) {
1982
+ throw portsError(
1983
+ EVOLUTION_LEDGER_PORTS_COLLISION_CODE,
1984
+ "release state migration collides with another state baseline",
1985
+ );
1986
+ }
1987
+ return { event, migration, record };
1988
+ }
1989
+
1990
+ #migrationFromSnapshot(snapshot, event, expected = null) {
1991
+ const record = this.#snapshotSubject(
1992
+ snapshot,
1993
+ event,
1994
+ ARTIFACT_TYPES.migration,
1995
+ );
1996
+ return this.#migrationFromEvent(event, record, expected);
1997
+ }
1998
+
1999
+ #migrationProjection(migrated, current) {
2000
+ const { plan, receipt, state } = migrated.migration;
2001
+ const core = {
2002
+ authenticated: true,
2003
+ authorityReceiptDigest: state.authorityReceiptDigest,
2004
+ current,
2005
+ durable: true,
2006
+ epoch: migrated.event.epoch,
2007
+ headDigest: migrated.event.eventDigest,
2008
+ intentDigest: plan.stateMigrationDigest,
2009
+ ledgerId: migrated.event.ledgerId,
2010
+ pointerDigest: state.stateDigest,
2011
+ prepareReceiptDigest: receipt.receiptDigest,
2012
+ revision: state.revision,
2013
+ schema: SKILL_RELEASE_LEDGER_PROJECTION_SCHEMA,
2014
+ sequence: migrated.event.sequence,
2015
+ skillName: state.skillName,
2016
+ stateDigest: state.stateDigest,
2017
+ status: "committed",
2018
+ transactionId: state.transactionId,
2019
+ };
2020
+ return deepFreeze({
2021
+ ...core,
2022
+ receiptDigest: projectionReceiptDigest("migration", core),
2023
+ });
2024
+ }
2025
+
1848
2026
  #finalizeFromEvent(snapshot, event, prepareCache = new Map()) {
1849
2027
  const record = this.#snapshotSubject(
1850
2028
  snapshot,
@@ -1917,6 +2095,30 @@ class EvolutionLedgerDomainPorts {
1917
2095
  #lineages(snapshot, prepareCache = new Map()) {
1918
2096
  const groups = new Map();
1919
2097
  const byTransaction = new Map();
2098
+ const migrations = new Map();
2099
+ const migrationsByTransaction = new Map();
2100
+ for (const event of snapshot.events) {
2101
+ if (
2102
+ event.schema !== EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA ||
2103
+ event.type !== EVENT_TYPES.migration
2104
+ ) {
2105
+ continue;
2106
+ }
2107
+ const migrated = this.#migrationFromSnapshot(snapshot, event);
2108
+ const transactionId = migrated.migration.plan.stateMigrationDigest;
2109
+ const groupKey = `${migrated.migration.plan.tenantId}\0${migrated.migration.plan.skillName}`;
2110
+ if (
2111
+ migrations.has(groupKey) ||
2112
+ migrationsByTransaction.has(transactionId)
2113
+ ) {
2114
+ throw portsError(
2115
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2116
+ "release state migration baseline appears more than once",
2117
+ );
2118
+ }
2119
+ migrations.set(groupKey, migrated);
2120
+ migrationsByTransaction.set(transactionId, migrated);
2121
+ }
1920
2122
  for (const event of snapshot.events) {
1921
2123
  if (
1922
2124
  event.schema !== EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA ||
@@ -1943,14 +2145,24 @@ class EvolutionLedgerDomainPorts {
1943
2145
  left.finalization.revision - right.finalization.revision ||
1944
2146
  left.event.sequence - right.event.sequence,
1945
2147
  );
1946
- let previous = null;
2148
+ const first = group[0];
2149
+ const groupKey = `${first.tenantId}\0${first.finalization.skillName}`;
2150
+ const baseline = migrations.get(groupKey) || null;
2151
+ let previous = baseline;
1947
2152
  for (let index = 0; index < group.length; index += 1) {
1948
2153
  const entry = group[index];
2154
+ const previousRevision =
2155
+ previous?.finalization?.revision ??
2156
+ previous?.migration?.state.revision ??
2157
+ 0;
2158
+ const previousStateDigest =
2159
+ previous?.finalization?.stateDigest ??
2160
+ previous?.migration?.state.stateDigest ??
2161
+ null;
1949
2162
  if (
1950
- entry.finalization.revision !== index + 1 ||
1951
- entry.prepared.intent.expectedRevision !== index ||
1952
- entry.prepared.intent.previousStateDigest !==
1953
- (previous?.finalization.stateDigest ?? null) ||
2163
+ entry.finalization.revision !== previousRevision + 1 ||
2164
+ entry.prepared.intent.expectedRevision !== previousRevision ||
2165
+ entry.prepared.intent.previousStateDigest !== previousStateDigest ||
1954
2166
  (previous !== null && entry.event.sequence <= previous.event.sequence)
1955
2167
  ) {
1956
2168
  throw portsError(
@@ -1961,7 +2173,7 @@ class EvolutionLedgerDomainPorts {
1961
2173
  previous = entry;
1962
2174
  }
1963
2175
  }
1964
- return { byTransaction, groups };
2176
+ return { byTransaction, groups, migrations, migrationsByTransaction };
1965
2177
  }
1966
2178
 
1967
2179
  #committedProjection(finalized, lineages) {
@@ -2038,11 +2250,21 @@ class EvolutionLedgerDomainPorts {
2038
2250
  return { existing, lineages, prepared };
2039
2251
  }
2040
2252
  const groupKey = `${prepared.intent.mutationRequest.tenantId}\0${finalization.skillName}`;
2041
- const current = lineages.groups.get(groupKey)?.at(-1) || null;
2253
+ const current =
2254
+ lineages.groups.get(groupKey)?.at(-1) ||
2255
+ lineages.migrations.get(groupKey) ||
2256
+ null;
2257
+ const currentRevision =
2258
+ current?.finalization?.revision ??
2259
+ current?.migration?.state.revision ??
2260
+ 0;
2261
+ const currentStateDigest =
2262
+ current?.finalization?.stateDigest ??
2263
+ current?.migration?.state.stateDigest ??
2264
+ null;
2042
2265
  if (
2043
- finalization.revision !== (current?.finalization.revision ?? 0) + 1 ||
2044
- prepared.intent.previousStateDigest !==
2045
- (current?.finalization.stateDigest ?? null)
2266
+ finalization.revision !== currentRevision + 1 ||
2267
+ prepared.intent.previousStateDigest !== currentStateDigest
2046
2268
  ) {
2047
2269
  throw portsError(
2048
2270
  EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
@@ -2052,6 +2274,99 @@ class EvolutionLedgerDomainPorts {
2052
2274
  return { existing: null, lineages, prepared };
2053
2275
  }
2054
2276
 
2277
+ migrate(input) {
2278
+ const migration = normalizeStateMigration(input);
2279
+ const transactionId = migration.plan.stateMigrationDigest;
2280
+ const eventId = deterministicEventId("migration", { transactionId });
2281
+ let snapshot = this.#snapshot();
2282
+ for (let attempt = 0; attempt < MAX_FINALIZE_RETRIES; attempt += 1) {
2283
+ const existingEvent = snapshot.byEventId.get(eventId);
2284
+ const lineages = this.#lineages(snapshot);
2285
+ const groupKey = `${migration.plan.tenantId}\0${migration.plan.skillName}`;
2286
+ const existingGroupMigration = lineages.migrations.get(groupKey) || null;
2287
+ const existingFinalizations = lineages.groups.get(groupKey) || [];
2288
+ if (existingEvent) {
2289
+ const existing = this.#migrationFromSnapshot(snapshot, existingEvent, {
2290
+ stateDigest: migration.state.stateDigest,
2291
+ transactionId,
2292
+ });
2293
+ if (
2294
+ existing.migration.plan.stateMigrationDigest !== transactionId ||
2295
+ canonicalJson(existing.migration) !== canonicalJson(migration)
2296
+ ) {
2297
+ throw portsError(
2298
+ EVOLUTION_LEDGER_PORTS_COLLISION_CODE,
2299
+ "release state migration event id is bound to other evidence",
2300
+ );
2301
+ }
2302
+ return this.#migrationProjection(
2303
+ existing,
2304
+ existingFinalizations.length === 0,
2305
+ );
2306
+ }
2307
+ if (existingGroupMigration || existingFinalizations.length > 0) {
2308
+ throw portsError(
2309
+ EVOLUTION_LEDGER_PORTS_COLLISION_CODE,
2310
+ "release state migration requires an empty Skill ledger lineage",
2311
+ );
2312
+ }
2313
+ const subjectRef = this.#putSubject(
2314
+ ARTIFACT_TYPES.migration,
2315
+ migration,
2316
+ transactionId,
2317
+ this.#audience,
2318
+ );
2319
+ const previous = snapshot.events.at(-1) || null;
2320
+ try {
2321
+ this.#verifiedAppend(
2322
+ {
2323
+ artifactTenantId: this.#artifactTenantId,
2324
+ correlationId: transactionId,
2325
+ decision: "committed",
2326
+ eventId,
2327
+ reason: transactionId,
2328
+ skillName: migration.plan.skillName,
2329
+ sourceRefs: [],
2330
+ subjectRef,
2331
+ tenantId: migration.plan.tenantId,
2332
+ type: EVENT_TYPES.migration,
2333
+ },
2334
+ {
2335
+ expectedHeadDigest: previous?.eventDigest ?? null,
2336
+ expectedSequence: previous?.sequence ?? 0,
2337
+ },
2338
+ );
2339
+ } catch (cause) {
2340
+ if (isHeadConflict(cause)) {
2341
+ snapshot = this.#snapshot();
2342
+ continue;
2343
+ }
2344
+ if (!isCommitUnknown(cause) && !isEventConflict(cause)) throw cause;
2345
+ }
2346
+ const recovered = this.#snapshot();
2347
+ const persisted = recovered.byEventId.get(eventId);
2348
+ if (!persisted) {
2349
+ throw portsError(
2350
+ EVOLUTION_LEDGER_PORTS_UNAVAILABLE_CODE,
2351
+ "release state migration did not converge to a queryable event",
2352
+ );
2353
+ }
2354
+ const migrated = this.#migrationFromSnapshot(recovered, persisted, {
2355
+ stateDigest: migration.state.stateDigest,
2356
+ transactionId,
2357
+ });
2358
+ const recoveredLineages = this.#lineages(recovered);
2359
+ return this.#migrationProjection(
2360
+ migrated,
2361
+ (recoveredLineages.groups.get(groupKey) || []).length === 0,
2362
+ );
2363
+ }
2364
+ throw portsError(
2365
+ EVOLUTION_LEDGER_PORTS_UNAVAILABLE_CODE,
2366
+ "release state migration could not acquire a stable ledger head",
2367
+ );
2368
+ }
2369
+
2055
2370
  prepare(input) {
2056
2371
  const intent = normalizeIntent(input);
2057
2372
  this.#assertAudience(intent.mutationRequest.audience, "intent audience");
@@ -2186,11 +2501,32 @@ class EvolutionLedgerDomainPorts {
2186
2501
 
2187
2502
  query(transactionIdValue) {
2188
2503
  const transactionId = digest(transactionIdValue, "transactionId");
2504
+ const migrationEventId = deterministicEventId("migration", {
2505
+ transactionId,
2506
+ });
2189
2507
  const prepareEventId = deterministicEventId("prepare", { transactionId });
2190
2508
  const finalizeEventId = deterministicEventId("finalize", { transactionId });
2191
2509
  const snapshot = this.#snapshot();
2510
+ const migrationEvent = snapshot.byEventId.get(migrationEventId);
2192
2511
  const prepareEvent = snapshot.byEventId.get(prepareEventId);
2193
2512
  const finalizeEvent = snapshot.byEventId.get(finalizeEventId);
2513
+ if (migrationEvent) {
2514
+ if (prepareEvent || finalizeEvent) {
2515
+ throw portsError(
2516
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2517
+ "release transaction id has both migration and transition evidence",
2518
+ );
2519
+ }
2520
+ const migrated = this.#migrationFromSnapshot(snapshot, migrationEvent, {
2521
+ transactionId,
2522
+ });
2523
+ const lineages = this.#lineages(snapshot);
2524
+ const groupKey = `${migrated.migration.plan.tenantId}\0${migrated.migration.plan.skillName}`;
2525
+ return this.#migrationProjection(
2526
+ migrated,
2527
+ (lineages.groups.get(groupKey) || []).length === 0,
2528
+ );
2529
+ }
2194
2530
  if (!prepareEvent) {
2195
2531
  if (finalizeEvent) {
2196
2532
  throw portsError(
@@ -2675,13 +3011,14 @@ export function createEvolutionLedgerPorts(options = {}) {
2675
3011
  });
2676
3012
  const prepare = Object.freeze((input) => adapter.prepare(input));
2677
3013
  const finalize = Object.freeze((input) => adapter.finalize(input));
3014
+ const migrate = Object.freeze((input) => adapter.migrate(input));
2678
3015
  const query = Object.freeze((transactionId) => adapter.query(transactionId));
2679
3016
  const append = Object.freeze((event) => adapter.appendAudit(event));
2680
3017
  const claim = Object.freeze((nonce) => adapter.claimNonce(nonce));
2681
3018
  return Object.freeze({
2682
3019
  auditSink: Object.freeze({ append }),
2683
3020
  nonceStore: Object.freeze({ claim }),
2684
- transactionLedger: Object.freeze({ finalize, prepare, query }),
3021
+ transactionLedger: Object.freeze({ finalize, migrate, prepare, query }),
2685
3022
  });
2686
3023
  }
2687
3024