chainlesschain 0.166.6 → 0.166.9

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 (214) hide show
  1. package/README.md +21 -0
  2. package/package.json +5 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-CVnFjTfG.js → AIOps-DJvpifGx.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-BxkwuuQC.js → ActionButton-D2UhuF_A.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-C2670q6z.js → Analytics-C9ho9obu.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CU_rylW6.js → AppLayout-BvRCpFK3.js} +3 -3
  8. package/src/assets/web-panel/assets/{Artifacts-DGJmYqnj.js → Artifacts-jxrySvpk.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-BZOQbINJ.js → Audit-ovEw0ZYl.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-DghB4QwF.js → BackgroundAgents-D7H5z6zS.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-l0mwPbta.js → Backup-BuXob8za.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-Bv3WSZOh.js → BaseInput-CtnszuQ2.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-s88nBdvt.js → Chat-B_mYE8fJ.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-Z8CBuB1a.js → ChatBubbleRenderer-DaiA6CsX.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-B5icasEs.js → Checkbox-ierdtcJD.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-CsUFqNud.js → Codegen-3VKPJD_B.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-DlBtClaW.js → Col-1EdMyf5P.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-xRn1IdLB.js → Community-D6H7UA8K.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-naIr8a_o.js → Compact-BBAZvYIm.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-Dp9esfFE.js → Compliance-CgsTrAoj.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DQlMYJB-.js → Cowork-tnZgLoTE.js} +4 -4
  22. package/src/assets/web-panel/assets/{Cron-Cd0oNLzJ.js → Cron-CPpZw2Nh.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-BtDIx3XX.js → Crosschain-BymBcp5z.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-BOlpzEwg.js → DID-DKPxS_K1.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-DV15Axk1.js → Dashboard-DvJhEmH9.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-COXrewN1.js → Dropdown-b8iQyQIZ.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-EjIt0Cm7.js → EmailListRenderer--0-A-zKb.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DJlhwb-R.js → FamilyGuardDashboard-C12iDN06.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BMiFl82k.js → Federation-BRhaE2Z8.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-BUcDQyxn.js → FormItemContext-C4dnq7yf.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-C25uFxvK.js → GenericCardRenderer-CGAdbR5n.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-D20uaEUU.js → Git-4eA2fYzL.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-CQxYJjCX.js → Governance-BJuY9Y-9.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-m-sczpS5.js → Inference-DZ5Dy4up.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-CBsIlU0S.js → KnowledgeGraph-BMTjRs4A.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-D0-5bqeu.js → Logs-BKEeQEfJ.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-B05DgASC.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-CwDGFu2Q.js → Marketplace-Dhho4fEg.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-7FxJ3omT.js → McpTools-BW6xxSlU.js} +2 -2
  40. package/src/assets/web-panel/assets/{Memory-DOVyb59U.js → Memory-mPqlpSkq.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-DZXl-Hje.js → MobileBridge-Cb9N_DQI.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-DlZ8tRXt.js → MobileProjects-BNs8tah_.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-D7Pjx1s_.js → Mtc-CaxBt8tn.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-BND7lX8p.js → MtcAudit-DRPQbp3t.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-BknS7B-p.js → Multisig-CRm-d8bK.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-7C2-KPHt.js → NLProgramming-BCCk3LPs.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-DNWdTndN.js → Notes-Cv8SN8gN.js} +4 -4
  48. package/src/assets/web-panel/assets/{NotificationSettings-DCm4KcJZ.js → NotificationSettings-CggIvTh5.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-DyVwwjJx.js → OrderTableRenderer-BW3_bV12.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-Dl2O_qJ9.js → Organization-BuRE-VCO.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-BOFCvk9Q.js → Overflow-DBrm1gju.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-DgdVowY1.js → P2P-CWVnDYgS.js} +2 -2
  53. package/src/assets/web-panel/assets/PdhVaultBrowser-8RKUIpte.js +7 -0
  54. package/src/assets/web-panel/assets/{Permissions-BHNEUUwa.js → Permissions-tDUAxogW.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-CaZbrOdz.js → PersonalDataHub-Dv2-CFis.js} +4 -4
  56. package/src/assets/web-panel/assets/{Pipeline-DJDnoXmE.js → Pipeline-DM6kvFni.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-CBQr2eX8.js → Privacy-DzK-yL0d.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-Yghqa06z.js → ProjectInit-B5UrNpkj.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-HBAtJi8U.js → ProjectSettings-CxJD43oW.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-Z2Orm8Ma.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-uJTz77GI.js → Providers-CYl4jRYK.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-k3M5ouTp.js → QrScannerModal-DeH2T0fH.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-CMji45PH.js → QuickAsk-Bw9k_kTk.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-DyoZYPls.js → Recommend-Bl_jGwoi.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-d6u01Kq0.js +5 -0
  66. package/src/assets/web-panel/assets/{Reputation-D4hIs4vV.js → Reputation-Ds_Dfr-k.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-mzE-ElTg.js → Row-BpQUQTNj.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-cg7J3hI6.js → RssFeed-BatpZBGt.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-6M0TkGSZ.js → Search-D7hOObzi.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-B1GQ67qh.js → Security-dXQ4FKNt.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-D_RwU_5S.js → Services-D8wInGPa.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-TZjk-dsW.js → Skeleton-DXQCoYpM.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CG6FcaCV.js → Skills-D3oLRIVn.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-BI190QDv.js → Sla-BmP4-LnJ.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-BWmxF2Wu.js → SpeechSettings-DLj-xzro.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-CwPiGw6L.js → SyncSettings-8KKaaRMr.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-BIXgCeSk.js → Tasks-GyK42I7C.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-CQFgGCoK.js → Templates-n1y_8UBG.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-DAelEdkL.js → Tenant-B39nBph8.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-BbqWK6qh.js → Terminal-DCQoOKXe.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-cmG3zvY5.js → TimelineRenderer-BkhbDfXk.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-C8444NKU.js → Tokens-BeHIIU8D.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-C1Rpnz0I.js → Trigger-BHvWXVOb.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-u4koPiFD.js → Trust-y2WaOSto.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-oPWKn80Z.js → UkeySign-DBFeJBzt.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-D0CUUY_5.js → VideoEditing-BEOWitC-.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-fu9pIAbt.js → Wallet-BITedTe6.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-Bc5ciuOx.js → WebAuthn-DMwlJVin.js} +2 -2
  89. package/src/assets/web-panel/assets/{WorkflowEditor-BCin4_4N.js → WorkflowEditor-CKfGFEu1.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-B2jbM-XN.js → chat-DR6gnBGF.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-CUVoUQ_2.js → colors-C_Hw5NCn.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-DgOGpkRH.js → compact-item-B8IPwsEu.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-DIxU6eKI.js → createContext-D-u4JVnJ.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-Cq6lSd_q.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-DoKRKMav.js → hasIn-CZubdS4D.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-ByjrulIZ.js → index-11ASqx-A.js} +1 -1
  97. package/src/assets/web-panel/assets/index-BQ3213fz.js +1 -0
  98. package/src/assets/web-panel/assets/{index-BwYofQJg.js → index-BXS6wYJZ.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CLdpHe6w.js → index-Bi21Etg4.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-2flsPFIX.js → index-Bizm87cX.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BXb-Smmm.js → index-Bv2132PO.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-B5ySiGYy.js → index-BzoFanEQ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CWbL1-N0.js → index-C25rOz7O.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Cj-us-D_.js → index-C2VmtNaQ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C9TsO9T9.js → index-Cbm8F0M2.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-eTWPaeBI.js → index-CfniPP5p.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-D2yo6ast.js → index-Cg2bCeol.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CPXdBnGi.js → index-CiXkhOkY.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BCLeNqIL.js → index-Cl5RpreD.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BtSPhEyC.js → index-CqmLw8cs.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-eYxUASSG.js → index-Ctje8Vl3.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-i5MB455u.js → index-D1w96gg9.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CpvyOt5Z.js → index-D47jt8ET.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CeWSw-z5.js → index-DJ6pG79m.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B3F_p8NA.js → index-DTosx2Wu.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B9mSYovv.js → index-DY6MHo9D.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DJMHnbmu.js → index-DcFjRT-K.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-D-ufbAJB.js → index-DfnzrUxU.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BFUprhNd.js → index-DjRrqooR.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Co4lDEk-.js → index-DmRcgiYT.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DGTZdZOE.js → index-DpjHpRoq.js} +3 -3
  122. package/src/assets/web-panel/assets/{index-DHugFl3v.js → index-Dt-w3xQ7.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-B-f6l4Vm.js → index-DuOU5apg.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DtyAuGOm.js → index-LvjAKDSl.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-be8SonCh.js → index-_nL79NT8.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BRMEO2Tl.js → index-auyNYjLo.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-C88m9lsi.js → index-cVqbas5C.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CqlwIjJx.js → index-ffe7bvqP.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DpTFx8Xx.js → index-idZKyADQ.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Cskz--fd.js → index-k1Xa5iw1.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CF80xxPG.js → index-mYZJxGH6.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Ds8r3Fzb.js → index-rYBHSDcJ.js} +1 -1
  133. package/src/assets/web-panel/assets/index-vJagfET2.js +1 -0
  134. package/src/assets/web-panel/assets/{index-C846lPGD.js → index-xoNssgz_.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-B4chl7iR.js → initDefaultProps-lcU_dT2r.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-DruN9h96.js → motion-Dc7UNXZ1.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-Cl0UtCgU.js → move-Cll8ZXaL.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-FX2ttw70.js → mtc-parser-CAb_yLIM.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-BDCneY46.js → omit-DurYMyTe.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-DycsEg8b.js → pickAttrs-BITQyOlw.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-Bc-dBuMv.js → placementArrow-Dg1rH91i.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve--Wwaf8lu.js → responsiveObserve-D_EWIeac.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-vDmHQqHH.js → slide-lK4d3zsh.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-9c52yv3G.js → statusUtils-Bflq-Git.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-BT4BiO6_.js → styleChecker-Ccp0I-wt.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-C7XxWPcP.js → useFlexGapSupport-CYZbByYA.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-BHoMqh4i.js → useFs-B_x0nxFD.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-BOLxvsAG.js → usePersonalDataHub-DW55rL85.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-CA7poeeP.js → vnode-Ca6MH3W8.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-B_sAn-co.js → zoom-NdHelOog.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +1 -1
  153. package/src/commands/graph.js +215 -5
  154. package/src/commands/orchestrate.js +61 -9
  155. package/src/commands/team-distributed.js +342 -2
  156. package/src/commands/team.js +169 -7
  157. package/src/data/changelog.json +46 -0
  158. package/src/gateways/ws/message-dispatcher.js +4 -0
  159. package/src/gateways/ws/session-protocol.js +89 -11
  160. package/src/gateways/ws/ws-agent-handler.js +65 -9
  161. package/src/gateways/ws/ws-approval-gate.js +181 -16
  162. package/src/gateways/ws/ws-server.js +16 -6
  163. package/src/generated/cc-agent-protocol.schema.json +154 -3
  164. package/src/lib/agent-team/task-lease.js +487 -3
  165. package/src/lib/agent-team/team-agent-stream.js +16 -0
  166. package/src/lib/agent-team/team-distributed-graph-bridge.js +257 -0
  167. package/src/lib/agent-team/team-distributed-graph-writer.js +523 -0
  168. package/src/lib/agent-team/team-distributed-queue.js +251 -0
  169. package/src/lib/agent-team/team-graph-runtime-adapter.js +1918 -0
  170. package/src/lib/agent-team/team-runner.js +285 -3
  171. package/src/lib/app-server/graph-runtime.js +1078 -0
  172. package/src/lib/app-server/rollout-store.js +32 -0
  173. package/src/lib/app-server/server.js +200 -0
  174. package/src/lib/approval-grant-ledger.js +69 -0
  175. package/src/lib/autonomous-agent.js +11 -0
  176. package/src/lib/codex-app-server-adapter.js +11 -20
  177. package/src/lib/cowork-graph-authority-adapter.js +455 -0
  178. package/src/lib/dynamic-workflow-facade.js +83 -16
  179. package/src/lib/graph-kernel/adapters.js +93 -20
  180. package/src/lib/graph-kernel/authority.js +324 -0
  181. package/src/lib/graph-kernel/compiler.js +67 -21
  182. package/src/lib/graph-kernel/cutover-authority-resolver.js +245 -0
  183. package/src/lib/graph-kernel/cutover-ledger.js +692 -0
  184. package/src/lib/graph-kernel/event-store.js +15 -1
  185. package/src/lib/graph-kernel/graph-runtime-surfaces.json +1427 -0
  186. package/src/lib/graph-kernel/index.js +4 -0
  187. package/src/lib/graph-kernel/migration-saga.js +309 -0
  188. package/src/lib/graph-kernel/retirement-evidence.js +567 -0
  189. package/src/lib/graph-kernel/runtime-surface-manifest.js +481 -0
  190. package/src/lib/graph-kernel/runtime.js +737 -38
  191. package/src/lib/graph-kernel/store-cutover-evidence.js +354 -0
  192. package/src/lib/graph-kernel/trace-reducer.js +6 -0
  193. package/src/lib/graph-kernel/trigger-adapter.js +60 -3
  194. package/src/lib/interaction-adapter.js +61 -9
  195. package/src/lib/legacy-runtime-authority.js +160 -0
  196. package/src/lib/orchestrator.js +28 -0
  197. package/src/lib/policy-decision-event.js +149 -0
  198. package/src/lib/process-execution-broker/platform-sandbox.js +15 -1
  199. package/src/lib/record-replay/index.js +1 -0
  200. package/src/lib/record-replay/playwright-ui-driver.js +327 -0
  201. package/src/lib/scheduler-kernel/graph-authority-adapter.js +512 -0
  202. package/src/lib/scheduler-kernel/runtime.js +75 -2
  203. package/src/lib/webhook-security.js +484 -36
  204. package/src/runtime/coding-agent-events.cjs +13 -11
  205. package/src/runtime/headless-runner.js +17 -1
  206. package/src/runtime/headless-stream.js +66 -3
  207. package/src/runtime/session-slash-commands.js +57 -6
  208. package/src/assets/web-panel/assets/MarkdownRenderer-BwH414Ms.js +0 -1
  209. package/src/assets/web-panel/assets/PdhVaultBrowser-BiaZfQIM.js +0 -7
  210. package/src/assets/web-panel/assets/Projects-DiCGnMjz.js +0 -1
  211. package/src/assets/web-panel/assets/RemoteSession-s1gR38IO.js +0 -5
  212. package/src/assets/web-panel/assets/devWarning-DiSlgCC4.js +0 -1
  213. package/src/assets/web-panel/assets/index-9WIQEHvv.js +0 -1
  214. package/src/assets/web-panel/assets/index-B7mDobAl.js +0 -1
@@ -0,0 +1,354 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ export const GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA =
4
+ "chainlesschain.graph-store-cutover-evidence/v1";
5
+
6
+ const DIGEST = /^sha256:[a-f0-9]{64}$/u;
7
+ const COMMIT = /^[a-f0-9]{40,64}$/u;
8
+ const STORE = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$/u;
9
+
10
+ function normalizePlatform(value) {
11
+ const platform = String(value || "")
12
+ .trim()
13
+ .toLowerCase();
14
+ if (platform === "win32") return "windows";
15
+ if (platform === "darwin") return "macos";
16
+ return platform;
17
+ }
18
+
19
+ function evidenceError(code, message, details = {}) {
20
+ const error = new Error(message);
21
+ error.name = "GraphStoreCutoverEvidenceError";
22
+ error.code = code;
23
+ Object.assign(error, details);
24
+ return error;
25
+ }
26
+
27
+ function stableValue(value) {
28
+ if (Array.isArray(value)) return value.map(stableValue);
29
+ if (!value || typeof value !== "object") return value;
30
+ return Object.fromEntries(
31
+ Object.keys(value)
32
+ .filter((key) => value[key] !== undefined)
33
+ .sort()
34
+ .map((key) => [key, stableValue(value[key])]),
35
+ );
36
+ }
37
+
38
+ export function graphStoreEvidenceDigest(value) {
39
+ return `sha256:${createHash("sha256")
40
+ .update(JSON.stringify(stableValue(value)), "utf8")
41
+ .digest("hex")}`;
42
+ }
43
+
44
+ export function assertExactCommitSha(expectedCommit, actualCommit) {
45
+ const actual = String(actualCommit || "")
46
+ .trim()
47
+ .toLowerCase();
48
+ const expected = String(expectedCommit || "")
49
+ .trim()
50
+ .toLowerCase();
51
+ if (!COMMIT.test(actual) || (expected && !COMMIT.test(expected))) {
52
+ throw evidenceError(
53
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
54
+ "expected and actual commit SHAs must be exact hexadecimal identities",
55
+ );
56
+ }
57
+ if (expected && expected !== actual) {
58
+ throw evidenceError(
59
+ "CC_GRAPH_STORE_EVIDENCE_SHA_MISMATCH",
60
+ `expected commit ${expected} does not match checked-out HEAD ${actual}`,
61
+ { expectedCommit: expected, actualCommit: actual },
62
+ );
63
+ }
64
+ return actual;
65
+ }
66
+
67
+ function exactDigest(value, field) {
68
+ const output = String(value || "");
69
+ if (!DIGEST.test(output)) {
70
+ throw evidenceError(
71
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
72
+ `${field} must be a sha256 digest`,
73
+ { field },
74
+ );
75
+ }
76
+ return output;
77
+ }
78
+
79
+ function normalizeStore(value) {
80
+ const surface = String(value?.surface || "").trim();
81
+ const entryId = String(value?.entryId || "").trim();
82
+ const store = String(value?.store || "").trim();
83
+ if (!STORE.test(surface) || !STORE.test(entryId) || !STORE.test(store)) {
84
+ throw evidenceError(
85
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
86
+ "store evidence has an invalid surface, entry, or store identifier",
87
+ );
88
+ }
89
+ if (value?.recovered !== true || Number(value?.rpoLossCount) !== 0) {
90
+ throw evidenceError(
91
+ "CC_GRAPH_STORE_EVIDENCE_RPO_FAILED",
92
+ `store evidence does not prove RPO=0 recovery: ${store}`,
93
+ { store },
94
+ );
95
+ }
96
+ return Object.freeze({
97
+ surface,
98
+ entryId,
99
+ store,
100
+ cutpointDigest: exactDigest(value.cutpointDigest, "cutpointDigest"),
101
+ recoveryReceiptDigest: exactDigest(
102
+ value.recoveryReceiptDigest,
103
+ "recoveryReceiptDigest",
104
+ ),
105
+ rollbackDrillDigest: exactDigest(
106
+ value.rollbackDrillDigest,
107
+ "rollbackDrillDigest",
108
+ ),
109
+ rpoLossCount: 0,
110
+ recovered: true,
111
+ });
112
+ }
113
+
114
+ export function createGraphStoreCutoverEvidence({
115
+ source,
116
+ commitSha,
117
+ platform,
118
+ stores,
119
+ sourceReceipts,
120
+ }) {
121
+ const record = normalizeGraphStoreCutoverEvidence(
122
+ {
123
+ schema: GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA,
124
+ status: "passed",
125
+ source,
126
+ commitSha,
127
+ platform,
128
+ stores,
129
+ sourceReceipts,
130
+ },
131
+ { requireEvidenceDigest: false },
132
+ );
133
+ const unsigned = { ...record };
134
+ delete unsigned.evidenceDigest;
135
+ return Object.freeze({
136
+ ...unsigned,
137
+ evidenceDigest: graphStoreEvidenceDigest(unsigned),
138
+ });
139
+ }
140
+
141
+ export function normalizeGraphStoreCutoverEvidence(
142
+ value,
143
+ { requireEvidenceDigest = true } = {},
144
+ ) {
145
+ if (
146
+ !value ||
147
+ typeof value !== "object" ||
148
+ Array.isArray(value) ||
149
+ value.schema !== GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA ||
150
+ value.status !== "passed"
151
+ ) {
152
+ throw evidenceError(
153
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
154
+ "store cutover evidence schema or status is invalid",
155
+ );
156
+ }
157
+ const source = String(value.source || "").trim();
158
+ const commitSha = String(value.commitSha || "")
159
+ .trim()
160
+ .toLowerCase();
161
+ const platform = normalizePlatform(value.platform);
162
+ if (!STORE.test(source) || !COMMIT.test(commitSha) || !platform) {
163
+ throw evidenceError(
164
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
165
+ "store evidence source, commit SHA, or platform is invalid",
166
+ );
167
+ }
168
+ if (!Array.isArray(value.stores) || value.stores.length === 0) {
169
+ throw evidenceError(
170
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
171
+ "store evidence must contain at least one real store receipt",
172
+ );
173
+ }
174
+ const stores = value.stores
175
+ .map(normalizeStore)
176
+ .sort(
177
+ (left, right) =>
178
+ left.surface.localeCompare(right.surface) ||
179
+ left.entryId.localeCompare(right.entryId) ||
180
+ left.store.localeCompare(right.store),
181
+ );
182
+ if (
183
+ new Set(
184
+ stores.map(
185
+ (entry) => `${entry.surface}\0${entry.entryId}\0${entry.store}`,
186
+ ),
187
+ ).size !== stores.length
188
+ ) {
189
+ throw evidenceError(
190
+ "CC_GRAPH_STORE_EVIDENCE_DUPLICATE",
191
+ "store evidence contains a duplicate store receipt",
192
+ );
193
+ }
194
+ const sourceReceipts = Object.fromEntries(
195
+ Object.entries(value.sourceReceipts || {})
196
+ .sort(([left], [right]) => left.localeCompare(right))
197
+ .map(([name, receipt]) => [name, exactDigest(receipt, name)]),
198
+ );
199
+ if (Object.keys(sourceReceipts).length === 0) {
200
+ throw evidenceError(
201
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
202
+ "store evidence must bind its source journey receipts",
203
+ );
204
+ }
205
+ const normalized = {
206
+ schema: GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA,
207
+ status: "passed",
208
+ source,
209
+ commitSha,
210
+ platform,
211
+ stores,
212
+ sourceReceipts,
213
+ };
214
+ if (requireEvidenceDigest) {
215
+ const evidenceDigest = exactDigest(value.evidenceDigest, "evidenceDigest");
216
+ if (evidenceDigest !== graphStoreEvidenceDigest(normalized)) {
217
+ throw evidenceError(
218
+ "CC_GRAPH_STORE_EVIDENCE_TAMPERED",
219
+ "store cutover evidence digest does not match its contents",
220
+ );
221
+ }
222
+ normalized.evidenceDigest = evidenceDigest;
223
+ }
224
+ return Object.freeze(normalized);
225
+ }
226
+
227
+ export function graphStoreCutoverCoverage(manifest, evidenceRecords = []) {
228
+ const records = evidenceRecords.map((record) =>
229
+ normalizeGraphStoreCutoverEvidence(record),
230
+ );
231
+ const commits = new Set(records.map((record) => record.commitSha));
232
+ if (commits.size > 1) {
233
+ throw evidenceError(
234
+ "CC_GRAPH_STORE_EVIDENCE_SHA_MISMATCH",
235
+ "store evidence records must bind one exact commit SHA",
236
+ );
237
+ }
238
+ const availableStores = new Map();
239
+ for (const record of records) {
240
+ for (const store of record.stores) {
241
+ const key = `${store.surface}\0${store.entryId}\0${store.store}`;
242
+ const receipts = availableStores.get(key) || [];
243
+ receipts.push({
244
+ platform: record.platform,
245
+ evidenceDigest: record.evidenceDigest,
246
+ ...store,
247
+ });
248
+ availableStores.set(key, receipts);
249
+ }
250
+ }
251
+ const requiredPlatforms = [
252
+ ...(manifest.cutoverPolicy?.requiredPlatforms || []),
253
+ ]
254
+ .map(normalizePlatform)
255
+ .sort();
256
+ if (requiredPlatforms.length === 0) {
257
+ throw evidenceError(
258
+ "CC_GRAPH_STORE_EVIDENCE_INVALID",
259
+ "runtime manifest must declare required cutover platforms",
260
+ );
261
+ }
262
+ const entries = manifest.surfaces.flatMap((surface) =>
263
+ surface.entries
264
+ .filter((entry) => entry.cutoverStrategy === "migrate")
265
+ .map((entry) => {
266
+ const stores = [...entry.storeDispositions.migrate].sort();
267
+ const keyFor = (store) =>
268
+ `${surface.originSurface}\0${entry.id}\0${store}`;
269
+ const coveredStores = stores.filter((store) =>
270
+ availableStores.has(keyFor(store)),
271
+ );
272
+ const missingStores = stores.filter(
273
+ (store) => !availableStores.has(keyFor(store)),
274
+ );
275
+ const platformCoverage = stores.map((store) => {
276
+ const coveredPlatforms = [
277
+ ...new Set(
278
+ (availableStores.get(keyFor(store)) || []).map(
279
+ (receipt) => receipt.platform,
280
+ ),
281
+ ),
282
+ ].sort();
283
+ const missingPlatforms = requiredPlatforms.filter(
284
+ (platform) => !coveredPlatforms.includes(platform),
285
+ );
286
+ return Object.freeze({
287
+ store,
288
+ coveredPlatforms: Object.freeze(coveredPlatforms),
289
+ missingPlatforms: Object.freeze(missingPlatforms),
290
+ complete: missingPlatforms.length === 0,
291
+ });
292
+ });
293
+ const incompletePlatformStores = platformCoverage.filter(
294
+ (store) => !store.complete,
295
+ );
296
+ return Object.freeze({
297
+ surface: surface.originSurface,
298
+ entryId: entry.id,
299
+ stores: Object.freeze(stores),
300
+ coveredStores: Object.freeze(coveredStores),
301
+ missingStores: Object.freeze(missingStores),
302
+ platformCoverage: Object.freeze(platformCoverage),
303
+ incompletePlatformStores: Object.freeze(incompletePlatformStores),
304
+ complete:
305
+ missingStores.length === 0 && incompletePlatformStores.length === 0,
306
+ });
307
+ }),
308
+ );
309
+ const storeSlotCount = entries.reduce(
310
+ (count, entry) => count + entry.stores.length,
311
+ 0,
312
+ );
313
+ const coveredStoreSlotCount = entries.reduce(
314
+ (count, entry) => count + entry.coveredStores.length,
315
+ 0,
316
+ );
317
+ const completeStoreSlotCount = entries.reduce(
318
+ (count, entry) =>
319
+ count + entry.platformCoverage.filter((store) => store.complete).length,
320
+ 0,
321
+ );
322
+ const platformStoreSlotCount = storeSlotCount * requiredPlatforms.length;
323
+ const coveredPlatformStoreSlotCount = entries.reduce(
324
+ (count, entry) =>
325
+ count +
326
+ entry.platformCoverage.reduce(
327
+ (storeCount, store) =>
328
+ storeCount +
329
+ store.coveredPlatforms.filter((platform) =>
330
+ requiredPlatforms.includes(platform),
331
+ ).length,
332
+ 0,
333
+ ),
334
+ 0,
335
+ );
336
+ return Object.freeze({
337
+ schema: "chainlesschain.graph-store-cutover-coverage/v1",
338
+ commitSha: [...commits][0] || null,
339
+ requiredPlatforms: Object.freeze(requiredPlatforms),
340
+ evidenceRecordCount: records.length,
341
+ migratableEntryCount: entries.length,
342
+ completeEntryCount: entries.filter((entry) => entry.complete).length,
343
+ storeSlotCount,
344
+ coveredStoreSlotCount,
345
+ missingStoreSlotCount: storeSlotCount - coveredStoreSlotCount,
346
+ completeStoreSlotCount,
347
+ incompletePlatformStoreSlotCount: storeSlotCount - completeStoreSlotCount,
348
+ platformStoreSlotCount,
349
+ coveredPlatformStoreSlotCount,
350
+ missingPlatformStoreSlotCount:
351
+ platformStoreSlotCount - coveredPlatformStoreSlotCount,
352
+ entries: Object.freeze(entries),
353
+ });
354
+ }
@@ -280,6 +280,12 @@ export function reduceGraphTrace(
280
280
  runId: state.id,
281
281
  throughSeq: ordered.at(-1)?.seq || 0,
282
282
  eventHeadHash: ordered.at(-1)?.hash || null,
283
+ originSurface: state.authority?.originSurface || null,
284
+ authoritySource: state.authority?.authoritySource || null,
285
+ authorityMode: state.authority?.authorityMode || null,
286
+ authorityGeneration: state.authority?.authorityGeneration || null,
287
+ writerId: state.authority?.writerId || null,
288
+ projectionVersion: state.authority?.projectionVersion || null,
283
289
  definitionId: definition.id,
284
290
  graphRevision: state.graphRevision,
285
291
  revisionDigest: state.revisionDigest,
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { MemoryRolloutStore } from "../app-server/rollout-store.js";
3
+ import { createGraphAuthorityBinding } from "./authority.js";
3
4
 
4
5
  const JOURNAL_THREAD_ID = "scheduler-graph-dispatch";
5
6
 
@@ -61,6 +62,61 @@ export class SchedulerGraphTriggerAdapter {
61
62
  this.journal = journal;
62
63
  }
63
64
 
65
+ runtimeClaims() {
66
+ return Object.freeze({
67
+ originSurface: "scheduler",
68
+ surface: "scheduler",
69
+ execution: "real",
70
+ persistence: "durable",
71
+ isolated: true,
72
+ terminalEvidence: true,
73
+ authorityModes: Object.freeze(["canonical"]),
74
+ featureGated: true,
75
+ });
76
+ }
77
+
78
+ _recover(runId) {
79
+ try {
80
+ return this.kernel.recoverRun(runId);
81
+ } catch (error) {
82
+ if (error?.code !== "CC_GRAPH_STALE_WRITER") throw error;
83
+ }
84
+ const events = this.kernel.eventStore.read(runId);
85
+ const latest = events.at(-1);
86
+ const previous = [...events]
87
+ .reverse()
88
+ .find((event) => event.payload?.state?.authority)?.payload
89
+ .state.authority;
90
+ const writer = this.kernel.writerIdentity;
91
+ if (
92
+ !latest ||
93
+ !previous ||
94
+ Number(writer.authorityGeneration) <= Number(previous.authorityGeneration)
95
+ ) {
96
+ const error = new Error(
97
+ "scheduler recovery requires an explicitly higher Graph writer generation",
98
+ );
99
+ error.code = "CC_GRAPH_STALE_GENERATION";
100
+ throw error;
101
+ }
102
+ return this.kernel.recoverRun(runId, {
103
+ authority: createGraphAuthorityBinding({
104
+ ...previous,
105
+ logicalRunId: runId,
106
+ originSurface: "scheduler",
107
+ authorityMode: "canonical",
108
+ authoritySource: "graph_kernel",
109
+ authorityGeneration: writer.authorityGeneration,
110
+ writerId: writer.writerId,
111
+ writerLeaseId: writer.writerLeaseId,
112
+ writerLeaseExpiresAt: new Date(
113
+ this.kernel.now() + this.kernel.writerLeaseTtlMs,
114
+ ).toISOString(),
115
+ eventHead: latest.hash,
116
+ }),
117
+ });
118
+ }
119
+
64
120
  dispatch(occurrence, compiledGraph, options = {}) {
65
121
  const key = dispatchKey(occurrence);
66
122
  const digest = keyDigest(key);
@@ -72,7 +128,7 @@ export class SchedulerGraphTriggerAdapter {
72
128
  try {
73
129
  run = this.kernel.getRun(existing.runId);
74
130
  } catch {
75
- run = this.kernel.recoverRun(existing.runId);
131
+ run = this._recover(existing.runId);
76
132
  }
77
133
  return Object.freeze({
78
134
  occurrenceStatus: "succeeded",
@@ -86,7 +142,7 @@ export class SchedulerGraphTriggerAdapter {
86
142
  .find((entry) => entry.phase === "pending");
87
143
  if (pending) {
88
144
  try {
89
- const graphRun = this.kernel.recoverRun(pending.runId);
145
+ const graphRun = this._recover(pending.runId);
90
146
  if (graphRun.revisionDigest !== compiledGraph.revisionDigest) {
91
147
  const error = new Error(
92
148
  "pending scheduler dispatch is bound to a different GraphRevision",
@@ -127,6 +183,7 @@ export class SchedulerGraphTriggerAdapter {
127
183
  const graphRun = this.kernel.startRun(compiledGraph, {
128
184
  ...options,
129
185
  runId,
186
+ originSurface: "scheduler",
130
187
  occurrenceRef: {
131
188
  jobRevision: occurrence.jobRevision,
132
189
  occurrenceId: occurrence.occurrenceId || occurrence.idempotencyKey,
@@ -173,7 +230,7 @@ export class SchedulerGraphTriggerAdapter {
173
230
  try {
174
231
  graphRun = this.kernel.getRun(accepted.runId);
175
232
  } catch {
176
- graphRun = this.kernel.recoverRun(accepted.runId);
233
+ graphRun = this._recover(accepted.runId);
177
234
  }
178
235
  return Object.freeze({
179
236
  occurrenceStatus: "succeeded",
@@ -205,6 +205,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
205
205
  // null (the default for plain questions) → no binding check, unchanged.
206
206
  binding: options.binding || null,
207
207
  bindingType: options.bindingType || null,
208
+ requireBinding: options.requireBinding === true,
208
209
  });
209
210
 
210
211
  if (approvalRequest) {
@@ -253,6 +254,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
253
254
  // Approval binding pass-through: a permission-gate producer supplies
254
255
  // it; plain questions never carry one (message stays byte-identical).
255
256
  ...(options.binding ? { binding: options.binding } : {}),
257
+ ...(options.requireBinding === true ? { requireBinding: true } : {}),
256
258
  },
257
259
  );
258
260
  }
@@ -290,6 +292,45 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
290
292
  return answer === "true" || answer === "yes" || answer === "y";
291
293
  }
292
294
 
295
+ /**
296
+ * Structured approval variant used by Desktop/WebSocket hosts. Unlike the
297
+ * legacy boolean askConfirm path, this preserves the canonical decision
298
+ * lifetime and requires the trusted host to echo the exact request binding.
299
+ */
300
+ async askApproval(question, options = {}) {
301
+ const {
302
+ binding = null,
303
+ default: dflt = false,
304
+ approval = {},
305
+ ...extra
306
+ } = options || {};
307
+ const answer = await this._ask(
308
+ "confirm",
309
+ question,
310
+ { default: dflt, approval, ...extra },
311
+ binding ? { binding, requireBinding: true } : {},
312
+ );
313
+ const candidate =
314
+ answer?.decision && typeof answer.decision === "object"
315
+ ? answer.decision
316
+ : answer;
317
+ if (
318
+ candidate &&
319
+ typeof candidate === "object" &&
320
+ [
321
+ "acceptOnce",
322
+ "acceptForTurn",
323
+ "acceptForSession",
324
+ "decline",
325
+ "cancel",
326
+ ].includes(candidate.kind)
327
+ ) {
328
+ return candidate;
329
+ }
330
+ if (answer === true) return { kind: "acceptOnce" };
331
+ return { kind: "decline" };
332
+ }
333
+
293
334
  /**
294
335
  * Agent-core AskUserQuestion transport for Desktop/WebSocket consumers.
295
336
  * It uses the same pending map and `session-answer` resolver as MCP
@@ -369,7 +410,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
369
410
  * Resolves the corresponding pending promise.
370
411
  */
371
412
  resolveAnswer(requestId, answer, binding = null) {
372
- this._resolvePending(requestId, answer, "question", binding);
413
+ return this._resolvePending(requestId, answer, "question", binding);
373
414
  }
374
415
 
375
416
  /**
@@ -441,7 +482,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
441
482
  }
442
483
 
443
484
  resolveHostTool(requestId, payload) {
444
- this._resolvePending(requestId, payload, "host-tool");
485
+ return this._resolvePending(requestId, payload, "host-tool");
445
486
  }
446
487
 
447
488
  rejectAllPending(reason = createAbortError("Interaction interrupted")) {
@@ -549,7 +590,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
549
590
  ) {
550
591
  const pending = this._pending.get(requestId);
551
592
  if (!pending) {
552
- return;
593
+ return Object.freeze({ settled: false, reason: "not_pending" });
553
594
  }
554
595
  // Kind guard: a question-answer must not settle a host-tool request (or
555
596
  // vice versa). On a mismatch, IGNORE the message — leave the request pending
@@ -559,7 +600,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
559
600
  // value). Backward-compatible: callers passing no expectedKind, and
560
601
  // pre-kind pending entries, behave exactly as before.
561
602
  if (expectedKind && pending.kind && pending.kind !== expectedKind) {
562
- return;
603
+ return Object.freeze({ settled: false, reason: "kind_mismatch" });
563
604
  }
564
605
 
565
606
  // Approval-binding guard (authority §"权限来源"): if this request was raised
@@ -572,17 +613,18 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
572
613
  pending.bindingType === "interaction" &&
573
614
  !sameInteractionBinding(pending.binding, incomingBinding)
574
615
  ) {
575
- return;
616
+ return Object.freeze({ settled: false, reason: "binding_mismatch" });
576
617
  }
577
618
 
578
619
  let effective = payload;
579
620
  if (
580
621
  pending.bindingType !== "interaction" &&
581
622
  pending.binding &&
582
- incomingBinding &&
583
- !verifyApprovalBinding(pending.binding, incomingBinding)
623
+ ((pending.requireBinding && !incomingBinding) ||
624
+ (incomingBinding &&
625
+ !verifyApprovalBinding(pending.binding, incomingBinding)))
584
626
  ) {
585
- effective = false;
627
+ effective = pending.requireBinding ? { kind: "decline" } : false;
586
628
  }
587
629
 
588
630
  this._pending.delete(requestId);
@@ -594,13 +636,23 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
594
636
  effective === true ||
595
637
  effective === "true" ||
596
638
  effective === "yes" ||
597
- effective === "y";
639
+ effective === "y" ||
640
+ ["acceptOnce", "acceptForTurn", "acceptForSession"].includes(
641
+ effective?.kind || effective?.decision?.kind,
642
+ );
598
643
  this._notifyPendingApproval("approval.settled", {
599
644
  requestId,
600
645
  reason: normalizedApproval ? "approved" : "denied",
601
646
  });
602
647
  }
603
648
  pending.resolve(effective);
649
+ return Object.freeze({
650
+ settled: true,
651
+ reason:
652
+ effective !== payload && pending.requireBinding
653
+ ? "binding_mismatch_denied"
654
+ : "resolved",
655
+ });
604
656
  }
605
657
  }
606
658