chainlesschain 0.166.7 → 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 (187) hide show
  1. package/README.md +21 -0
  2. package/package.json +3 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-BlrmQxa2.js → AIOps-DJvpifGx.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-zyRyLITg.js → ActionButton-D2UhuF_A.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-DwGz7OGN.js → Analytics-C9ho9obu.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-Dc-nj7Zd.js → AppLayout-BvRCpFK3.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-7Hu3O73p.js → Artifacts-jxrySvpk.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-Bnoe3-fR.js → Audit-ovEw0ZYl.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-BqYFrDKZ.js → BackgroundAgents-D7H5z6zS.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-B3hwW1nz.js → Backup-BuXob8za.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-XFVxLA4w.js → BaseInput-CtnszuQ2.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-CWRDNw7e.js → Chat-B_mYE8fJ.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-Bf30VM8G.js → ChatBubbleRenderer-DaiA6CsX.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-kFeeBgac.js → Checkbox-ierdtcJD.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-CCxp8xoI.js → Codegen-3VKPJD_B.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-BLKZalle.js → Col-1EdMyf5P.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-DD0eWCez.js → Community-D6H7UA8K.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-CHqHWdy0.js → Compact-BBAZvYIm.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-Bw54uPiK.js → Compliance-CgsTrAoj.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DZ13zKNJ.js → Cowork-tnZgLoTE.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-Dlj5Jevg.js → Cron-CPpZw2Nh.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-Nvz0aR0j.js → Crosschain-BymBcp5z.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-Ct89eUyY.js → DID-DKPxS_K1.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-BHUH5IAe.js → Dashboard-DvJhEmH9.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-BhZG-PO7.js → Dropdown-b8iQyQIZ.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-ae4RVwwJ.js → EmailListRenderer--0-A-zKb.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-AOcxLfLr.js → FamilyGuardDashboard-C12iDN06.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BK2PJQOF.js → Federation-BRhaE2Z8.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-C2n3xO2_.js → FormItemContext-C4dnq7yf.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-DcyUVFZq.js → GenericCardRenderer-CGAdbR5n.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-tBae9Lt8.js → Git-4eA2fYzL.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-DmNR3AP4.js → Governance-BJuY9Y-9.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-CoseEigi.js → Inference-DZ5Dy4up.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-Bdjd1sxr.js → KnowledgeGraph-BMTjRs4A.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-CtlkKIcn.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-BTYb7nEx.js → Marketplace-Dhho4fEg.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-D0iUdW3P.js → McpTools-BW6xxSlU.js} +2 -2
  40. package/src/assets/web-panel/assets/{Memory--gwI7w4Y.js → Memory-mPqlpSkq.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-JmFBi24T.js → MobileBridge-Cb9N_DQI.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-BK01cQRx.js → MobileProjects-BNs8tah_.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-u7avzyoO.js → Mtc-CaxBt8tn.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-gT3z5fo_.js → MtcAudit-DRPQbp3t.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-BIqZTz5n.js → Multisig-CRm-d8bK.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-DdhVfXYq.js → NLProgramming-BCCk3LPs.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-CBlyUmY3.js → Notes-Cv8SN8gN.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-DSyI26N3.js → NotificationSettings-CggIvTh5.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-B7IEuNz4.js → OrderTableRenderer-BW3_bV12.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-ozhi4kGS.js → Organization-BuRE-VCO.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-CBy57RVM.js → Overflow-DBrm1gju.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-CA-ZRv77.js → P2P-CWVnDYgS.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-DOHc9zm8.js → PdhVaultBrowser-8RKUIpte.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-DiP632GP.js → Permissions-tDUAxogW.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-AnU8O-SS.js → PersonalDataHub-Dv2-CFis.js} +5 -5
  56. package/src/assets/web-panel/assets/{Pipeline-DDibOUaP.js → Pipeline-DM6kvFni.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-D421t36T.js → Privacy-DzK-yL0d.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-DR879ZPJ.js → ProjectInit-B5UrNpkj.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-Ded8o6aY.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-Boivuu-E.js → Providers-CYl4jRYK.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-xKD_ntKp.js → QrScannerModal-DeH2T0fH.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-D3y_A6FV.js → QuickAsk-Bw9k_kTk.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-BjKM-YC2.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-Ci2GjH5p.js → Reputation-Ds_Dfr-k.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-B0-T2BSh.js → Row-BpQUQTNj.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-Bet-ur-r.js → RssFeed-BatpZBGt.js} +2 -2
  69. package/src/assets/web-panel/assets/{Search-DWtRAS2R.js → Search-D7hOObzi.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-BDfu2Qn6.js → Security-dXQ4FKNt.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-CvJmvSMM.js → Services-D8wInGPa.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-CEbrKpdC.js → Skeleton-DXQCoYpM.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CjVeiETf.js → Skills-D3oLRIVn.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-Dibypxum.js → Sla-BmP4-LnJ.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-XflYXp7a.js → SpeechSettings-DLj-xzro.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-ro1Ivx1E.js → SyncSettings-8KKaaRMr.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-CHq1qFbo.js → Tasks-GyK42I7C.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-CRnUZxtZ.js → Templates-n1y_8UBG.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-jUX72JCA.js → Tenant-B39nBph8.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-BBhAs7pt.js → Terminal-DCQoOKXe.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-CD5M3RGp.js → TimelineRenderer-BkhbDfXk.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-sah3v0gu.js → Tokens-BeHIIU8D.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-BNT3Uz3s.js → Trigger-BHvWXVOb.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-BytMGPMo.js → Trust-y2WaOSto.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-BkYVMRQs.js → UkeySign-DBFeJBzt.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-psvb5Q7Y.js → VideoEditing-BEOWitC-.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-PFQTW0MH.js → Wallet-BITedTe6.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-DgO-OwRT.js → WebAuthn-DMwlJVin.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-DL2l9VNl.js → WorkflowEditor-CKfGFEu1.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-C84akEzN.js → chat-DR6gnBGF.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-DzTWuQKP.js → colors-C_Hw5NCn.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-CR9LJQFv.js → compact-item-B8IPwsEu.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-CTTov5Kn.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-DALj523o.js → hasIn-CZubdS4D.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Be6Os5S8.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-CXaCRXN4.js → index-BXS6wYJZ.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-7ux_XohH.js → index-Bi21Etg4.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CXTEpfGe.js → index-Bizm87cX.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DH6OG-ci.js → index-Bv2132PO.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CZhhFQi9.js → index-BzoFanEQ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-B6QOJbSn.js → index-C25rOz7O.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CunGDV0g.js → index-C2VmtNaQ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CmELknPe.js → index-Cbm8F0M2.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DZER6Lj3.js → index-CfniPP5p.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-B2qpjU-D.js → index-Cg2bCeol.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-QW0EXx14.js → index-CiXkhOkY.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-C5eeMl_2.js → index-Cl5RpreD.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-s4CFyn-n.js → index-CqmLw8cs.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-eJcFleIV.js → index-Ctje8Vl3.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-3-XJoYgX.js → index-D1w96gg9.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-_8vetPbU.js → index-D47jt8ET.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Cef0n4k_.js → index-DJ6pG79m.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-AXnERsyV.js → index-DTosx2Wu.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DtW6Zr_i.js → index-DY6MHo9D.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CNmTDXmf.js → index-DcFjRT-K.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Dah8M4l2.js → index-DfnzrUxU.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-D0MqUnKO.js → index-DjRrqooR.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CqUgXYIQ.js → index-DmRcgiYT.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-D9ScRFxz.js → index-DpjHpRoq.js} +3 -3
  122. package/src/assets/web-panel/assets/{index-DjE_ew7U.js → index-Dt-w3xQ7.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-W9axN_Ce.js → index-DuOU5apg.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BDyt57zL.js → index-LvjAKDSl.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-hzzTITR9.js → index-_nL79NT8.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BNaQt49r.js → index-auyNYjLo.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DBIPnoTj.js → index-cVqbas5C.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CnxjXIsK.js → index-ffe7bvqP.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BHRXKiU1.js → index-idZKyADQ.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-D_Bg0LdK.js → index-k1Xa5iw1.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BKNIzw0U.js → index-mYZJxGH6.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DxdzSljS.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-CjkPDSX4.js → index-xoNssgz_.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-JuW8mFj7.js → initDefaultProps-lcU_dT2r.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-Cwb0HBve.js → motion-Dc7UNXZ1.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-DHokzMgu.js → move-Cll8ZXaL.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-DX31y6QS.js → mtc-parser-CAb_yLIM.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-BCIUYDA6.js → omit-DurYMyTe.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-DMCj4EoZ.js → pickAttrs-BITQyOlw.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-Dy5K-u1s.js → placementArrow-Dg1rH91i.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-DkGeZu54.js → responsiveObserve-D_EWIeac.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-Dc5dyJdg.js → slide-lK4d3zsh.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-DIUBjOaC.js → statusUtils-Bflq-Git.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-DmyEOxm5.js → styleChecker-Ccp0I-wt.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-FRhakk1e.js → useFlexGapSupport-CYZbByYA.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-clXyV1WQ.js → useFs-B_x0nxFD.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-UF6DG41z.js → usePersonalDataHub-DW55rL85.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-CoCt95G7.js → vnode-Ca6MH3W8.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-yVWt-ENm.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/orchestrate.js +61 -9
  154. package/src/data/changelog.json +34 -1
  155. package/src/gateways/ws/message-dispatcher.js +4 -0
  156. package/src/gateways/ws/session-protocol.js +89 -11
  157. package/src/gateways/ws/ws-agent-handler.js +65 -9
  158. package/src/gateways/ws/ws-approval-gate.js +181 -16
  159. package/src/gateways/ws/ws-server.js +16 -6
  160. package/src/generated/cc-agent-protocol.schema.json +148 -2
  161. package/src/lib/agent-team/task-lease.js +172 -3
  162. package/src/lib/agent-team/team-runner.js +60 -1
  163. package/src/lib/app-server/graph-runtime.js +326 -2
  164. package/src/lib/app-server/server.js +60 -0
  165. package/src/lib/approval-grant-ledger.js +69 -0
  166. package/src/lib/codex-app-server-adapter.js +11 -20
  167. package/src/lib/graph-kernel/compiler.js +66 -13
  168. package/src/lib/graph-kernel/cutover-authority-resolver.js +26 -0
  169. package/src/lib/graph-kernel/cutover-ledger.js +53 -11
  170. package/src/lib/graph-kernel/retirement-evidence.js +567 -0
  171. package/src/lib/graph-kernel/runtime.js +76 -14
  172. package/src/lib/interaction-adapter.js +61 -9
  173. package/src/lib/policy-decision-event.js +149 -0
  174. package/src/lib/process-execution-broker/platform-sandbox.js +15 -1
  175. package/src/lib/record-replay/index.js +1 -0
  176. package/src/lib/record-replay/playwright-ui-driver.js +327 -0
  177. package/src/lib/webhook-security.js +484 -36
  178. package/src/runtime/coding-agent-events.cjs +13 -11
  179. package/src/runtime/headless-runner.js +17 -1
  180. package/src/runtime/headless-stream.js +66 -3
  181. package/src/runtime/session-slash-commands.js +57 -6
  182. package/src/assets/web-panel/assets/MarkdownRenderer-CZsTBEQE.js +0 -1
  183. package/src/assets/web-panel/assets/Projects-BHPxiucB.js +0 -1
  184. package/src/assets/web-panel/assets/RemoteSession-CgqKMXG4.js +0 -5
  185. package/src/assets/web-panel/assets/devWarning-BOhvmlpc.js +0 -1
  186. package/src/assets/web-panel/assets/index-DDyMJexx.js +0 -1
  187. package/src/assets/web-panel/assets/index-btiojFYn.js +0 -1
@@ -0,0 +1,567 @@
1
+ import { graphDigest } from "./compiler.js";
2
+
3
+ export const GRAPH_RETIREMENT_EVIDENCE_SCHEMA =
4
+ "chainlesschain.graph-retirement-qualification/v1";
5
+ export const GRAPH_LEGACY_WRITER_OBSERVATION_SCHEMA =
6
+ "chainlesschain.graph-legacy-writer-observation/v1";
7
+
8
+ const DIGEST = /^sha256:[a-f0-9]{64}$/u;
9
+ const COMMIT = /^[a-f0-9]{40,64}$/u;
10
+ const ERROR_CODE = /^CC_[A-Z0-9_]{2,120}$/u;
11
+
12
+ function evidenceError(code, message, details = {}) {
13
+ const error = new Error(message);
14
+ error.name = "GraphRetirementEvidenceError";
15
+ error.code = code;
16
+ Object.assign(error, details);
17
+ return error;
18
+ }
19
+
20
+ function text(value, field) {
21
+ const normalized = String(value || "").trim();
22
+ if (!normalized || Buffer.byteLength(normalized, "utf8") > 1024) {
23
+ throw evidenceError(
24
+ "CC_GRAPH_RETIREMENT_EVIDENCE_INVALID",
25
+ `${field} must be a non-empty string no larger than 1 KiB`,
26
+ { field },
27
+ );
28
+ }
29
+ return normalized;
30
+ }
31
+
32
+ function digest(value, field) {
33
+ const normalized = String(value || "");
34
+ if (!DIGEST.test(normalized)) {
35
+ throw evidenceError(
36
+ "CC_GRAPH_RETIREMENT_EVIDENCE_INVALID",
37
+ `${field} must be a sha256 digest`,
38
+ { field },
39
+ );
40
+ }
41
+ return normalized;
42
+ }
43
+
44
+ function commit(value, field = "commitSha") {
45
+ const normalized = String(value || "").toLowerCase();
46
+ if (!COMMIT.test(normalized)) {
47
+ throw evidenceError(
48
+ "CC_GRAPH_RETIREMENT_EVIDENCE_INVALID",
49
+ `${field} must be an exact commit SHA`,
50
+ { field },
51
+ );
52
+ }
53
+ return normalized;
54
+ }
55
+
56
+ function positive(value, field) {
57
+ const normalized = Number(value);
58
+ if (!Number.isSafeInteger(normalized) || normalized < 1) {
59
+ throw evidenceError(
60
+ "CC_GRAPH_RETIREMENT_EVIDENCE_INVALID",
61
+ `${field} must be a positive safe integer`,
62
+ { field, value },
63
+ );
64
+ }
65
+ return normalized;
66
+ }
67
+
68
+ function zero(value, field) {
69
+ if (Number(value) !== 0) {
70
+ throw evidenceError(
71
+ "CC_GRAPH_RETIREMENT_GATE_FAILED",
72
+ `${field} must be zero`,
73
+ { field, value },
74
+ );
75
+ }
76
+ return 0;
77
+ }
78
+
79
+ function timestamp(value, field) {
80
+ const normalized = String(value || "");
81
+ const milliseconds = Date.parse(normalized);
82
+ if (
83
+ !Number.isFinite(milliseconds) ||
84
+ new Date(milliseconds).toISOString() !== normalized
85
+ ) {
86
+ throw evidenceError(
87
+ "CC_GRAPH_RETIREMENT_EVIDENCE_INVALID",
88
+ `${field} must be a canonical ISO timestamp`,
89
+ { field },
90
+ );
91
+ }
92
+ return { value: normalized, milliseconds };
93
+ }
94
+
95
+ function uniqueSortedStrings(value, field, { allowEmpty = false } = {}) {
96
+ if (!Array.isArray(value) || (!allowEmpty && value.length === 0)) {
97
+ throw evidenceError(
98
+ "CC_GRAPH_RETIREMENT_CONTRACT_INVALID",
99
+ `${field} must be ${allowEmpty ? "an" : "a non-empty"} array`,
100
+ { field },
101
+ );
102
+ }
103
+ const normalized = value.map((entry, index) =>
104
+ text(entry, `${field}[${index}]`),
105
+ );
106
+ if (new Set(normalized).size !== normalized.length) {
107
+ throw evidenceError(
108
+ "CC_GRAPH_RETIREMENT_CONTRACT_INVALID",
109
+ `${field} must not contain duplicates`,
110
+ { field },
111
+ );
112
+ }
113
+ return normalized.sort();
114
+ }
115
+
116
+ function sameMembers(actual, expected) {
117
+ return (
118
+ actual.length === expected.length &&
119
+ actual.every((entry, index) => entry === expected[index])
120
+ );
121
+ }
122
+
123
+ function clone(value) {
124
+ return value == null ? value : JSON.parse(JSON.stringify(value));
125
+ }
126
+
127
+ export function normalizeGraphRetirementContract(value) {
128
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
129
+ throw evidenceError(
130
+ "CC_GRAPH_RETIREMENT_CONTRACT_REQUIRED",
131
+ "retired entries require a manifest-bound retirement contract",
132
+ );
133
+ }
134
+ return Object.freeze({
135
+ rolloutKey: text(value.rolloutKey, "retirementContract.rolloutKey"),
136
+ replacementEntrypoint: text(
137
+ value.replacementEntrypoint,
138
+ "retirementContract.replacementEntrypoint",
139
+ ),
140
+ replacementEntryIds: uniqueSortedStrings(
141
+ value.replacementEntryIds,
142
+ "retirementContract.replacementEntryIds",
143
+ ),
144
+ historicalReadFunctions: uniqueSortedStrings(
145
+ value.historicalReadFunctions,
146
+ "retirementContract.historicalReadFunctions",
147
+ ),
148
+ mutationFunctions: uniqueSortedStrings(
149
+ value.mutationFunctions,
150
+ "retirementContract.mutationFunctions",
151
+ ),
152
+ writerFiles: uniqueSortedStrings(
153
+ value.writerFiles,
154
+ "retirementContract.writerFiles",
155
+ ),
156
+ });
157
+ }
158
+
159
+ export function graphRetirementEvidenceDigest(value) {
160
+ const unsigned = clone(value);
161
+ delete unsigned.evidenceDigest;
162
+ return graphDigest(unsigned, "cc.graph.retirement-qualification/v1");
163
+ }
164
+
165
+ export function graphLegacyWriterObservationDigest(value) {
166
+ const unsigned = clone(value);
167
+ delete unsigned.evidenceDigest;
168
+ return graphDigest(unsigned, "cc.graph.legacy-writer-observation/v1");
169
+ }
170
+
171
+ function evidenceIdentity(
172
+ input,
173
+ { schema, surface, entryId, manifestDigest, commitSha, contract },
174
+ ) {
175
+ if (input?.schema !== schema) {
176
+ throw evidenceError(
177
+ "CC_GRAPH_RETIREMENT_EVIDENCE_INVALID",
178
+ `evidence schema must be ${schema}`,
179
+ );
180
+ }
181
+ const normalized = {
182
+ schema,
183
+ surface: text(input.surface, "surface"),
184
+ entryId: text(input.entryId, "entryId"),
185
+ rolloutKey: text(input.rolloutKey, "rolloutKey"),
186
+ manifestDigest: digest(input.manifestDigest, "manifestDigest"),
187
+ commitSha: commit(input.commitSha),
188
+ };
189
+ if (
190
+ normalized.surface !== surface ||
191
+ normalized.entryId !== entryId ||
192
+ normalized.rolloutKey !== contract.rolloutKey ||
193
+ normalized.manifestDigest !== manifestDigest ||
194
+ normalized.commitSha !== commitSha
195
+ ) {
196
+ throw evidenceError(
197
+ "CC_GRAPH_RETIREMENT_BINDING_MISMATCH",
198
+ "retirement evidence does not match the ledger entry, manifest, or commit",
199
+ {
200
+ expected: {
201
+ surface,
202
+ entryId,
203
+ rolloutKey: contract.rolloutKey,
204
+ manifestDigest,
205
+ commitSha,
206
+ },
207
+ actual: normalized,
208
+ },
209
+ );
210
+ }
211
+ return normalized;
212
+ }
213
+
214
+ function observationWindow(input, { notBefore } = {}) {
215
+ const started = timestamp(input.startedAt, "startedAt");
216
+ const ended = timestamp(input.endedAt, "endedAt");
217
+ if (ended.milliseconds <= started.milliseconds) {
218
+ throw evidenceError(
219
+ "CC_GRAPH_RETIREMENT_OBSERVATION_INVALID",
220
+ "retirement observation must end after it starts",
221
+ );
222
+ }
223
+ if (notBefore && started.milliseconds < Date.parse(notBefore)) {
224
+ throw evidenceError(
225
+ "CC_GRAPH_RETIREMENT_OBSERVATION_INVALID",
226
+ "legacy writer observation cannot start before canonical authority",
227
+ { notBefore, startedAt: started.value },
228
+ );
229
+ }
230
+ return {
231
+ startedAt: started.value,
232
+ endedAt: ended.value,
233
+ durationMs: ended.milliseconds - started.milliseconds,
234
+ observationSampleCount: positive(
235
+ input.observationSampleCount,
236
+ "observationSampleCount",
237
+ ),
238
+ };
239
+ }
240
+
241
+ function normalizeMutationProbes(value, contract) {
242
+ if (!Array.isArray(value)) {
243
+ throw evidenceError(
244
+ "CC_GRAPH_RETIREMENT_MUTATION_COVERAGE_INCOMPLETE",
245
+ "retirement evidence requires mutation probes",
246
+ );
247
+ }
248
+ const normalized = value.map((entry, index) => {
249
+ const mutationFunction = text(
250
+ entry?.mutationFunction,
251
+ `mutationProbes[${index}].mutationFunction`,
252
+ );
253
+ const attemptCount = positive(
254
+ entry?.attemptCount,
255
+ `mutationProbes[${index}].attemptCount`,
256
+ );
257
+ const blockedCount = positive(
258
+ entry?.blockedCount,
259
+ `mutationProbes[${index}].blockedCount`,
260
+ );
261
+ const successCount = zero(
262
+ entry?.successCount,
263
+ `mutationProbes[${index}].successCount`,
264
+ );
265
+ const errorCode = String(entry?.errorCode || "");
266
+ if (!ERROR_CODE.test(errorCode)) {
267
+ throw evidenceError(
268
+ "CC_GRAPH_RETIREMENT_EVIDENCE_INVALID",
269
+ `mutationProbes[${index}].errorCode must be a stable CC_* code`,
270
+ );
271
+ }
272
+ if (blockedCount !== attemptCount) {
273
+ throw evidenceError(
274
+ "CC_GRAPH_RETIREMENT_GATE_FAILED",
275
+ `${mutationFunction} must block every mutation attempt`,
276
+ { mutationFunction, attemptCount, blockedCount },
277
+ );
278
+ }
279
+ return {
280
+ mutationFunction,
281
+ attemptCount,
282
+ blockedCount,
283
+ successCount,
284
+ errorCode,
285
+ evidenceDigest: digest(
286
+ entry?.evidenceDigest,
287
+ `mutationProbes[${index}].evidenceDigest`,
288
+ ),
289
+ };
290
+ });
291
+ normalized.sort((left, right) =>
292
+ left.mutationFunction.localeCompare(right.mutationFunction),
293
+ );
294
+ const actual = normalized.map((entry) => entry.mutationFunction);
295
+ if (
296
+ new Set(actual).size !== actual.length ||
297
+ !sameMembers(actual, contract.mutationFunctions)
298
+ ) {
299
+ throw evidenceError(
300
+ "CC_GRAPH_RETIREMENT_MUTATION_COVERAGE_INCOMPLETE",
301
+ "mutation probes must cover every retired mutation exactly once",
302
+ { expected: contract.mutationFunctions, actual },
303
+ );
304
+ }
305
+ return normalized;
306
+ }
307
+
308
+ function normalizeReplacementJourneys(value, contract, platforms, commitSha) {
309
+ if (!Array.isArray(value)) {
310
+ throw evidenceError(
311
+ "CC_GRAPH_RETIREMENT_REPLACEMENT_COVERAGE_INCOMPLETE",
312
+ "retirement evidence requires replacement product journeys",
313
+ );
314
+ }
315
+ const normalized = value.map((entry, index) => {
316
+ const replacementEntryId = text(
317
+ entry?.replacementEntryId,
318
+ `replacementJourneys[${index}].replacementEntryId`,
319
+ );
320
+ const platform = String(entry?.platform || "").toLowerCase();
321
+ const journeyCommit = commit(
322
+ entry?.commitSha,
323
+ `replacementJourneys[${index}].commitSha`,
324
+ );
325
+ if (
326
+ !platforms.includes(platform) ||
327
+ journeyCommit !== commitSha ||
328
+ entry?.status !== "passed" ||
329
+ entry?.productEntrypoint !== contract.replacementEntrypoint
330
+ ) {
331
+ throw evidenceError(
332
+ "CC_GRAPH_RETIREMENT_REPLACEMENT_JOURNEY_FAILED",
333
+ "replacement journey must pass through the declared product entrypoint on the exact commit",
334
+ { replacementEntryId, platform },
335
+ );
336
+ }
337
+ return {
338
+ replacementEntryId,
339
+ productEntrypoint: contract.replacementEntrypoint,
340
+ platform,
341
+ commitSha: journeyCommit,
342
+ status: "passed",
343
+ evidenceDigest: digest(
344
+ entry?.evidenceDigest,
345
+ `replacementJourneys[${index}].evidenceDigest`,
346
+ ),
347
+ };
348
+ });
349
+ normalized.sort((left, right) =>
350
+ `${left.replacementEntryId}:${left.platform}`.localeCompare(
351
+ `${right.replacementEntryId}:${right.platform}`,
352
+ ),
353
+ );
354
+ const actual = normalized.map(
355
+ (entry) => `${entry.replacementEntryId}:${entry.platform}`,
356
+ );
357
+ const expected = contract.replacementEntryIds
358
+ .flatMap((replacementEntryId) =>
359
+ platforms.map((platform) => `${replacementEntryId}:${platform}`),
360
+ )
361
+ .sort();
362
+ if (
363
+ new Set(actual).size !== actual.length ||
364
+ !sameMembers(actual, expected)
365
+ ) {
366
+ throw evidenceError(
367
+ "CC_GRAPH_RETIREMENT_REPLACEMENT_COVERAGE_INCOMPLETE",
368
+ "replacement journeys must cover every declared replacement on every required platform",
369
+ { expected, actual },
370
+ );
371
+ }
372
+ return normalized;
373
+ }
374
+
375
+ function normalizeHistoricalReadProbes(value, contract) {
376
+ if (!Array.isArray(value)) {
377
+ throw evidenceError(
378
+ "CC_GRAPH_RETIREMENT_HISTORICAL_READ_COVERAGE_INCOMPLETE",
379
+ "retirement evidence requires historical read probes",
380
+ );
381
+ }
382
+ const normalized = value.map((entry, index) => {
383
+ const historicalReadFunction = text(
384
+ entry?.historicalReadFunction,
385
+ `historicalReadProbes[${index}].historicalReadFunction`,
386
+ );
387
+ if (entry?.status !== "passed") {
388
+ throw evidenceError(
389
+ "CC_GRAPH_RETIREMENT_HISTORICAL_READ_FAILED",
390
+ `${historicalReadFunction} did not pass its historical read probe`,
391
+ );
392
+ }
393
+ return {
394
+ historicalReadFunction,
395
+ status: "passed",
396
+ readCount: positive(
397
+ entry?.readCount,
398
+ `historicalReadProbes[${index}].readCount`,
399
+ ),
400
+ mutationAttemptCount: zero(
401
+ entry?.mutationAttemptCount,
402
+ `historicalReadProbes[${index}].mutationAttemptCount`,
403
+ ),
404
+ evidenceDigest: digest(
405
+ entry?.evidenceDigest,
406
+ `historicalReadProbes[${index}].evidenceDigest`,
407
+ ),
408
+ };
409
+ });
410
+ normalized.sort((left, right) =>
411
+ left.historicalReadFunction.localeCompare(right.historicalReadFunction),
412
+ );
413
+ const actual = normalized.map((entry) => entry.historicalReadFunction);
414
+ if (
415
+ new Set(actual).size !== actual.length ||
416
+ !sameMembers(actual, contract.historicalReadFunctions)
417
+ ) {
418
+ throw evidenceError(
419
+ "CC_GRAPH_RETIREMENT_HISTORICAL_READ_COVERAGE_INCOMPLETE",
420
+ "historical read probes must cover every declared read function exactly once",
421
+ { expected: contract.historicalReadFunctions, actual },
422
+ );
423
+ }
424
+ return normalized;
425
+ }
426
+
427
+ function verifyEvidenceDigest(input, normalized, digestFunction) {
428
+ const supplied = digest(input?.evidenceDigest, "evidenceDigest");
429
+ const expected = digestFunction(normalized);
430
+ if (supplied !== expected) {
431
+ throw evidenceError(
432
+ "CC_GRAPH_RETIREMENT_EVIDENCE_DIGEST_MISMATCH",
433
+ "retirement evidence digest does not match its normalized contents",
434
+ { expectedEvidenceDigest: expected, actualEvidenceDigest: supplied },
435
+ );
436
+ }
437
+ return supplied;
438
+ }
439
+
440
+ export function normalizeGraphRetirementEvidence(
441
+ input,
442
+ {
443
+ surface,
444
+ entryId,
445
+ manifestDigest,
446
+ commitSha,
447
+ contract: contractInput,
448
+ requiredPlatforms,
449
+ },
450
+ ) {
451
+ const contract = normalizeGraphRetirementContract(contractInput);
452
+ const platforms = uniqueSortedStrings(
453
+ requiredPlatforms,
454
+ "requiredPlatforms",
455
+ ).map((platform) => platform.toLowerCase());
456
+ const normalized = {
457
+ ...evidenceIdentity(input, {
458
+ schema: GRAPH_RETIREMENT_EVIDENCE_SCHEMA,
459
+ surface,
460
+ entryId,
461
+ manifestDigest,
462
+ commitSha,
463
+ contract,
464
+ }),
465
+ ...observationWindow(input),
466
+ activeLegacyRunCount: zero(
467
+ input?.activeLegacyRunCount,
468
+ "activeLegacyRunCount",
469
+ ),
470
+ legacyMutationSuccessCount: zero(
471
+ input?.legacyMutationSuccessCount,
472
+ "legacyMutationSuccessCount",
473
+ ),
474
+ replacementJourneys: normalizeReplacementJourneys(
475
+ input?.replacementJourneys,
476
+ contract,
477
+ platforms,
478
+ commitSha,
479
+ ),
480
+ mutationProbes: normalizeMutationProbes(input?.mutationProbes, contract),
481
+ historicalReadProbes: normalizeHistoricalReadProbes(
482
+ input?.historicalReadProbes,
483
+ contract,
484
+ ),
485
+ };
486
+ normalized.evidenceDigest = verifyEvidenceDigest(
487
+ input,
488
+ normalized,
489
+ graphRetirementEvidenceDigest,
490
+ );
491
+ return Object.freeze(normalized);
492
+ }
493
+
494
+ export function normalizeGraphLegacyWriterObservation(
495
+ input,
496
+ {
497
+ surface,
498
+ entryId,
499
+ manifestDigest,
500
+ commitSha,
501
+ contract: contractInput,
502
+ notBefore,
503
+ },
504
+ ) {
505
+ const contract = normalizeGraphRetirementContract(contractInput);
506
+ const writerObservations = Array.isArray(input?.writerObservations)
507
+ ? input.writerObservations.map((entry, index) => ({
508
+ writerFile: text(
509
+ entry?.writerFile,
510
+ `writerObservations[${index}].writerFile`,
511
+ ),
512
+ observationSampleCount: positive(
513
+ entry?.observationSampleCount,
514
+ `writerObservations[${index}].observationSampleCount`,
515
+ ),
516
+ mutationSuccessCount: zero(
517
+ entry?.mutationSuccessCount,
518
+ `writerObservations[${index}].mutationSuccessCount`,
519
+ ),
520
+ evidenceDigest: digest(
521
+ entry?.evidenceDigest,
522
+ `writerObservations[${index}].evidenceDigest`,
523
+ ),
524
+ }))
525
+ : [];
526
+ writerObservations.sort((left, right) =>
527
+ left.writerFile.localeCompare(right.writerFile),
528
+ );
529
+ const actualWriterFiles = writerObservations.map((entry) => entry.writerFile);
530
+ if (
531
+ new Set(actualWriterFiles).size !== actualWriterFiles.length ||
532
+ !sameMembers(actualWriterFiles, contract.writerFiles)
533
+ ) {
534
+ throw evidenceError(
535
+ "CC_GRAPH_RETIREMENT_WRITER_COVERAGE_INCOMPLETE",
536
+ "legacy writer observations must cover every declared writer file exactly once",
537
+ { expected: contract.writerFiles, actual: actualWriterFiles },
538
+ );
539
+ }
540
+ const normalized = {
541
+ ...evidenceIdentity(input, {
542
+ schema: GRAPH_LEGACY_WRITER_OBSERVATION_SCHEMA,
543
+ surface,
544
+ entryId,
545
+ manifestDigest,
546
+ commitSha,
547
+ contract,
548
+ }),
549
+ ...observationWindow(input, { notBefore }),
550
+ activeLegacyRunCount: zero(
551
+ input?.activeLegacyRunCount,
552
+ "activeLegacyRunCount",
553
+ ),
554
+ legacyMutationSuccessCount: zero(
555
+ input?.legacyMutationSuccessCount,
556
+ "legacyMutationSuccessCount",
557
+ ),
558
+ writerObservations,
559
+ mutationProbes: normalizeMutationProbes(input?.mutationProbes, contract),
560
+ };
561
+ normalized.evidenceDigest = verifyEvidenceDigest(
562
+ input,
563
+ normalized,
564
+ graphLegacyWriterObservationDigest,
565
+ );
566
+ return Object.freeze(normalized);
567
+ }