chainlesschain 0.165.2 → 0.165.4

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 +151 -29
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/assets/{AIOps-lS1R0Cza.js → AIOps-C__nnraW.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-BmlgBPsj.js → ActionButton-CsKWHEZ-.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-CNKczv1S.js → Analytics-BhIjfjWO.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-BuZGJARQ.js → AppLayout-BjuXFzWZ.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-Dm73Sl-O.js → Artifacts-k6whDkZJ.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-BGMW7A5e.js → Audit-C4FBMYRh.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BQ6M54JR.js → BackgroundAgents-C_vRrSXk.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DBzGP0bR.js → Backup-CngFZeVp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-D1mLCoOV.js → BaseInput-B_H9EBRm.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-BUfcN7p8.js → Chat-DLEC5kt7.js} +4 -4
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-Du0Yg5Pi.js → Checkbox-m3ClR4xh.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-B2RXziHW.js → Codegen-CmLSFrgp.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-DWhekOrR.js → Col-DFGQteHN.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-HQhrkon4.js → Community-EUUVORHE.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-izHNb4uz.js → Compact-2PSg0Yr7.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BDwLy41-.js → Compliance-CcKur7gB.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DFJhLa7K.js → Cowork-DK_Fezfa.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-DYY9RG7-.js → Cron-Dbw89xl7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-rr7tJTtv.js → Crosschain-CH66h_Ec.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D2sfHRLi.js → DID-D1igRb17.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-q_eGdhha.js → Dashboard-DVAsrobk.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-Cufrh2Bz.js → Dropdown-Dl7W8AQs.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-B-kdv10f.js → EmailListRenderer-D5tpaEQC.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D21XjgfG.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-CAwRTLZH.js → Federation-BTVcgS9n.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-vx3daNDF.js → FormItemContext-BRnkJAIz.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-CRWY2wU4.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Q6SwauyD.js → Git-WXLYTQj2.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-BJ1q4IQZ.js → Governance-BezaUhtc.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CSWjROgD.js → Inference-CuRay3Gu.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-fzuQsWuY.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DVF8Mnns.js → Logs-C55y2pPY.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-BQP7LOA4.js → Marketplace-Dk08Uycg.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-BNlJCmNc.js → McpTools-C11fSB5V.js} +4 -4
  39. package/src/assets/web-panel/assets/{Memory-DLLg5WQ4.js → Memory-mr0eZc97.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-CR2skNAF.js → MobileBridge-C0iCSRbb.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BxVavObl.js → MobileProjects-CY-xMG8Z.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-B17pgqMI.js → Mtc-Bplqc_Wc.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-4UmV5cIL.js → MtcAudit-BlzwsoSM.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-DoMEXEcU.js → Multisig-BBLmTty6.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-h9DMXFX4.js → NLProgramming-DtT1uf1W.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-Cihn-xX8.js → Notes-DcqQAxTK.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-BE6ZGa3R.js → NotificationSettings-cb0kWoZe.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-CnwojoSI.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-B2vpwmjb.js → Organization-DlTlbkUN.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-C4z28R0-.js → Overflow-pp1qs-oY.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BVlFkwhW.js → P2P-BESLnyYz.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BXbEdL5B.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-C28xs4lp.js → Permissions-B36PeT1_.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-Dgl_rBjM.js → PersonalDataHub-CTK2ad-3.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-3QUIhrKI.js → Pipeline-zJNGXsac.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-8Gh33OZ5.js → Privacy-b9fz0Qf0.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-BNmg4tZi.js → ProjectInit-DjZbZgiB.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-vgMfeCf9.js → ProjectSettings-C-hHJXlD.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-CXoOa8eX.js → Providers-Dz-CAYYU.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-BhfTF0oS.js → QrScannerModal-A0yoQ3-3.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-C746HEAj.js → QuickAsk-DrFgFJNC.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-BSej8Eo0.js → Recommend-KC8hF1g4.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-f3gmnlG3.js → RemoteSession-DGTPIk6u.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-CyvybpkN.js → Reputation-QmbwM7Yk.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-DwV2PeYn.js → Row-BxjJylia.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-11GrzjZy.js → RssFeed-B7Wda1J6.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-BjKXkrAY.js → Search-_plQ_YSA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-eWiFb9Yk.js → Security-CD2YJZfx.js} +2 -2
  70. package/src/assets/web-panel/assets/{Services-CdCsMAtt.js → Services-qQE7NmwE.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-4Q2UTKQ5.js → Skeleton-DgQqkFf7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-v4rtYrRj.js → Skills-C4C0oFFt.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-CRhsFvd_.js → Sla-Px2N2B5c.js} +1 -1
  74. package/src/assets/web-panel/assets/SpeechSettings-DN6C3lQd.js +1 -0
  75. package/src/assets/web-panel/assets/{SyncSettings-D16zonl7.js → SyncSettings-jm5aH_m7.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-Xxozz0i_.js → Tasks-DlkJcv67.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-CXJpPtCT.js → Templates-DyrTHUBs.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-XRV0L1ZF.js → Tenant-mC434PtL.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-CYuO1i_w.js → Terminal-o0_s3NgK.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-BXqitWsu.js → TimelineRenderer-DAGlAXOw.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BvPrDHIy.js → Tokens-BnulS_bs.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DhCrSTf5.js → Trigger-suQbVXYM.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DmsuZD6K.js → Trust-DbIJAPo5.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-D_yrts5C.js → UkeySign-CQNpbIHi.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-B01ihPrm.js → VideoEditing-D8aWCERk.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-DpUjKa-N.js → Wallet-CuLpYfZc.js} +2 -2
  87. package/src/assets/web-panel/assets/{WebAuthn-CL07yON6.js → WebAuthn-CsfG8ZMc.js} +2 -2
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CLMflnRr.js → WorkflowEditor-BYsEAZbd.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DtUqe8h_.js → chat-FT4Um3-I.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DPKrgVfy.js → colors-CKbS_Wlt.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BTt2GtOm.js → compact-item-CFJtzuJM.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-D_VeUc1J.js → createContext-B9kSRW6K.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-1kndiylj.js → hasIn-DR-x0Xpi.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-dVc-CXY4.js → index-7jHr_A_k.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DFIZ_1Sf.js → index-B3ZX81mK.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-fk2Rjacw.js → index-B7osrXqy.js} +3 -3
  98. package/src/assets/web-panel/assets/{index-CHG-KcS4.js → index-BGbPnC5x.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Dbbymxpj.js → index-BI5hP_qy.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BaZAbw9A.js → index-BK3TiKVq.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CzjkKUmR.js → index-BVPU43b1.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BAXfRKfG.js → index-BW-t9n-q.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-8nz_fmlj.js → index-BfFCQHL3.js} +1 -1
  104. package/src/assets/web-panel/assets/index-Bizb4hkw.js +1 -0
  105. package/src/assets/web-panel/assets/{index-DdkplL9R.js → index-Bt4fS2eL.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DG2MZQ3f.js → index-BwR7yc2h.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DfKBRdSS.js → index-Bzz0C1BZ.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-GsoUQ2M7.js → index-C2JvmYRc.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-l1BETrDb.js → index-CGaXUsIs.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-4bna2_SR.js → index-CJmIQ9XR.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DfGl8CqG.js → index-C_enk9I_.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D95OFht7.js → index-Cr2FLUsD.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DsJCDUJG.js → index-CvrCCqJt.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-sDoMHTNA.js → index-D4LfPvWA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-By5n8up9.js → index-DMGmg497.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-ocf06EVQ.js → index-DShSkww-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Bhudc_Ez.js → index-DTxNy0ZU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CX81qSM4.js → index-DW4BWjTk.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BlDNVgBt.js → index-DWdqx7zI.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CcO04eDn.js → index-Dap9c3eD.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Dwqmtk65.js → index-DcfxhKXR.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-2eyAXE3d.js → index-DdkIhfi-.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-brCInrzq.js → index-DeSgw-WV.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DJ8vXGOa.js → index-DiNUEpSQ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BHpBMWCh.js → index-DjEP7WkH.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-m31Ka8hZ.js → index-DtkFqPVA.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CtF7EN49.js → index-KqDaCApw.js} +1 -1
  128. package/src/assets/web-panel/assets/index-OHSl-xCh.js +1 -0
  129. package/src/assets/web-panel/assets/{index-B9KvcS7R.js → index-OSzjTzGM.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CauoBQkH.js → index-QBSeNVO3.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-FzdwcSy2.js → index-WE08gMJP.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DxdTdBix.js → index-r2VI1Ikk.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BepLZwgB.js → index-tqSEHPRT.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CvyYJd7z.js → initDefaultProps-Dd7n7VgI.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-DYZkhUdz.js → motion-BwxouRw1.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-slnJRVT1.js → move-DObN0PG9.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-DVc0CKmy.js → mtc-parser-B3nOUQc7.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BCXAtHCq.js → omit-o9WU2Nbl.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DBsemz_K.js → pickAttrs-CL_vvfQ_.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-BRtkJ-nv.js → placementArrow-CYrM2tyK.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Cebq7EZn.js → responsiveObserve-k_06cQ96.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DT7qvId2.js → slide-CPKG0pxS.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-pQiITLkG.js → statusUtils-BDDEeLTw.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-c-19BVKQ.js → styleChecker-Cmb7RTh7.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-DsS5-0bE.js → useFlexGapSupport-e2IedC4N.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-CxGiMe5n.js → useFs-CE_gxVnm.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-D9btVID5.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-CUYFsFEN.js → vnode-DW886XV1.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CXmn_35j.js → zoom-Dwo_adaf.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +3 -3
  152. package/src/commands/agent.js +105 -35
  153. package/src/commands/artifacts.js +363 -33
  154. package/src/commands/cowork.js +202 -36
  155. package/src/commands/session-budget.js +155 -0
  156. package/src/commands/session-location.js +948 -0
  157. package/src/commands/session.js +72 -46
  158. package/src/data/changelog.json +26 -0
  159. package/src/gateways/ws/artifact-protocol.js +77 -13
  160. package/src/gateways/ws/session-protocol.js +391 -24
  161. package/src/gateways/ws/ws-agent-handler.js +191 -14
  162. package/src/gateways/ws/ws-server.js +14 -3
  163. package/src/gateways/ws/ws-session-gateway.js +101 -5
  164. package/src/harness/jsonl-session-store.js +1210 -0
  165. package/src/lib/agent-team/team-runner.js +43 -13
  166. package/src/lib/artifact-access-ledger.js +461 -0
  167. package/src/lib/artifact-cleanup-ledger.js +861 -0
  168. package/src/lib/artifact-deletion-ledger.js +677 -0
  169. package/src/lib/artifact-store.js +256 -51
  170. package/src/lib/background-agent-keeper-protocol.js +75 -4
  171. package/src/lib/background-agent-launch-barrier.js +74 -0
  172. package/src/lib/background-agent-supervisor.js +149 -5
  173. package/src/lib/background-turn-bootstrap-protocol.js +4 -0
  174. package/src/lib/command-lifecycle-report.js +8 -4
  175. package/src/lib/cowork-adapter.js +9 -5
  176. package/src/lib/cowork-task-runner.js +20 -0
  177. package/src/lib/cowork-workflow.js +178 -20
  178. package/src/lib/direct-model-usage.js +62 -22
  179. package/src/lib/dynamic-workflow-runtime.js +3184 -111
  180. package/src/lib/execution-location-result-apply.js +339 -0
  181. package/src/lib/execution-location-result-artifact.js +271 -0
  182. package/src/lib/execution-location-result-review.js +253 -0
  183. package/src/lib/execution-location-result-store.js +331 -0
  184. package/src/lib/execution-location-result.js +617 -0
  185. package/src/lib/execution-location-target.js +236 -1
  186. package/src/lib/managed-tool-checkpoint.js +47 -4
  187. package/src/lib/process-execution-broker/workspace-transaction.js +3 -0
  188. package/src/lib/session-budget-production-root.js +376 -0
  189. package/src/lib/session-budget-runtime.js +109 -18
  190. package/src/lib/session-budget-usage.js +63 -0
  191. package/src/lib/session-host-snapshot.js +19 -2
  192. package/src/lib/session-resource-budget.js +766 -105
  193. package/src/lib/sub-agent-context.js +69 -22
  194. package/src/lib/web-ui-server.js +12 -1
  195. package/src/lib/with-file-lock.js +175 -26
  196. package/src/repl/agent-repl.js +237 -16
  197. package/src/runtime/agent-core.js +123 -0
  198. package/src/runtime/headless-runner.js +135 -46
  199. package/src/runtime/headless-stream.js +133 -25
  200. package/src/runtime/policies/agent-policy.js +10 -0
  201. package/src/workers/background-agent-keeper.js +112 -19
  202. package/src/workers/background-agent-worker.js +383 -134
  203. package/src/workers/background-turn-bootstrap.js +13 -8
  204. package/src/assets/web-panel/assets/ChatBubbleRenderer-CY5m8ZHg.js +0 -1
  205. package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +0 -1
  206. package/src/assets/web-panel/assets/Projects-BhtAVilc.js +0 -1
  207. package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +0 -1
  208. package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +0 -1
  209. package/src/assets/web-panel/assets/index-CPcM-eqo.js +0 -1
  210. package/src/assets/web-panel/assets/index-xeSyVoRe.js +0 -1
@@ -83,6 +83,12 @@ import {
83
83
  readSessionAntiRollbackAnchor,
84
84
  sessionAntiRollbackPredecessorWitness,
85
85
  } from "../lib/session-anti-rollback-anchor.js";
86
+ import { normalizeSessionBudgetRootConfig } from "../lib/session-budget-production-root.js";
87
+ import {
88
+ normalizeExecutionLocationResultBundle,
89
+ verifyExecutionLocationResultBundle,
90
+ } from "../lib/execution-location-result.js";
91
+ import { normalizeExecutionLocationResultStoreReceipt } from "../lib/execution-location-result-store.js";
86
92
 
87
93
  let securedSessionsDir = null;
88
94
  let securedSessionsDirIdentity = null;
@@ -114,6 +120,9 @@ export const _sessionScaleFaultHooks = Object.seal({
114
120
  beforeReplicaDirectoryFsync: null,
115
121
  afterReplicaDirectoryFsync: null,
116
122
  afterLocationHandoffAppend: null,
123
+ afterResultCollectionSettlementAppend: null,
124
+ afterResultApplyReservationAppend: null,
125
+ afterResultApplyTerminalAppend: null,
117
126
  beforeDeleteDirectoryFsync: null,
118
127
  afterDeleteDirectoryFsync: null,
119
128
  afterAntiRollbackPublish: null,
@@ -134,6 +143,26 @@ export const SESSION_EXECUTION_LOCATION_HANDOFF_SCHEMA =
134
143
  "chainlesschain.session-execution-location-handoff/v1";
135
144
  export const SESSION_EXECUTION_LOCATION_HANDOFF_INSTALL_SCHEMA =
136
145
  "chainlesschain.session-execution-location-handoff-install/v1";
146
+ export const SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_EVENT =
147
+ "execution_location_result_collection";
148
+ export const SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA_V1 =
149
+ "chainlesschain.session-execution-location-result-collection/v1";
150
+ export const SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA =
151
+ "chainlesschain.session-execution-location-result-collection/v2";
152
+ export const SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA_V1 =
153
+ "chainlesschain.session-execution-location-result-collection-receipt/v1";
154
+ export const SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA =
155
+ "chainlesschain.session-execution-location-result-collection-receipt/v2";
156
+ export const SESSION_EXECUTION_LOCATION_RESULT_APPLY_RESERVATION_EVENT =
157
+ "execution_location_result_apply_reserved";
158
+ export const SESSION_EXECUTION_LOCATION_RESULT_APPLY_RESERVATION_SCHEMA =
159
+ "chainlesschain.session-execution-location-result-apply-reservation/v1";
160
+ export const SESSION_EXECUTION_LOCATION_RESULT_APPLY_TERMINAL_EVENT =
161
+ "execution_location_result_apply_terminal";
162
+ export const SESSION_EXECUTION_LOCATION_RESULT_APPLY_TERMINAL_SCHEMA =
163
+ "chainlesschain.session-execution-location-result-apply-terminal/v1";
164
+ export const SESSION_EXECUTION_LOCATION_RESULT_APPLY_RECEIPT_SCHEMA =
165
+ "chainlesschain.session-execution-location-result-apply-receipt/v1";
137
166
  export const MAX_SESSION_REPLICA_BYTES = 64 * 1024 * 1024;
138
167
  const WS_TURN_CONTENT_MAX_BYTES = 4 * 1024 * 1024;
139
168
  const WS_TURN_REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:@-]*$/;
@@ -2639,6 +2668,13 @@ export function startSession(sessionId, meta = {}) {
2639
2668
  ),
2640
2669
  }
2641
2670
  : {}),
2671
+ ...(meta.sessionBudgetRoot != null
2672
+ ? {
2673
+ sessionBudgetRoot: normalizeSessionBudgetRootConfig(
2674
+ meta.sessionBudgetRoot,
2675
+ ),
2676
+ }
2677
+ : {}),
2642
2678
  });
2643
2679
 
2644
2680
  return id;
@@ -2677,6 +2713,16 @@ export function getVerifiedSessionExecutionLocationAuthority(sessionId) {
2677
2713
  executionLocation = locationHandoff.target.binding;
2678
2714
  bindingEventHash = event.hash;
2679
2715
  bindingEventCount = eventCount;
2716
+ return;
2717
+ }
2718
+ if (
2719
+ event?.type === SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_EVENT
2720
+ ) {
2721
+ projectSessionResultCollectionSettlement(
2722
+ sessionId,
2723
+ event,
2724
+ eventCount,
2725
+ );
2680
2726
  }
2681
2727
  },
2682
2728
  finish(authority) {
@@ -3813,6 +3859,1170 @@ function sessionLocationHandoffInstallReceipt(
3813
3859
  });
3814
3860
  }
3815
3861
 
3862
+ function normalizeSessionLocationDigest(value, field) {
3863
+ const normalized = boundedAuthorityString(value, field, 80).toLowerCase();
3864
+ if (!/^sha256:[a-f0-9]{64}$/u.test(normalized)) {
3865
+ throw new TypeError(`${field} is invalid`);
3866
+ }
3867
+ return normalized;
3868
+ }
3869
+
3870
+ function normalizeSessionLocationHead(value, field) {
3871
+ const normalized = boundedAuthorityString(value, field, 64).toLowerCase();
3872
+ if (!/^[a-f0-9]{64}$/u.test(normalized)) {
3873
+ throw new TypeError(`${field} is invalid`);
3874
+ }
3875
+ return normalized;
3876
+ }
3877
+
3878
+ function normalizeSessionLocationEventCount(value, field) {
3879
+ const normalized = Number(value);
3880
+ if (!Number.isSafeInteger(normalized) || normalized < 1) {
3881
+ throw new TypeError(`${field} is invalid`);
3882
+ }
3883
+ return normalized;
3884
+ }
3885
+
3886
+ function normalizeSessionResultCollectionRequestId(value) {
3887
+ const requestId = boundedAuthorityString(
3888
+ value,
3889
+ "result collection request id",
3890
+ 128,
3891
+ );
3892
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:@+-]{0,127}$/u.test(requestId)) {
3893
+ throw new TypeError("result collection request id is invalid");
3894
+ }
3895
+ return requestId;
3896
+ }
3897
+
3898
+ function normalizeSessionResultCollectionSource(value, sessionId) {
3899
+ const source = exactRecord(
3900
+ value,
3901
+ ["sessionId", "headHash", "eventCount"],
3902
+ "session result collection source",
3903
+ );
3904
+ if (source.sessionId !== sessionId) {
3905
+ throw new TypeError("session result collection source is invalid");
3906
+ }
3907
+ return Object.freeze({
3908
+ sessionId,
3909
+ headHash: normalizeSessionLocationHead(
3910
+ source.headHash,
3911
+ "result collection source head",
3912
+ ),
3913
+ eventCount: normalizeSessionLocationEventCount(
3914
+ source.eventCount,
3915
+ "result collection source event count",
3916
+ ),
3917
+ });
3918
+ }
3919
+
3920
+ function createSessionResultCollectionSettlementData(
3921
+ sessionId,
3922
+ requestIdInput,
3923
+ collection,
3924
+ storageInput,
3925
+ ) {
3926
+ if (
3927
+ !collection ||
3928
+ typeof collection !== "object" ||
3929
+ Array.isArray(collection)
3930
+ ) {
3931
+ throw new TypeError("execution-location result collection is invalid");
3932
+ }
3933
+ const requestId = normalizeSessionResultCollectionRequestId(requestIdInput);
3934
+ if (
3935
+ collection.schema !== "cc-execution-location-target-result-collection/v1" ||
3936
+ collection.requestId !== requestId ||
3937
+ collection.applied !== false
3938
+ ) {
3939
+ throw new TypeError("execution-location result collection is invalid");
3940
+ }
3941
+ const source = normalizeSessionResultCollectionSource(
3942
+ collection.sourceAuthority,
3943
+ sessionId,
3944
+ );
3945
+ const bundle = normalizeExecutionLocationResultBundle(collection.bundle);
3946
+ const verification = verifyExecutionLocationResultBundle({
3947
+ bundle,
3948
+ sourceAuthority: source,
3949
+ expectedHandoffId: collection.handoffId,
3950
+ });
3951
+ const target = Object.freeze({
3952
+ headHash: normalizeSessionLocationHead(
3953
+ collection.targetHeadHash,
3954
+ "result collection target head",
3955
+ ),
3956
+ eventCount: normalizeSessionLocationEventCount(
3957
+ collection.targetEventCount,
3958
+ "result collection target event count",
3959
+ ),
3960
+ });
3961
+ const totalBytes = Number(verification.totalBytes);
3962
+ if (
3963
+ !Number.isSafeInteger(totalBytes) ||
3964
+ totalBytes < 1 ||
3965
+ collection.resultId !== bundle.resultId ||
3966
+ collection.handoffId !== bundle.session.handoffId ||
3967
+ collection.targetHeadHash !== bundle.session.target.headHash ||
3968
+ Number(collection.targetEventCount) !== bundle.session.target.eventCount ||
3969
+ collection.profileDigest !== bundle.session.target.profileDigest ||
3970
+ collection.targetFactsDigest !== bundle.session.target.targetFactsDigest ||
3971
+ collection.bundleDigest !== bundle.bundleDigest ||
3972
+ collection.verificationDigest !== verification.verificationDigest ||
3973
+ collection.verification?.verificationDigest !==
3974
+ verification.verificationDigest ||
3975
+ collection.verification?.applied !== false
3976
+ ) {
3977
+ throw new TypeError("execution-location result verification is invalid");
3978
+ }
3979
+ const storage = normalizeExecutionLocationResultStoreReceipt(storageInput);
3980
+ if (
3981
+ storage.sessionId !== sessionId ||
3982
+ storage.resultId !== bundle.resultId ||
3983
+ storage.handoffId !== bundle.session.handoffId ||
3984
+ storage.bundleDigest !== bundle.bundleDigest
3985
+ ) {
3986
+ throw new TypeError("execution-location result storage receipt is invalid");
3987
+ }
3988
+ const collectionMaterial = {
3989
+ schema: "cc-execution-location-target-result-collection/v1",
3990
+ requestId,
3991
+ requestDigest: collection.requestDigest,
3992
+ resultId: collection.resultId,
3993
+ target: collection.target,
3994
+ profileDigest: collection.profileDigest,
3995
+ targetFactsDigest: collection.targetFactsDigest,
3996
+ collectionAttestationDigest: collection.collectionAttestationDigest,
3997
+ handoffId: collection.handoffId,
3998
+ sourceAuthority: collection.sourceAuthority,
3999
+ targetHeadHash: collection.targetHeadHash,
4000
+ targetEventCount: collection.targetEventCount,
4001
+ bundleDigest: collection.bundleDigest,
4002
+ verificationDigest: collection.verificationDigest,
4003
+ applied: collection.applied,
4004
+ continuity: collection.continuity,
4005
+ gaps: collection.gaps,
4006
+ };
4007
+ if (
4008
+ !["wsl", "ssh", "container"].includes(collection.target) ||
4009
+ collection.continuity !== "single-fixed-command-response" ||
4010
+ JSON.stringify(collection.gaps) !==
4011
+ JSON.stringify([
4012
+ "returned-result-bytes-not-durable",
4013
+ "cross-host-concurrent-writer-fencing-not-durable",
4014
+ "returned-result-not-applied",
4015
+ ]) ||
4016
+ collection.collectionDigest !==
4017
+ sessionLocationDigest(
4018
+ "chainlesschain.execution-location.target-result-collection.v1\0",
4019
+ collectionMaterial,
4020
+ )
4021
+ ) {
4022
+ throw new TypeError(
4023
+ "execution-location result collection digest is invalid",
4024
+ );
4025
+ }
4026
+ const material = {
4027
+ schema: SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA,
4028
+ requestId,
4029
+ requestDigest: normalizeSessionLocationDigest(
4030
+ collection.requestDigest,
4031
+ "result collection request digest",
4032
+ ),
4033
+ resultId: boundedAuthorityString(
4034
+ collection.resultId,
4035
+ "result collection result id",
4036
+ 128,
4037
+ ),
4038
+ handoffId: normalizeSessionLocationDigest(
4039
+ collection.handoffId,
4040
+ "result collection handoff id",
4041
+ ),
4042
+ source,
4043
+ target,
4044
+ profileDigest: normalizeSessionLocationDigest(
4045
+ collection.profileDigest,
4046
+ "result collection profile digest",
4047
+ ),
4048
+ targetFactsDigest: normalizeSessionLocationDigest(
4049
+ collection.targetFactsDigest,
4050
+ "result collection target facts digest",
4051
+ ),
4052
+ collectionAttestationDigest: normalizeSessionLocationDigest(
4053
+ collection.collectionAttestationDigest,
4054
+ "result collection attestation digest",
4055
+ ),
4056
+ bundleDigest: normalizeSessionLocationDigest(
4057
+ collection.bundleDigest,
4058
+ "result collection bundle digest",
4059
+ ),
4060
+ verificationDigest: normalizeSessionLocationDigest(
4061
+ collection.verificationDigest,
4062
+ "result collection verification digest",
4063
+ ),
4064
+ collectionDigest: normalizeSessionLocationDigest(
4065
+ collection.collectionDigest,
4066
+ "result collection digest",
4067
+ ),
4068
+ storage,
4069
+ totalBytes,
4070
+ applied: false,
4071
+ };
4072
+ return Object.freeze({
4073
+ ...material,
4074
+ settlementId: sessionLocationDigest(
4075
+ "chainlesschain.session-execution-location-result-collection-id.v1\0",
4076
+ material,
4077
+ ),
4078
+ });
4079
+ }
4080
+
4081
+ function normalizeSessionResultCollectionSettlementData(sessionId, data) {
4082
+ const isLegacy =
4083
+ data.schema === SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA_V1;
4084
+ if (
4085
+ !isLegacy &&
4086
+ data.schema !== SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA
4087
+ ) {
4088
+ throw new TypeError("session result collection settlement schema is invalid");
4089
+ }
4090
+ const source = normalizeSessionResultCollectionSource(data.source, sessionId);
4091
+ const target = exactRecord(
4092
+ data.target,
4093
+ ["headHash", "eventCount"],
4094
+ "session result collection target",
4095
+ );
4096
+ const resultId = boundedAuthorityString(
4097
+ data.resultId,
4098
+ "result collection result id",
4099
+ 128,
4100
+ );
4101
+ const totalBytes = Number(data.totalBytes);
4102
+ if (
4103
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(resultId) ||
4104
+ !Number.isSafeInteger(totalBytes) ||
4105
+ totalBytes < 1 ||
4106
+ data.applied !== false
4107
+ ) {
4108
+ throw new TypeError("session result collection settlement is invalid");
4109
+ }
4110
+ const material = {
4111
+ schema: data.schema,
4112
+ requestId: normalizeSessionResultCollectionRequestId(data.requestId),
4113
+ requestDigest: normalizeSessionLocationDigest(
4114
+ data.requestDigest,
4115
+ "result collection request digest",
4116
+ ),
4117
+ resultId,
4118
+ handoffId: normalizeSessionLocationDigest(
4119
+ data.handoffId,
4120
+ "result collection handoff id",
4121
+ ),
4122
+ source,
4123
+ target: Object.freeze({
4124
+ headHash: normalizeSessionLocationHead(
4125
+ target.headHash,
4126
+ "result collection target head",
4127
+ ),
4128
+ eventCount: normalizeSessionLocationEventCount(
4129
+ target.eventCount,
4130
+ "result collection target event count",
4131
+ ),
4132
+ }),
4133
+ profileDigest: normalizeSessionLocationDigest(
4134
+ data.profileDigest,
4135
+ "result collection profile digest",
4136
+ ),
4137
+ targetFactsDigest: normalizeSessionLocationDigest(
4138
+ data.targetFactsDigest,
4139
+ "result collection target facts digest",
4140
+ ),
4141
+ collectionAttestationDigest: normalizeSessionLocationDigest(
4142
+ data.collectionAttestationDigest,
4143
+ "result collection attestation digest",
4144
+ ),
4145
+ bundleDigest: normalizeSessionLocationDigest(
4146
+ data.bundleDigest,
4147
+ "result collection bundle digest",
4148
+ ),
4149
+ verificationDigest: normalizeSessionLocationDigest(
4150
+ data.verificationDigest,
4151
+ "result collection verification digest",
4152
+ ),
4153
+ collectionDigest: normalizeSessionLocationDigest(
4154
+ data.collectionDigest,
4155
+ "result collection digest",
4156
+ ),
4157
+ ...(!isLegacy
4158
+ ? {
4159
+ storage: normalizeExecutionLocationResultStoreReceipt(data.storage),
4160
+ }
4161
+ : {}),
4162
+ totalBytes,
4163
+ applied: false,
4164
+ };
4165
+ const settlementId = sessionLocationDigest(
4166
+ "chainlesschain.session-execution-location-result-collection-id.v1\0",
4167
+ material,
4168
+ );
4169
+ if (data.settlementId !== settlementId) {
4170
+ throw new TypeError("session result collection settlement id is invalid");
4171
+ }
4172
+ if (
4173
+ !isLegacy &&
4174
+ (material.storage.sessionId !== sessionId ||
4175
+ material.storage.resultId !== resultId ||
4176
+ material.storage.handoffId !== material.handoffId ||
4177
+ material.storage.bundleDigest !== material.bundleDigest)
4178
+ ) {
4179
+ throw new TypeError("session result collection storage is invalid");
4180
+ }
4181
+ return Object.freeze({ ...material, settlementId });
4182
+ }
4183
+
4184
+ function projectSessionResultCollectionSettlement(
4185
+ sessionId,
4186
+ event,
4187
+ eventCount,
4188
+ ) {
4189
+ const legacy =
4190
+ event?.data?.schema ===
4191
+ SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA_V1;
4192
+ const data = exactRecord(
4193
+ event?.data,
4194
+ [
4195
+ "schema",
4196
+ "settlementId",
4197
+ "requestId",
4198
+ "requestDigest",
4199
+ "resultId",
4200
+ "handoffId",
4201
+ "source",
4202
+ "target",
4203
+ "profileDigest",
4204
+ "targetFactsDigest",
4205
+ "collectionAttestationDigest",
4206
+ "bundleDigest",
4207
+ "verificationDigest",
4208
+ "collectionDigest",
4209
+ ...(!legacy ? ["storage"] : []),
4210
+ "totalBytes",
4211
+ "applied",
4212
+ ],
4213
+ "session result collection settlement",
4214
+ );
4215
+ if (
4216
+ !legacy &&
4217
+ data.schema !== SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA
4218
+ ) {
4219
+ throw new TypeError("session result collection settlement schema is invalid");
4220
+ }
4221
+ const normalized = normalizeSessionResultCollectionSettlementData(
4222
+ sessionId,
4223
+ data,
4224
+ );
4225
+ if (
4226
+ normalized.settlementId !== data.settlementId ||
4227
+ normalized.source.headHash !== event?.prevHash ||
4228
+ normalized.source.eventCount !== eventCount - 1
4229
+ ) {
4230
+ throw new TypeError("session result collection predecessor is invalid");
4231
+ }
4232
+ return Object.freeze({
4233
+ ...normalized,
4234
+ eventHash: event.hash,
4235
+ eventCount,
4236
+ at: new Date(event.timestamp).toISOString(),
4237
+ });
4238
+ }
4239
+
4240
+ function sessionResultCollectionReceipt(sessionId, settlement) {
4241
+ const legacy =
4242
+ settlement.schema ===
4243
+ SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_SCHEMA_V1;
4244
+ const receiptSchema = legacy
4245
+ ? SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA_V1
4246
+ : SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA;
4247
+ const material = {
4248
+ schema: receiptSchema,
4249
+ sessionId,
4250
+ settlementId: settlement.settlementId,
4251
+ requestId: settlement.requestId,
4252
+ requestDigest: settlement.requestDigest,
4253
+ resultId: settlement.resultId,
4254
+ handoffId: settlement.handoffId,
4255
+ sourceHeadHash: settlement.source.headHash,
4256
+ sourceEventCount: settlement.source.eventCount,
4257
+ settlementEventHash: settlement.eventHash,
4258
+ settlementEventCount: settlement.eventCount,
4259
+ targetHeadHash: settlement.target.headHash,
4260
+ targetEventCount: settlement.target.eventCount,
4261
+ bundleDigest: settlement.bundleDigest,
4262
+ verificationDigest: settlement.verificationDigest,
4263
+ collectionDigest: settlement.collectionDigest,
4264
+ ...(!legacy ? { storage: settlement.storage } : {}),
4265
+ totalBytes: settlement.totalBytes,
4266
+ applied: false,
4267
+ };
4268
+ return Object.freeze({
4269
+ ...material,
4270
+ receiptDigest: sessionLocationDigest(
4271
+ legacy
4272
+ ? "chainlesschain.session-execution-location-result-collection-receipt.v1\0"
4273
+ : "chainlesschain.session-execution-location-result-collection-receipt.v2\0",
4274
+ material,
4275
+ ),
4276
+ });
4277
+ }
4278
+
4279
+ export function readVerifiedSessionExecutionLocationResultSettlement(
4280
+ sessionId,
4281
+ requestIdInput,
4282
+ options = {},
4283
+ ) {
4284
+ const requestId = normalizeSessionResultCollectionRequestId(requestIdInput);
4285
+ const expectedRequestDigest =
4286
+ options.requestDigest == null
4287
+ ? null
4288
+ : normalizeSessionLocationDigest(
4289
+ options.requestDigest,
4290
+ "result collection request digest",
4291
+ );
4292
+ return readVerifiedProjection(sessionId, () => {
4293
+ let eventCount = 0;
4294
+ let found = null;
4295
+ return {
4296
+ accept(event) {
4297
+ eventCount += 1;
4298
+ if (event?.type !== SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_EVENT) {
4299
+ return;
4300
+ }
4301
+ const settlement = projectSessionResultCollectionSettlement(
4302
+ sessionId,
4303
+ event,
4304
+ eventCount,
4305
+ );
4306
+ if (settlement.requestId !== requestId) return;
4307
+ if (found !== null) {
4308
+ throw new TypeError("duplicate session result collection request id");
4309
+ }
4310
+ found = settlement;
4311
+ },
4312
+ finish() {
4313
+ if (
4314
+ found !== null &&
4315
+ expectedRequestDigest !== null &&
4316
+ found.requestDigest !== expectedRequestDigest
4317
+ ) {
4318
+ throw new Error(
4319
+ "result collection request id is already bound to different inputs",
4320
+ );
4321
+ }
4322
+ return found === null
4323
+ ? null
4324
+ : sessionResultCollectionReceipt(sessionId, found);
4325
+ },
4326
+ };
4327
+ });
4328
+ }
4329
+
4330
+ export function settleSessionExecutionLocationResultCollection(
4331
+ sessionId,
4332
+ requestIdInput,
4333
+ collection,
4334
+ storage,
4335
+ ) {
4336
+ const data = createSessionResultCollectionSettlementData(
4337
+ sessionId,
4338
+ requestIdInput,
4339
+ collection,
4340
+ storage,
4341
+ );
4342
+ const prior = readVerifiedSessionExecutionLocationResultSettlement(
4343
+ sessionId,
4344
+ data.requestId,
4345
+ { requestDigest: data.requestDigest },
4346
+ );
4347
+ if (prior !== null) {
4348
+ if (prior.settlementId !== data.settlementId) {
4349
+ throw new Error(
4350
+ "result collection request id is already settled with a different result",
4351
+ );
4352
+ }
4353
+ return Object.freeze({
4354
+ ...prior,
4355
+ settlementAppended: false,
4356
+ recovered: true,
4357
+ });
4358
+ }
4359
+ try {
4360
+ appendAuthorityEventIfHead(
4361
+ sessionId,
4362
+ SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_EVENT,
4363
+ data,
4364
+ data.source.headHash,
4365
+ );
4366
+ } catch (error) {
4367
+ const raced = readVerifiedSessionExecutionLocationResultSettlement(
4368
+ sessionId,
4369
+ data.requestId,
4370
+ { requestDigest: data.requestDigest },
4371
+ );
4372
+ if (raced === null || raced.settlementId !== data.settlementId) {
4373
+ throw error;
4374
+ }
4375
+ return Object.freeze({
4376
+ ...raced,
4377
+ settlementAppended: false,
4378
+ recovered: true,
4379
+ });
4380
+ }
4381
+ runSessionScaleFaultHook(
4382
+ "afterResultCollectionSettlementAppend",
4383
+ Object.freeze({
4384
+ sessionId,
4385
+ requestId: data.requestId,
4386
+ requestDigest: data.requestDigest,
4387
+ settlementId: data.settlementId,
4388
+ }),
4389
+ );
4390
+ const receipt = readVerifiedSessionExecutionLocationResultSettlement(
4391
+ sessionId,
4392
+ data.requestId,
4393
+ { requestDigest: data.requestDigest },
4394
+ );
4395
+ if (receipt === null || receipt.settlementId !== data.settlementId) {
4396
+ throw new Error("result collection settlement is not canonical");
4397
+ }
4398
+ return Object.freeze({
4399
+ ...receipt,
4400
+ settlementAppended: true,
4401
+ recovered: false,
4402
+ });
4403
+ }
4404
+
4405
+ function normalizeSessionResultApplyId(value) {
4406
+ const applyId = boundedAuthorityString(
4407
+ value,
4408
+ "result apply id",
4409
+ 128,
4410
+ );
4411
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,127}$/u.test(applyId)) {
4412
+ throw new TypeError("result apply id is invalid");
4413
+ }
4414
+ return applyId;
4415
+ }
4416
+
4417
+ function normalizeSessionResultApplyGit(input) {
4418
+ const value = exactRecord(
4419
+ input,
4420
+ ["rootDigest", "commit"],
4421
+ "result apply source git",
4422
+ );
4423
+ const commit = String(value.commit || "").toLowerCase();
4424
+ if (!/^[a-f0-9]{40,64}$/u.test(commit)) {
4425
+ throw new TypeError("result apply source git commit is invalid");
4426
+ }
4427
+ return Object.freeze({
4428
+ rootDigest: normalizeSessionLocationDigest(
4429
+ value.rootDigest,
4430
+ "result apply source git root digest",
4431
+ ),
4432
+ commit,
4433
+ });
4434
+ }
4435
+
4436
+ function normalizeSessionResultApplyPreparedTransaction(input) {
4437
+ const value = exactRecord(
4438
+ input,
4439
+ [
4440
+ "id",
4441
+ "checkpointId",
4442
+ "checkpointDigest",
4443
+ "coverage",
4444
+ "externalSideEffects",
4445
+ ],
4446
+ "result apply prepared transaction",
4447
+ );
4448
+ const id = boundedAuthorityString(value.id, "result apply transaction id", 192);
4449
+ const checkpointId = boundedAuthorityString(
4450
+ value.checkpointId,
4451
+ "result apply checkpoint id",
4452
+ 192,
4453
+ );
4454
+ if (
4455
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,191}$/u.test(id) ||
4456
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,191}$/u.test(checkpointId) ||
4457
+ !["full", "partial"].includes(value.coverage) ||
4458
+ value.externalSideEffects !== false
4459
+ ) {
4460
+ throw new TypeError("result apply prepared transaction is invalid");
4461
+ }
4462
+ return Object.freeze({
4463
+ id,
4464
+ checkpointId,
4465
+ checkpointDigest: normalizeSessionLocationDigest(
4466
+ value.checkpointDigest,
4467
+ "result apply checkpoint digest",
4468
+ ),
4469
+ coverage: value.coverage,
4470
+ externalSideEffects: false,
4471
+ });
4472
+ }
4473
+
4474
+ function normalizeSessionResultApplyTerminalTransaction(input) {
4475
+ const value = exactRecord(
4476
+ input,
4477
+ [
4478
+ "id",
4479
+ "checkpointId",
4480
+ "checkpointDigest",
4481
+ "evidenceDigest",
4482
+ "writeManifestDigest",
4483
+ "coverage",
4484
+ "fileCoverage",
4485
+ "externalSideEffects",
4486
+ "uncoveredPaths",
4487
+ ],
4488
+ "result apply terminal transaction",
4489
+ );
4490
+ const prepared = normalizeSessionResultApplyPreparedTransaction({
4491
+ id: value.id,
4492
+ checkpointId: value.checkpointId,
4493
+ checkpointDigest: value.checkpointDigest,
4494
+ coverage: value.coverage,
4495
+ externalSideEffects: value.externalSideEffects,
4496
+ });
4497
+ if (
4498
+ !["full", "partial", "none"].includes(value.fileCoverage) ||
4499
+ !Array.isArray(value.uncoveredPaths) ||
4500
+ value.uncoveredPaths.length > 128
4501
+ ) {
4502
+ throw new TypeError("result apply terminal transaction is invalid");
4503
+ }
4504
+ const uncoveredPaths = value.uncoveredPaths.map((entry) =>
4505
+ boundedAuthorityString(entry, "result apply uncovered path", 512),
4506
+ );
4507
+ if (
4508
+ new Set(uncoveredPaths).size !== uncoveredPaths.length ||
4509
+ uncoveredPaths.some((entry, index) =>
4510
+ index > 0 ? entry.localeCompare(uncoveredPaths[index - 1]) < 0 : false,
4511
+ )
4512
+ ) {
4513
+ throw new TypeError("result apply uncovered paths are invalid");
4514
+ }
4515
+ return Object.freeze({
4516
+ ...prepared,
4517
+ evidenceDigest: normalizeSessionLocationDigest(
4518
+ value.evidenceDigest,
4519
+ "result apply evidence digest",
4520
+ ),
4521
+ writeManifestDigest: normalizeSessionLocationDigest(
4522
+ value.writeManifestDigest,
4523
+ "result apply write manifest digest",
4524
+ ),
4525
+ fileCoverage: value.fileCoverage,
4526
+ uncoveredPaths: Object.freeze(uncoveredPaths),
4527
+ });
4528
+ }
4529
+
4530
+ function normalizeSessionResultApplyReview(review, settlement) {
4531
+ if (
4532
+ review?.schema !== "cc-execution-location-result-review/v1" ||
4533
+ review.sessionId !== settlement.sessionId ||
4534
+ review.requestId !== settlement.requestId ||
4535
+ review.resultId !== settlement.resultId ||
4536
+ review.handoffId !== settlement.handoffId ||
4537
+ review.settlement?.settlementId !== settlement.settlementId ||
4538
+ review.settlement?.eventHash !== settlement.settlementEventHash ||
4539
+ review.settlement?.eventCount !== settlement.settlementEventCount ||
4540
+ review.settlement?.receiptDigest !== settlement.receiptDigest ||
4541
+ review.bundleDigest !== settlement.bundleDigest ||
4542
+ review.verificationDigest !== settlement.verificationDigest ||
4543
+ review.collectionDigest !== settlement.collectionDigest ||
4544
+ review.diff?.digest == null ||
4545
+ review.applied !== false ||
4546
+ review.applyPolicy?.automaticApply !== false
4547
+ ) {
4548
+ throw new TypeError("result apply review authority is invalid");
4549
+ }
4550
+ return Object.freeze({
4551
+ reviewDigest: normalizeSessionLocationDigest(
4552
+ review.reviewDigest,
4553
+ "result apply review digest",
4554
+ ),
4555
+ diffDigest: normalizeSessionLocationDigest(
4556
+ review.diff.digest,
4557
+ "result apply diff digest",
4558
+ ),
4559
+ });
4560
+ }
4561
+
4562
+ function createSessionResultApplyReservationData(
4563
+ sessionId,
4564
+ applyIdInput,
4565
+ review,
4566
+ settlement,
4567
+ sourceGit,
4568
+ transaction,
4569
+ ) {
4570
+ const applyId = normalizeSessionResultApplyId(applyIdInput);
4571
+ const reviewed = normalizeSessionResultApplyReview(review, settlement);
4572
+ const material = {
4573
+ schema: SESSION_EXECUTION_LOCATION_RESULT_APPLY_RESERVATION_SCHEMA,
4574
+ applyId,
4575
+ requestId: settlement.requestId,
4576
+ reviewDigest: reviewed.reviewDigest,
4577
+ settlementId: settlement.settlementId,
4578
+ settlementEventHash: settlement.settlementEventHash,
4579
+ settlementEventCount: settlement.settlementEventCount,
4580
+ bundleDigest: settlement.bundleDigest,
4581
+ diffDigest: reviewed.diffDigest,
4582
+ sourceGit: normalizeSessionResultApplyGit(sourceGit),
4583
+ transaction: normalizeSessionResultApplyPreparedTransaction(transaction),
4584
+ applied: false,
4585
+ };
4586
+ return Object.freeze({
4587
+ ...material,
4588
+ reservationId: sessionLocationDigest(
4589
+ "chainlesschain.session-execution-location-result-apply-reservation-id.v1\0",
4590
+ { sessionId, ...material },
4591
+ ),
4592
+ });
4593
+ }
4594
+
4595
+ function projectSessionResultApplyReservation(
4596
+ sessionId,
4597
+ event,
4598
+ eventCount,
4599
+ settlement,
4600
+ ) {
4601
+ const data = exactRecord(
4602
+ event?.data,
4603
+ [
4604
+ "schema",
4605
+ "reservationId",
4606
+ "applyId",
4607
+ "requestId",
4608
+ "reviewDigest",
4609
+ "settlementId",
4610
+ "settlementEventHash",
4611
+ "settlementEventCount",
4612
+ "bundleDigest",
4613
+ "diffDigest",
4614
+ "sourceGit",
4615
+ "transaction",
4616
+ "applied",
4617
+ ],
4618
+ "session result apply reservation",
4619
+ );
4620
+ if (
4621
+ !settlement ||
4622
+ settlement.settlementId !== data.settlementId ||
4623
+ settlement.requestId !== data.requestId ||
4624
+ settlement.bundleDigest !== data.bundleDigest ||
4625
+ settlement.eventHash !== data.settlementEventHash ||
4626
+ settlement.eventCount !== data.settlementEventCount ||
4627
+ event?.prevHash !== settlement.eventHash ||
4628
+ eventCount !== settlement.eventCount + 1 ||
4629
+ data.applied !== false
4630
+ ) {
4631
+ throw new TypeError("session result apply reservation predecessor is invalid");
4632
+ }
4633
+ const material = {
4634
+ schema: SESSION_EXECUTION_LOCATION_RESULT_APPLY_RESERVATION_SCHEMA,
4635
+ applyId: normalizeSessionResultApplyId(data.applyId),
4636
+ requestId: normalizeSessionResultCollectionRequestId(data.requestId),
4637
+ reviewDigest: normalizeSessionLocationDigest(
4638
+ data.reviewDigest,
4639
+ "result apply review digest",
4640
+ ),
4641
+ settlementId: normalizeSessionLocationDigest(
4642
+ data.settlementId,
4643
+ "result apply settlement id",
4644
+ ),
4645
+ settlementEventHash: normalizeSessionLocationHead(
4646
+ data.settlementEventHash,
4647
+ "result apply settlement event hash",
4648
+ ),
4649
+ settlementEventCount: normalizeSessionLocationEventCount(
4650
+ data.settlementEventCount,
4651
+ "result apply settlement event count",
4652
+ ),
4653
+ bundleDigest: normalizeSessionLocationDigest(
4654
+ data.bundleDigest,
4655
+ "result apply bundle digest",
4656
+ ),
4657
+ diffDigest: normalizeSessionLocationDigest(
4658
+ data.diffDigest,
4659
+ "result apply diff digest",
4660
+ ),
4661
+ sourceGit: normalizeSessionResultApplyGit(data.sourceGit),
4662
+ transaction: normalizeSessionResultApplyPreparedTransaction(
4663
+ data.transaction,
4664
+ ),
4665
+ applied: false,
4666
+ };
4667
+ const reservationId = sessionLocationDigest(
4668
+ "chainlesschain.session-execution-location-result-apply-reservation-id.v1\0",
4669
+ { sessionId, ...material },
4670
+ );
4671
+ if (data.reservationId !== reservationId) {
4672
+ throw new TypeError("session result apply reservation id is invalid");
4673
+ }
4674
+ return Object.freeze({
4675
+ ...material,
4676
+ reservationId,
4677
+ eventHash: event.hash,
4678
+ eventCount,
4679
+ at: new Date(event.timestamp).toISOString(),
4680
+ });
4681
+ }
4682
+
4683
+ function createSessionResultApplyTerminalData(
4684
+ sessionId,
4685
+ reservation,
4686
+ source,
4687
+ outcome,
4688
+ transaction,
4689
+ ) {
4690
+ if (!["applied", "rolled_back"].includes(outcome)) {
4691
+ throw new TypeError("result apply terminal outcome is invalid");
4692
+ }
4693
+ const material = {
4694
+ schema: SESSION_EXECUTION_LOCATION_RESULT_APPLY_TERMINAL_SCHEMA,
4695
+ applyId: reservation.applyId,
4696
+ reservationId: reservation.reservationId,
4697
+ reviewDigest: reservation.reviewDigest,
4698
+ settlementId: reservation.settlementId,
4699
+ bundleDigest: reservation.bundleDigest,
4700
+ diffDigest: reservation.diffDigest,
4701
+ source: Object.freeze({
4702
+ headHash: normalizeSessionLocationHead(
4703
+ source.headHash,
4704
+ "result apply terminal source head",
4705
+ ),
4706
+ eventCount: normalizeSessionLocationEventCount(
4707
+ source.eventCount,
4708
+ "result apply terminal source event count",
4709
+ ),
4710
+ }),
4711
+ sourceGit: reservation.sourceGit,
4712
+ transaction: normalizeSessionResultApplyTerminalTransaction(transaction),
4713
+ outcome,
4714
+ applied: outcome === "applied",
4715
+ };
4716
+ return Object.freeze({
4717
+ ...material,
4718
+ terminalId: sessionLocationDigest(
4719
+ "chainlesschain.session-execution-location-result-apply-terminal-id.v1\0",
4720
+ { sessionId, ...material },
4721
+ ),
4722
+ });
4723
+ }
4724
+
4725
+ function projectSessionResultApplyTerminal(
4726
+ sessionId,
4727
+ event,
4728
+ eventCount,
4729
+ reservation,
4730
+ ) {
4731
+ const data = exactRecord(
4732
+ event?.data,
4733
+ [
4734
+ "schema",
4735
+ "terminalId",
4736
+ "applyId",
4737
+ "reservationId",
4738
+ "reviewDigest",
4739
+ "settlementId",
4740
+ "bundleDigest",
4741
+ "diffDigest",
4742
+ "source",
4743
+ "sourceGit",
4744
+ "transaction",
4745
+ "outcome",
4746
+ "applied",
4747
+ ],
4748
+ "session result apply terminal",
4749
+ );
4750
+ const source = exactRecord(
4751
+ data.source,
4752
+ ["headHash", "eventCount"],
4753
+ "session result apply terminal source",
4754
+ );
4755
+ if (
4756
+ !reservation ||
4757
+ data.applyId !== reservation.applyId ||
4758
+ data.reservationId !== reservation.reservationId ||
4759
+ data.reviewDigest !== reservation.reviewDigest ||
4760
+ data.settlementId !== reservation.settlementId ||
4761
+ data.bundleDigest !== reservation.bundleDigest ||
4762
+ data.diffDigest !== reservation.diffDigest ||
4763
+ event?.prevHash !== source.headHash ||
4764
+ eventCount !== Number(source.eventCount) + 1 ||
4765
+ data.applied !== (data.outcome === "applied")
4766
+ ) {
4767
+ throw new TypeError("session result apply terminal authority is invalid");
4768
+ }
4769
+ const normalized = createSessionResultApplyTerminalData(
4770
+ sessionId,
4771
+ reservation,
4772
+ source,
4773
+ data.outcome,
4774
+ data.transaction,
4775
+ );
4776
+ if (
4777
+ data.terminalId !== normalized.terminalId ||
4778
+ canonicalJson(data.sourceGit, "resultApplySourceGit") !==
4779
+ canonicalJson(reservation.sourceGit, "resultApplySourceGit")
4780
+ ) {
4781
+ throw new TypeError("session result apply terminal id is invalid");
4782
+ }
4783
+ return Object.freeze({
4784
+ ...normalized,
4785
+ eventHash: event.hash,
4786
+ eventCount,
4787
+ at: new Date(event.timestamp).toISOString(),
4788
+ });
4789
+ }
4790
+
4791
+ function sessionResultApplyReceipt(sessionId, reservation, terminal) {
4792
+ const material = {
4793
+ schema: SESSION_EXECUTION_LOCATION_RESULT_APPLY_RECEIPT_SCHEMA,
4794
+ sessionId,
4795
+ applyId: reservation.applyId,
4796
+ requestId: reservation.requestId,
4797
+ status: terminal?.outcome || "reserved",
4798
+ reviewDigest: reservation.reviewDigest,
4799
+ settlementId: reservation.settlementId,
4800
+ bundleDigest: reservation.bundleDigest,
4801
+ diffDigest: reservation.diffDigest,
4802
+ sourceGit: reservation.sourceGit,
4803
+ transaction: terminal?.transaction || reservation.transaction,
4804
+ reservation: Object.freeze({
4805
+ reservationId: reservation.reservationId,
4806
+ eventHash: reservation.eventHash,
4807
+ eventCount: reservation.eventCount,
4808
+ }),
4809
+ terminal: terminal
4810
+ ? Object.freeze({
4811
+ terminalId: terminal.terminalId,
4812
+ eventHash: terminal.eventHash,
4813
+ eventCount: terminal.eventCount,
4814
+ outcome: terminal.outcome,
4815
+ })
4816
+ : null,
4817
+ applied: terminal?.outcome === "applied",
4818
+ };
4819
+ return Object.freeze({
4820
+ ...material,
4821
+ receiptDigest: sessionLocationDigest(
4822
+ "chainlesschain.session-execution-location-result-apply-receipt.v1\0",
4823
+ material,
4824
+ ),
4825
+ });
4826
+ }
4827
+
4828
+ export function readVerifiedSessionExecutionLocationResultApply(
4829
+ sessionId,
4830
+ applyIdInput,
4831
+ ) {
4832
+ const applyId = normalizeSessionResultApplyId(applyIdInput);
4833
+ return readVerifiedProjection(sessionId, () => {
4834
+ let eventCount = 0;
4835
+ const settlements = new Map();
4836
+ const reservations = new Map();
4837
+ const terminals = new Map();
4838
+ return {
4839
+ accept(event) {
4840
+ eventCount += 1;
4841
+ if (event?.type === SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_EVENT) {
4842
+ const settlement = projectSessionResultCollectionSettlement(
4843
+ sessionId,
4844
+ event,
4845
+ eventCount,
4846
+ );
4847
+ settlements.set(settlement.settlementId, settlement);
4848
+ return;
4849
+ }
4850
+ if (event?.type === SESSION_EXECUTION_LOCATION_RESULT_APPLY_RESERVATION_EVENT) {
4851
+ const settlement = settlements.get(event?.data?.settlementId) || null;
4852
+ const reservation = projectSessionResultApplyReservation(
4853
+ sessionId,
4854
+ event,
4855
+ eventCount,
4856
+ settlement,
4857
+ );
4858
+ if (
4859
+ reservations.has(reservation.applyId) ||
4860
+ [...reservations.values()].some(
4861
+ (entry) => entry.reservationId === reservation.reservationId,
4862
+ )
4863
+ ) {
4864
+ throw new TypeError("duplicate session result apply reservation");
4865
+ }
4866
+ reservations.set(reservation.applyId, reservation);
4867
+ return;
4868
+ }
4869
+ if (event?.type === SESSION_EXECUTION_LOCATION_RESULT_APPLY_TERMINAL_EVENT) {
4870
+ const reservation = reservations.get(event?.data?.applyId) || null;
4871
+ const terminal = projectSessionResultApplyTerminal(
4872
+ sessionId,
4873
+ event,
4874
+ eventCount,
4875
+ reservation,
4876
+ );
4877
+ if (terminals.has(terminal.applyId)) {
4878
+ throw new TypeError("duplicate session result apply terminal");
4879
+ }
4880
+ terminals.set(terminal.applyId, terminal);
4881
+ }
4882
+ },
4883
+ finish() {
4884
+ const reservation = reservations.get(applyId) || null;
4885
+ return reservation === null
4886
+ ? null
4887
+ : sessionResultApplyReceipt(
4888
+ sessionId,
4889
+ reservation,
4890
+ terminals.get(applyId) || null,
4891
+ );
4892
+ },
4893
+ };
4894
+ });
4895
+ }
4896
+
4897
+ export function reserveSessionExecutionLocationResultApply(
4898
+ sessionId,
4899
+ applyId,
4900
+ review,
4901
+ sourceGit,
4902
+ transaction,
4903
+ ) {
4904
+ const settlement = readVerifiedSessionExecutionLocationResultSettlement(
4905
+ sessionId,
4906
+ review?.requestId,
4907
+ );
4908
+ if (settlement === null) {
4909
+ throw new Error("result apply settlement was not found");
4910
+ }
4911
+ const data = createSessionResultApplyReservationData(
4912
+ sessionId,
4913
+ applyId,
4914
+ review,
4915
+ settlement,
4916
+ sourceGit,
4917
+ transaction,
4918
+ );
4919
+ const prior = readVerifiedSessionExecutionLocationResultApply(
4920
+ sessionId,
4921
+ data.applyId,
4922
+ );
4923
+ if (prior !== null) {
4924
+ if (prior.reservation.reservationId !== data.reservationId) {
4925
+ throw new Error("result apply id is already bound to different inputs");
4926
+ }
4927
+ return Object.freeze({ ...prior, reservationAppended: false, recovered: true });
4928
+ }
4929
+ appendAuthorityEventIfHead(
4930
+ sessionId,
4931
+ SESSION_EXECUTION_LOCATION_RESULT_APPLY_RESERVATION_EVENT,
4932
+ data,
4933
+ settlement.settlementEventHash,
4934
+ );
4935
+ runSessionScaleFaultHook(
4936
+ "afterResultApplyReservationAppend",
4937
+ Object.freeze({ sessionId, applyId: data.applyId, reservationId: data.reservationId }),
4938
+ );
4939
+ const receipt = readVerifiedSessionExecutionLocationResultApply(
4940
+ sessionId,
4941
+ data.applyId,
4942
+ );
4943
+ if (
4944
+ receipt === null ||
4945
+ receipt.reservation.reservationId !== data.reservationId
4946
+ ) {
4947
+ throw new Error("result apply reservation is not canonical");
4948
+ }
4949
+ return Object.freeze({ ...receipt, reservationAppended: true, recovered: false });
4950
+ }
4951
+
4952
+ export function settleSessionExecutionLocationResultApply(
4953
+ sessionId,
4954
+ applyIdInput,
4955
+ outcome,
4956
+ transaction,
4957
+ ) {
4958
+ const applyId = normalizeSessionResultApplyId(applyIdInput);
4959
+ const prior = readVerifiedSessionExecutionLocationResultApply(sessionId, applyId);
4960
+ if (prior === null) {
4961
+ throw new Error("result apply reservation was not found");
4962
+ }
4963
+ const normalizedTransaction = normalizeSessionResultApplyTerminalTransaction(
4964
+ transaction,
4965
+ );
4966
+ if (prior.terminal !== null) {
4967
+ if (
4968
+ prior.status !== outcome ||
4969
+ canonicalJson(prior.transaction, "resultApplyTransaction") !==
4970
+ canonicalJson(normalizedTransaction, "resultApplyTransaction")
4971
+ ) {
4972
+ throw new Error("result apply is already settled differently");
4973
+ }
4974
+ return Object.freeze({ ...prior, terminalAppended: false, recovered: true });
4975
+ }
4976
+ const current = getVerifiedSessionExecutionLocationAuthority(sessionId);
4977
+ const reservation = Object.freeze({
4978
+ applyId: prior.applyId,
4979
+ requestId: prior.requestId,
4980
+ reservationId: prior.reservation.reservationId,
4981
+ reviewDigest: prior.reviewDigest,
4982
+ settlementId: prior.settlementId,
4983
+ bundleDigest: prior.bundleDigest,
4984
+ diffDigest: prior.diffDigest,
4985
+ sourceGit: prior.sourceGit,
4986
+ });
4987
+ const data = createSessionResultApplyTerminalData(
4988
+ sessionId,
4989
+ reservation,
4990
+ { headHash: current.headHash, eventCount: current.eventCount },
4991
+ outcome,
4992
+ normalizedTransaction,
4993
+ );
4994
+ try {
4995
+ appendAuthorityEventIfHead(
4996
+ sessionId,
4997
+ SESSION_EXECUTION_LOCATION_RESULT_APPLY_TERMINAL_EVENT,
4998
+ data,
4999
+ current.headHash,
5000
+ );
5001
+ } catch (error) {
5002
+ const raced = readVerifiedSessionExecutionLocationResultApply(
5003
+ sessionId,
5004
+ applyId,
5005
+ );
5006
+ if (
5007
+ raced?.status !== outcome ||
5008
+ canonicalJson(raced.transaction, "resultApplyTransaction") !==
5009
+ canonicalJson(normalizedTransaction, "resultApplyTransaction")
5010
+ ) {
5011
+ throw error;
5012
+ }
5013
+ return Object.freeze({ ...raced, terminalAppended: false, recovered: true });
5014
+ }
5015
+ runSessionScaleFaultHook(
5016
+ "afterResultApplyTerminalAppend",
5017
+ Object.freeze({ sessionId, applyId, terminalId: data.terminalId }),
5018
+ );
5019
+ const receipt = readVerifiedSessionExecutionLocationResultApply(sessionId, applyId);
5020
+ if (receipt?.terminal?.terminalId !== data.terminalId) {
5021
+ throw new Error("result apply terminal is not canonical");
5022
+ }
5023
+ return Object.freeze({ ...receipt, terminalAppended: true, recovered: false });
5024
+ }
5025
+
3816
5026
  /**
3817
5027
  * Install one exact, source-verified transcript revision into an empty target
3818
5028
  * session store. The target validates hash chain, transcript structure, exact