chainlesschain 0.166.20 → 0.166.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/package.json +2 -2
  2. package/src/assets/web-panel/assets/{AIOps-CcJst5Zs.js → AIOps-BjMnsUci.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BpHPFKd3.js → ActionButton-DdYFP03A.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DHAsASuS.js → Analytics-Bb8TuuK_.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BTKwo5RC.js → AppLayout-Kn3TIOtk.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-BcCBTggA.js → Artifacts-4IxpqI_b.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-z1JvJYbT.js → Audit-BOV2caqU.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-CJ7DCMDR.js → BackgroundAgents-B86k-ay4.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-CKpxw4uw.js → Backup-C5_ie1e3.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-2jI_IlUB.js → BaseInput-xpwg6QCW.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-C_4RfBeN.js → Chat-CVZOcZau.js} +5 -5
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-D8fPYhUu.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-BnF4z4N1.js → Checkbox-MKTq3zdP.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-m_LMamhM.js → Codegen-JUk3wzep.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-DzMbA760.js → Col-JPvTA0kC.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-SScuZUcW.js → Community-Tqgl87NQ.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-CiOHRvwQ.js → Compact-BuAFYBmN.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-97FzYz-6.js → Compliance-CXS9WIPZ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-C0ss-SRl.js → Cowork-Ds2bFHrr.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-CCbdc9fp.js → Cron-C_dV_OeW.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BPnabXej.js → Crosschain-BsO6tIRo.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-B65hFnHs.js → DID-rNOFqBac.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-B6qR_TF2.js → Dashboard-C2fcKKVY.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-6c-2Fxm-.js → Dropdown-Y7Ndr0X_.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-GD57mfiz.js → EmailListRenderer-DcP_uPmL.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-B2mxG6LN.js → FamilyGuardDashboard-Cwn3gDzk.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-cZS-uvAo.js → Federation-ClQuOsqb.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-UbSfBIe1.js → FormItemContext-DfwtmlcK.js} +1 -1
  29. package/src/assets/web-panel/assets/GenericCardRenderer-zNZhtbC5.js +1 -0
  30. package/src/assets/web-panel/assets/{Git-DAlhOiDA.js → Git-BZmdW-G5.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-B-RRVaP8.js → Governance-CqBk4lEn.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-DBl-pXYR.js → Inference-Dbmt3ZXk.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DjqOkvgY.js → KnowledgeGraph-hMTH6qf3.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-CEV7AEAD.js → Logs-CkiYgiW2.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-BDCxa4d1.js → MarkdownRenderer-BL1FElXg.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-oRjzfmYJ.js → Marketplace-CbB6wfin.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-BiTnznLw.js → McpTools-BSwiFtte.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-DR0C5K4N.js → Memory-B03PeHrz.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge--oR8wEcp.js → MobileBridge-CRGrnd-X.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-DKqpYMuG.js → MobileProjects-CE_5v2kO.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-Dg0D6fDQ.js → Mtc-Dp11QVx1.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-D4_-yWTK.js → MtcAudit-CYu-3JBu.js} +5 -5
  43. package/src/assets/web-panel/assets/{Multisig-Coz55FxA.js → Multisig-CGyJ0Xl3.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-BWVjgW9Y.js → NLProgramming-CoWi_ov1.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-BflVuGwr.js → Notes-CgU9DDo9.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-CT0F_dJ7.js → NotificationSettings-DX4I2b4W.js} +1 -1
  47. package/src/assets/web-panel/assets/OrderTableRenderer-CwHc15Zs.js +1 -0
  48. package/src/assets/web-panel/assets/{Organization-CMDTM2z5.js → Organization-oopLO_tk.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-acKvvYpC.js → Overflow-BFVvjMyf.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CRq5j9Ax.js → P2P-CBy5t-Tk.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-DmtzN6Kn.js → PdhVaultBrowser--YWJNsu6.js} +4 -4
  52. package/src/assets/web-panel/assets/{Permissions-SZ-kjJDa.js → Permissions-C2dZ8scb.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DXh-ZfgJ.js → PersonalDataHub-Bs3l7Hlx.js} +6 -6
  54. package/src/assets/web-panel/assets/{Pipeline-DhBU9ftP.js → Pipeline-DEBWbZuD.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-BgEXpO_V.js → Privacy-CjHBb6NU.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-B2DJ-dmK.js → ProjectInit-D2WipUz5.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-ve3SocWc.js → ProjectSettings-B6WfnrGB.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-5ZvFasSJ.js → Projects-FF_thRi6.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-C8fcF3BK.js → Providers-CCv5M_Dv.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-unjO8lNO.js → QrScannerModal-CGthxU54.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-BT1QtT7D.js → QuickAsk-CnPmXPFb.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-BSjFrY1w.js → Recommend-Df_tGEa9.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-CWV0bICg.js → RemoteSession-Z58N0Loe.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-BMjiMsk2.js → Reputation-CZTBQ2Vt.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-9XCY22PM.js → Row-CdK3YpCQ.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-DQ9PDy7Q.js → RssFeed-CFMVT5sb.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-Boym2HwG.js → Search-DrF8RIvD.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-Gbq3lGQb.js → Security-Ddk2f2DM.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-OcUfLdnu.js → Services-CCuK-VOo.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-BjTog6cA.js → Skeleton-DxCpHzeM.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-Dny4ft_1.js → Skills-t2oTDgcv.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-Cy_VnhpZ.js → Sla-Df63M9_R.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-CrFuL_lp.js → SpeechSettings-l7ox6KuX.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-k-FnjuOR.js → SyncSettings-COd_tgPp.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-ZEqDSo0_.js → Tasks-CzDCcrik.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CYYksYV5.js → Templates-D-vfxTGA.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BvTTRTHS.js → Tenant-BlpT_Gxc.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-DMOQOtkj.js → Terminal-D5rq52Hg.js} +2 -2
  79. package/src/assets/web-panel/assets/TimelineRenderer-DdoMndkK.js +1 -0
  80. package/src/assets/web-panel/assets/{Tokens-VW6Wocdp.js → Tokens-BhgBsI6g.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-BtOxZqP6.js → Trigger-DwwzoikZ.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-XcGJoTQx.js → Trust-HkTpzXFb.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-aASNCs5j.js → UkeySign-D9nk6Ehe.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-Bz89M52u.js → VideoEditing-BKk0rfoy.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-uU4dSS_N.js → Wallet-IVWIU_Lq.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-Brrroxgr.js → WebAuthn-CFTCpfsG.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-Cny-evI9.js → WorkflowEditor-Dnf4Obif.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-CJ5iSwWq.js → chat-D2snERdj.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-DWa-2flG.js → colors-DKEjK1N1.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-DFwUfptU.js → compact-item-BEDLwQdt.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-FHWWcyeB.js → createContext-DA9iW1a0.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-DyhgpXPf.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-QY_TElrN.js → hasIn-5l2xEcY9.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-hw1J_Oxs.js → index-5pW4t1iD.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BR4RMPnB.js → index-7P1b8HZo.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BUNwuu5v.js → index-B00GeekA.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-B18zERdP.js → index-B4QYBliR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-wqiOz655.js → index-B7_W_rYd.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BQCtBurK.js → index-BO9dQjpt.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DUfILsc-.js → index-BZ5lY2zx.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DUepuy7O.js → index-B_eCoZgW.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-uRUZdL7I.js → index-BgfImyZI.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CUoLd1dt.js → index-Bq5P3piS.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BiHRihC0.js → index-Bqc8tdIF.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BcVr-LOk.js → index-C7sKbM5s.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DDpXDi4J.js → index-CGlotREA.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CjejB-z9.js → index-CRPrHE7h.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-D2rPJ6Sv.js → index-CX1x4AFn.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-w3SdYwaC.js → index-CbTPvp2_.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D-Mhq8K6.js → index-CjWltbi_.js} +1 -1
  111. package/src/assets/web-panel/assets/index-Ck1jhFE0.js +1 -0
  112. package/src/assets/web-panel/assets/{index-Bd7McYpJ.js → index-CkMKuqUs.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BYbwQ7SP.js → index-CmruhzFi.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-2ufsNuVn.js → index-Csfb-7hw.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-0umhind6.js → index-CxEtQYdi.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B33frlaD.js → index-D7z4zB_a.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Dy2PnKZx.js → index-DLoalqRX.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CUiTugu3.js → index-DU2TXJu-.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CGv5In_T.js → index-DXet1xol.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DCHMVYG1.js → index-Dbd7eEex.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-th467RN6.js → index-Dbkghqn_.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CkmgbT7h.js → index-Dg2a9owQ.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-aTiI7lOQ.js → index-DpqtbXdE.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C5F1vwec.js → index-DqwPFbOb.js} +3 -3
  125. package/src/assets/web-panel/assets/{index-DaHvj4jA.js → index-DvV03Ayk.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BRsGZBHc.js → index-NJieh3T1.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CeGn0A4W.js → index-Td8ZwyoC.js} +1 -1
  128. package/src/assets/web-panel/assets/index-c8jJEHVs.js +1 -0
  129. package/src/assets/web-panel/assets/{index-va4Rt-yM.js → index-e-e40id6.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CKS7n6mE.js → index-fccZmC_h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BEjwv2x6.js → index-fgYk0QXO.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Dlq-u9E4.js → index-yYEQXYaU.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-BeSPUFDz.js → initDefaultProps-CPrcB1TC.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-Dcajvjm9.js → motion-BQ7mWRh_.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-B76orau-.js → move-CzOEq99p.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-zB6yFwcX.js → mtc-parser-BlQI5jrw.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-BsbNjz8w.js → omit-DlW4gxmv.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-BiJ9tssQ.js → pickAttrs-BBYms5nP.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BdfMjMeN.js → placementArrow-az2MPJ_7.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-rV4LGpbU.js → responsiveObserve-D1-ibEol.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-HsVw1qFQ.js → slide-DHGqa4GA.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-D1ry8XPE.js → statusUtils-CYGDo6lD.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-B1t6aQQ_.js → styleChecker-Cl2EM9K6.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-C8qbl-9w.js → useFlexGapSupport-DdYhzuv1.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-R7g_mYTC.js → useFs-DWumPuBW.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-Cd-kCe7Z.js → usePersonalDataHub-DxAO-Aqi.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-9WhK5UWA.js → vnode-CplsQf_N.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-CUqppPco.js → zoom-Cw5HXNSG.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +2 -2
  151. package/src/commands/agent.js +19 -1
  152. package/src/commands/evolution-knowledge.js +54 -0
  153. package/src/commands/evolution-workbench.js +83 -0
  154. package/src/commands/evolution.js +6 -1
  155. package/src/commands/serve.js +16 -0
  156. package/src/commands/skill.js +158 -16
  157. package/src/data/changelog.json +13 -0
  158. package/src/gateways/ws/session-protocol.js +2 -0
  159. package/src/gateways/ws/ws-agent-handler.js +124 -69
  160. package/src/gateways/ws/ws-server.js +19 -0
  161. package/src/generated/cc-agent-protocol.schema.json +7 -1
  162. package/src/harness/jsonl-session-store.js +25 -1
  163. package/src/index.js +1 -1
  164. package/src/lib/app-server/cli-agent-kernel-adapter.js +8 -0
  165. package/src/lib/app-server/graph-runtime.js +40 -1
  166. package/src/lib/app-server/server.js +181 -3
  167. package/src/lib/app-server/websocket-transport.js +2 -0
  168. package/src/lib/evolution/agent-evolution-runtime-composition-brand.js +17 -0
  169. package/src/lib/evolution/agent-evolution-runtime-composition.js +165 -1
  170. package/src/lib/evolution/controlled-skill-production-pilot.js +912 -0
  171. package/src/lib/evolution/evolution-artifact-ports.js +21 -0
  172. package/src/lib/evolution/evolution-raw-crypto-shred.js +185 -0
  173. package/src/lib/evolution/evolution-workbench-batch-executor.js +195 -0
  174. package/src/lib/evolution/evolution-workbench-cli-host.js +169 -0
  175. package/src/lib/evolution/evolution-workbench-metrics-ledger-adapter.js +648 -0
  176. package/src/lib/evolution/evolution-workbench-metrics.js +943 -0
  177. package/src/lib/evolution/evolution-workbench-projection.js +734 -0
  178. package/src/lib/evolution/evolution-workbench-version-control.js +272 -0
  179. package/src/lib/evolution/governed-knowledge-conflict-merge.js +352 -0
  180. package/src/lib/evolution/governed-knowledge-dependency-authority.js +273 -0
  181. package/src/lib/evolution/governed-knowledge-dependency-ledger-executor.js +646 -0
  182. package/src/lib/evolution/governed-knowledge-merge-ledger-executor.js +644 -0
  183. package/src/lib/evolution/governed-knowledge-merge-publisher-authority.js +282 -0
  184. package/src/lib/evolution/governed-knowledge-node-crypto-authority.js +348 -0
  185. package/src/lib/evolution/governed-knowledge-rbac-approval-authority.js +621 -0
  186. package/src/lib/evolution/governed-knowledge-review-host.js +249 -0
  187. package/src/lib/evolution/governed-knowledge-sync-ledger-adapter.js +643 -0
  188. package/src/lib/evolution/governed-knowledge-sync-merge-publisher.js +259 -0
  189. package/src/lib/evolution/governed-knowledge-sync.js +485 -0
  190. package/src/lib/evolution/governed-knowledge-trust-ledger.js +707 -0
  191. package/src/lib/evolution/governed-skill-marketplace.js +430 -0
  192. package/src/lib/evolution/governed-wiki-pruning.js +435 -0
  193. package/src/lib/evolution/skill-outcome-index-authority.js +268 -0
  194. package/src/lib/evolution/skill-outcome-source-catalog-authority.js +237 -0
  195. package/src/lib/public-ide-capability-manifest.js +4 -0
  196. package/src/lib/skill-outcome-authority.js +43 -0
  197. package/src/lib/skill-outcome-transcript-authority.js +252 -0
  198. package/src/lib/skill-retrieval-router-benchmark.js +135 -0
  199. package/src/lib/skill-retrieval-router.js +235 -0
  200. package/src/lib/skill-vector-authority.js +325 -0
  201. package/src/lib/skill-vector-process-authority.js +386 -0
  202. package/src/repl/agent-repl.js +7 -1
  203. package/src/runtime/agent-core.js +72 -6
  204. package/src/runtime/agent-runtime.js +42 -0
  205. package/src/runtime/headless-runner.js +32 -0
  206. package/src/runtime/headless-stream.js +36 -1
  207. package/src/runtime/runtime-factory.js +62 -4
  208. package/src/assets/web-panel/assets/ChatBubbleRenderer-eMmw1eZF.js +0 -1
  209. package/src/assets/web-panel/assets/GenericCardRenderer-BMAtvGt1.js +0 -1
  210. package/src/assets/web-panel/assets/OrderTableRenderer-Dyrnqy_o.js +0 -1
  211. package/src/assets/web-panel/assets/TimelineRenderer-CnudkJxk.js +0 -1
  212. package/src/assets/web-panel/assets/devWarning-DxufPwXC.js +0 -1
  213. package/src/assets/web-panel/assets/index-ZMTB9p5z.js +0 -1
  214. package/src/assets/web-panel/assets/index-_PvIDelE.js +0 -1
@@ -0,0 +1,912 @@
1
+ import { createHash } from "node:crypto";
2
+ import { types as utilTypes } from "node:util";
3
+
4
+ export const CONTROLLED_SKILL_PILOT_SCHEMA =
5
+ "chainlesschain.controlled-skill-production-pilot/v1";
6
+ export const CONTROLLED_SKILL_PILOT_STATE_SCHEMA =
7
+ "chainlesschain.controlled-skill-production-pilot-state/v1";
8
+ export const CONTROLLED_SKILL_PILOT_EVENT_SCHEMA =
9
+ "chainlesschain.controlled-skill-production-pilot-event/v1";
10
+
11
+ export const CONTROLLED_SKILL_PILOT_STAGE = Object.freeze({
12
+ CANDIDATE: "candidate",
13
+ SHADOW: "shadow",
14
+ CANARY: "canary",
15
+ ACTIVE: "active",
16
+ ROLLED_BACK: "rolled-back",
17
+ });
18
+
19
+ export const CONTROLLED_SKILL_PILOT_ERROR = Object.freeze({
20
+ INVALID: "CC_CONTROLLED_SKILL_PILOT_INVALID",
21
+ NOT_OPTED_IN: "CC_CONTROLLED_SKILL_PILOT_NOT_OPTED_IN",
22
+ REVIEW_REQUIRED: "CC_CONTROLLED_SKILL_PILOT_REVIEW_REQUIRED",
23
+ GATE_FAILED: "CC_CONTROLLED_SKILL_PILOT_GATE_FAILED",
24
+ KILL_SWITCH: "CC_CONTROLLED_SKILL_PILOT_KILL_SWITCH",
25
+ ACTIVE_DRIFT: "CC_CONTROLLED_SKILL_PILOT_ACTIVE_DRIFT",
26
+ PERSISTENCE_FAILED: "CC_CONTROLLED_SKILL_PILOT_PERSISTENCE_FAILED",
27
+ AUTHORITY_FAILED: "CC_CONTROLLED_SKILL_PILOT_AUTHORITY_FAILED",
28
+ });
29
+
30
+ const DIGEST = /^sha256:[a-f0-9]{64}$/u;
31
+ const SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/u;
32
+ const STAGES = new Set(Object.values(CONTROLLED_SKILL_PILOT_STAGE));
33
+ const FORWARD = new Map([
34
+ [CONTROLLED_SKILL_PILOT_STAGE.CANDIDATE, CONTROLLED_SKILL_PILOT_STAGE.SHADOW],
35
+ [CONTROLLED_SKILL_PILOT_STAGE.SHADOW, CONTROLLED_SKILL_PILOT_STAGE.CANARY],
36
+ [CONTROLLED_SKILL_PILOT_STAGE.CANARY, CONTROLLED_SKILL_PILOT_STAGE.ACTIVE],
37
+ ]);
38
+ const CONTROLLED_PILOT_ROLLBACK = CONTROLLED_SKILL_PILOT_STAGE.ROLLED_BACK;
39
+
40
+ function canonical(value) {
41
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
42
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
43
+ return `{${Object.keys(value)
44
+ .sort()
45
+ .map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
46
+ .join(",")}}`;
47
+ }
48
+
49
+ function hash(value) {
50
+ return `sha256:${createHash("sha256").update(canonical(value)).digest("hex")}`;
51
+ }
52
+
53
+ function clone(value) {
54
+ return value == null ? value : JSON.parse(JSON.stringify(value));
55
+ }
56
+
57
+ function deepFreeze(value, seen = new WeakSet()) {
58
+ if (!value || typeof value !== "object" || seen.has(value)) return value;
59
+ seen.add(value);
60
+ Object.freeze(value);
61
+ for (const child of Object.values(value)) deepFreeze(child, seen);
62
+ return value;
63
+ }
64
+
65
+ function fail(code, message) {
66
+ const error = new Error(message);
67
+ error.code = code;
68
+ throw error;
69
+ }
70
+
71
+ function plain(value, label) {
72
+ if (
73
+ !value ||
74
+ typeof value !== "object" ||
75
+ Array.isArray(value) ||
76
+ utilTypes.isProxy(value) ||
77
+ ![Object.prototype, null].includes(Object.getPrototypeOf(value))
78
+ ) {
79
+ throw new TypeError(`${label} must be a plain object`);
80
+ }
81
+ return value;
82
+ }
83
+
84
+ function text(value, label) {
85
+ if (
86
+ typeof value !== "string" ||
87
+ value.trim() !== value ||
88
+ !SAFE_ID.test(value)
89
+ ) {
90
+ throw new TypeError(`${label} is invalid`);
91
+ }
92
+ return value;
93
+ }
94
+
95
+ function digest(value, label) {
96
+ if (typeof value !== "string" || !DIGEST.test(value)) {
97
+ throw new TypeError(`${label} must be sha256-bound`);
98
+ }
99
+ return value;
100
+ }
101
+
102
+ function integer(
103
+ value,
104
+ label,
105
+ { min = 0, max = Number.MAX_SAFE_INTEGER } = {},
106
+ ) {
107
+ if (!Number.isSafeInteger(value) || value < min || value > max) {
108
+ throw new TypeError(`${label} is out of range`);
109
+ }
110
+ return value;
111
+ }
112
+
113
+ function finite(value, label, { min = -Infinity, max = Infinity } = {}) {
114
+ if (!Number.isFinite(value) || value < min || value > max) {
115
+ throw new TypeError(`${label} is out of range`);
116
+ }
117
+ return value;
118
+ }
119
+
120
+ function capture(owner, method, label = method) {
121
+ if (
122
+ !owner ||
123
+ typeof owner !== "object" ||
124
+ utilTypes.isProxy(owner) ||
125
+ typeof owner[method] !== "function"
126
+ ) {
127
+ throw new TypeError(`${label} port is required`);
128
+ }
129
+ return (...args) => Reflect.apply(owner[method], owner, args);
130
+ }
131
+
132
+ function normalizeDescriptor(input) {
133
+ plain(input, "descriptor");
134
+ const cohort = plain(input.cohort, "descriptor.cohort");
135
+ const observation = plain(input.observation, "descriptor.observation");
136
+ const thresholds = plain(input.thresholds, "descriptor.thresholds");
137
+ if (cohort.optInRequired !== true) {
138
+ throw new TypeError("production pilot cohort must require explicit opt-in");
139
+ }
140
+ const normalized = {
141
+ schema: CONTROLLED_SKILL_PILOT_SCHEMA,
142
+ tenantId: text(input.tenantId, "descriptor.tenantId"),
143
+ pilotId: text(input.pilotId, "descriptor.pilotId"),
144
+ skillName: text(input.skillName, "descriptor.skillName"),
145
+ candidateDigest: digest(
146
+ input.candidateDigest,
147
+ "descriptor.candidateDigest",
148
+ ),
149
+ baselineDigest: digest(input.baselineDigest, "descriptor.baselineDigest"),
150
+ evalReceiptDigest: digest(
151
+ input.evalReceiptDigest,
152
+ "descriptor.evalReceiptDigest",
153
+ ),
154
+ whyEvidenceDigest: digest(
155
+ input.whyEvidenceDigest,
156
+ "descriptor.whyEvidenceDigest",
157
+ ),
158
+ candidateDiffDigest: digest(
159
+ input.candidateDiffDigest,
160
+ "descriptor.candidateDiffDigest",
161
+ ),
162
+ permissionDiffDigest: digest(
163
+ input.permissionDiffDigest,
164
+ "descriptor.permissionDiffDigest",
165
+ ),
166
+ beforeEvaluationDigest: digest(
167
+ input.beforeEvaluationDigest,
168
+ "descriptor.beforeEvaluationDigest",
169
+ ),
170
+ afterEvaluationDigest: digest(
171
+ input.afterEvaluationDigest,
172
+ "descriptor.afterEvaluationDigest",
173
+ ),
174
+ reviewPacketDigest: digest(
175
+ input.reviewPacketDigest,
176
+ "descriptor.reviewPacketDigest",
177
+ ),
178
+ cohort: {
179
+ id: text(cohort.id, "descriptor.cohort.id"),
180
+ optInRequired: true,
181
+ maxSubjects: integer(
182
+ cohort.maxSubjects,
183
+ "descriptor.cohort.maxSubjects",
184
+ {
185
+ min: 1,
186
+ max: 10_000,
187
+ },
188
+ ),
189
+ canaryPercent: finite(
190
+ cohort.canaryPercent,
191
+ "descriptor.cohort.canaryPercent",
192
+ { min: 0.01, max: 100 },
193
+ ),
194
+ },
195
+ observation: {
196
+ minSamples: integer(
197
+ observation.minSamples,
198
+ "descriptor.observation.minSamples",
199
+ { min: 1, max: 10_000 },
200
+ ),
201
+ minWindowMs: integer(
202
+ observation.minWindowMs,
203
+ "descriptor.observation.minWindowMs",
204
+ { min: 1 },
205
+ ),
206
+ maxWindowMs: integer(
207
+ observation.maxWindowMs,
208
+ "descriptor.observation.maxWindowMs",
209
+ { min: 1 },
210
+ ),
211
+ },
212
+ thresholds: {
213
+ minAdoptionRate: finite(
214
+ thresholds.minAdoptionRate,
215
+ "descriptor.thresholds.minAdoptionRate",
216
+ { min: 0, max: 1 },
217
+ ),
218
+ minSuccessDelta: finite(
219
+ thresholds.minSuccessDelta,
220
+ "descriptor.thresholds.minSuccessDelta",
221
+ { min: -1, max: 1 },
222
+ ),
223
+ maxCostDelta: finite(
224
+ thresholds.maxCostDelta,
225
+ "descriptor.thresholds.maxCostDelta",
226
+ ),
227
+ maxUserRevisionRate: finite(
228
+ thresholds.maxUserRevisionRate,
229
+ "descriptor.thresholds.maxUserRevisionRate",
230
+ { min: 0, max: 1 },
231
+ ),
232
+ maxMisPromotionRate: finite(
233
+ thresholds.maxMisPromotionRate,
234
+ "descriptor.thresholds.maxMisPromotionRate",
235
+ { min: 0, max: 1 },
236
+ ),
237
+ maxRollbackRate: finite(
238
+ thresholds.maxRollbackRate,
239
+ "descriptor.thresholds.maxRollbackRate",
240
+ { min: 0, max: 1 },
241
+ ),
242
+ maxSecurityEvents: integer(
243
+ thresholds.maxSecurityEvents,
244
+ "descriptor.thresholds.maxSecurityEvents",
245
+ { max: 10_000 },
246
+ ),
247
+ },
248
+ };
249
+ if (normalized.observation.minSamples > normalized.cohort.maxSubjects) {
250
+ throw new TypeError("minimum samples exceed the bounded cohort");
251
+ }
252
+ const canarySubjectLimit = Math.max(
253
+ 1,
254
+ Math.ceil(
255
+ (normalized.cohort.maxSubjects * normalized.cohort.canaryPercent) / 100,
256
+ ),
257
+ );
258
+ if (normalized.observation.minSamples > canarySubjectLimit) {
259
+ throw new TypeError("minimum samples exceed the bounded canary cohort");
260
+ }
261
+ if (normalized.observation.maxWindowMs < normalized.observation.minWindowMs) {
262
+ throw new TypeError("maximum observation window is shorter than minimum");
263
+ }
264
+ return deepFreeze(normalized);
265
+ }
266
+
267
+ function emptyState(descriptorDigest) {
268
+ return {
269
+ schema: CONTROLLED_SKILL_PILOT_STATE_SCHEMA,
270
+ descriptorDigest,
271
+ revision: 0,
272
+ stage: CONTROLLED_SKILL_PILOT_STAGE.CANDIDATE,
273
+ stageStartedAt: null,
274
+ activeStateDigest: null,
275
+ reviewReceiptDigest: null,
276
+ killSwitch: false,
277
+ observations: [],
278
+ pendingTransition: null,
279
+ lastTransitionReceiptDigest: null,
280
+ };
281
+ }
282
+
283
+ function normalizeRestore(input, descriptorDigest) {
284
+ plain(input, "pilot restore");
285
+ const state = plain(input.state, "pilot restore.state");
286
+ if (
287
+ input.authenticated !== true ||
288
+ input.durable !== true ||
289
+ input.descriptorDigest !== descriptorDigest ||
290
+ input.stateDigest !== hash(state) ||
291
+ state.schema !== CONTROLLED_SKILL_PILOT_STATE_SCHEMA ||
292
+ state.descriptorDigest !== descriptorDigest ||
293
+ !STAGES.has(state.stage) ||
294
+ !Number.isSafeInteger(state.revision) ||
295
+ state.revision < 0 ||
296
+ !Array.isArray(state.observations) ||
297
+ (state.pendingTransition !== null &&
298
+ (!state.pendingTransition ||
299
+ typeof state.pendingTransition !== "object" ||
300
+ state.pendingTransition.requestDigest !==
301
+ hash(state.pendingTransition.request) ||
302
+ state.pendingTransition.request?.from !== state.stage))
303
+ ) {
304
+ fail(
305
+ CONTROLLED_SKILL_PILOT_ERROR.PERSISTENCE_FAILED,
306
+ "pilot restore is unauthenticated or corrupt",
307
+ );
308
+ }
309
+ return clone(state);
310
+ }
311
+
312
+ function normalizeApproval(value, descriptor, descriptorDigest) {
313
+ plain(value, "review approval");
314
+ if (
315
+ value.authenticated !== true ||
316
+ value.durable !== true ||
317
+ value.automated !== false ||
318
+ value.tenantId !== descriptor.tenantId ||
319
+ value.pilotId !== descriptor.pilotId ||
320
+ value.packetDigest !== descriptor.reviewPacketDigest ||
321
+ value.descriptorDigest !== descriptorDigest ||
322
+ value.decision !== "approved" ||
323
+ !DIGEST.test(value.receiptDigest ?? "")
324
+ ) {
325
+ fail(
326
+ CONTROLLED_SKILL_PILOT_ERROR.REVIEW_REQUIRED,
327
+ "a durable non-automated exact-pilot approval is required",
328
+ );
329
+ }
330
+ return value.receiptDigest;
331
+ }
332
+
333
+ function normalizeObservation(value, descriptor, stage) {
334
+ plain(value, "observation receipt");
335
+ if (
336
+ value.authenticated !== true ||
337
+ value.durable !== true ||
338
+ value.tenantId !== descriptor.tenantId ||
339
+ value.pilotId !== descriptor.pilotId ||
340
+ value.cohortId !== descriptor.cohort.id ||
341
+ value.stage !== stage ||
342
+ !DIGEST.test(value.subjectDigest ?? "") ||
343
+ !DIGEST.test(value.assignmentReceiptDigest ?? "") ||
344
+ !DIGEST.test(value.receiptDigest ?? "") ||
345
+ typeof value.optedIn !== "boolean" ||
346
+ typeof value.adopted !== "boolean" ||
347
+ typeof value.baselineSuccess !== "boolean" ||
348
+ typeof value.candidateSuccess !== "boolean" ||
349
+ typeof value.userRevised !== "boolean" ||
350
+ typeof value.misPromotion !== "boolean" ||
351
+ typeof value.rolledBack !== "boolean" ||
352
+ !Number.isFinite(value.baselineCostUsd) ||
353
+ value.baselineCostUsd < 0 ||
354
+ !Number.isFinite(value.candidateCostUsd) ||
355
+ value.candidateCostUsd < 0 ||
356
+ !Number.isSafeInteger(value.securityEvents) ||
357
+ value.securityEvents < 0 ||
358
+ !Number.isSafeInteger(value.observedAt)
359
+ ) {
360
+ fail(
361
+ CONTROLLED_SKILL_PILOT_ERROR.INVALID,
362
+ "observation receipt is incomplete or outside the fixed pilot",
363
+ );
364
+ }
365
+ if (!value.optedIn) {
366
+ fail(
367
+ CONTROLLED_SKILL_PILOT_ERROR.NOT_OPTED_IN,
368
+ "non-opted-in traffic cannot enter a production pilot",
369
+ );
370
+ }
371
+ return deepFreeze({
372
+ stage,
373
+ subjectDigest: value.subjectDigest,
374
+ assignmentReceiptDigest: value.assignmentReceiptDigest,
375
+ receiptDigest: value.receiptDigest,
376
+ adopted: value.adopted,
377
+ baselineSuccess: value.baselineSuccess,
378
+ candidateSuccess: value.candidateSuccess,
379
+ baselineCostUsd: value.baselineCostUsd,
380
+ candidateCostUsd: value.candidateCostUsd,
381
+ userRevised: value.userRevised,
382
+ misPromotion: value.misPromotion,
383
+ rolledBack: value.rolledBack,
384
+ securityEvents: value.securityEvents,
385
+ observedAt: value.observedAt,
386
+ });
387
+ }
388
+
389
+ function metricsFor(observations) {
390
+ const samples = observations.length;
391
+ if (samples === 0) {
392
+ return deepFreeze({
393
+ samples: 0,
394
+ adoptionRate: 0,
395
+ successDelta: 0,
396
+ costDelta: 0,
397
+ userRevisionRate: 0,
398
+ misPromotionRate: 0,
399
+ rollbackRate: 0,
400
+ securityEvents: 0,
401
+ });
402
+ }
403
+ const sum = (selector) =>
404
+ observations.reduce((n, row) => n + selector(row), 0);
405
+ return deepFreeze({
406
+ samples,
407
+ adoptionRate: sum((row) => Number(row.adopted)) / samples,
408
+ successDelta:
409
+ (sum((row) => Number(row.candidateSuccess)) -
410
+ sum((row) => Number(row.baselineSuccess))) /
411
+ samples,
412
+ costDelta:
413
+ (sum((row) => row.candidateCostUsd) - sum((row) => row.baselineCostUsd)) /
414
+ samples,
415
+ userRevisionRate: sum((row) => Number(row.userRevised)) / samples,
416
+ misPromotionRate: sum((row) => Number(row.misPromotion)) / samples,
417
+ rollbackRate: sum((row) => Number(row.rolledBack)) / samples,
418
+ securityEvents: sum((row) => row.securityEvents),
419
+ });
420
+ }
421
+
422
+ function gateFailures(descriptor, metrics, elapsedMs) {
423
+ const failures = [];
424
+ if (metrics.samples < descriptor.observation.minSamples)
425
+ failures.push("min_samples");
426
+ if (elapsedMs < descriptor.observation.minWindowMs)
427
+ failures.push("min_window");
428
+ if (elapsedMs > descriptor.observation.maxWindowMs)
429
+ failures.push("max_window");
430
+ const t = descriptor.thresholds;
431
+ if (metrics.adoptionRate < t.minAdoptionRate) failures.push("adoption_rate");
432
+ if (metrics.successDelta < t.minSuccessDelta) failures.push("success_delta");
433
+ if (metrics.costDelta > t.maxCostDelta) failures.push("cost_delta");
434
+ if (metrics.userRevisionRate > t.maxUserRevisionRate)
435
+ failures.push("user_revision_rate");
436
+ if (metrics.misPromotionRate > t.maxMisPromotionRate)
437
+ failures.push("mis_promotion_rate");
438
+ if (metrics.rollbackRate > t.maxRollbackRate) failures.push("rollback_rate");
439
+ if (metrics.securityEvents > t.maxSecurityEvents)
440
+ failures.push("security_events");
441
+ return failures;
442
+ }
443
+
444
+ export class ControlledSkillProductionPilot {
445
+ constructor({
446
+ descriptor: input,
447
+ ports,
448
+ now = Date.now,
449
+ restore = null,
450
+ } = {}) {
451
+ this.descriptor = normalizeDescriptor(input);
452
+ this.descriptorDigest = hash(this.descriptor);
453
+ this._now = typeof now === "function" ? now : Date.now;
454
+ this._readActiveState = capture(ports, "readActiveState");
455
+ this._verifyApproval = capture(ports, "verifyApproval");
456
+ this._verifyObservation = capture(ports, "verifyObservation");
457
+ this._verifyRestore = capture(ports, "verifyRestore");
458
+ this._transitionStage = capture(ports, "transitionStage");
459
+ this._commitState = capture(ports, "commitState");
460
+ this._state = restore
461
+ ? normalizeRestore(
462
+ this._verifyRestore({
463
+ restore: clone(restore),
464
+ descriptor: this.descriptor,
465
+ descriptorDigest: this.descriptorDigest,
466
+ }),
467
+ this.descriptorDigest,
468
+ )
469
+ : emptyState(this.descriptorDigest);
470
+ }
471
+
472
+ async start({ optedIn, tenantId, cohortId } = {}) {
473
+ if (
474
+ optedIn !== true ||
475
+ tenantId !== this.descriptor.tenantId ||
476
+ cohortId !== this.descriptor.cohort.id
477
+ ) {
478
+ fail(
479
+ CONTROLLED_SKILL_PILOT_ERROR.NOT_OPTED_IN,
480
+ "pilot start requires exact tenant/cohort opt-in",
481
+ );
482
+ }
483
+ if (this._state.activeStateDigest !== null) return this.view();
484
+ const now = this._timestamp();
485
+ const next = clone(this._state);
486
+ next.activeStateDigest = hash(await this._readActiveState());
487
+ next.stageStartedAt = now;
488
+ await this._commit(next, "pilot.started", { optedIn: true });
489
+ return this.view();
490
+ }
491
+
492
+ async approveShadow(input) {
493
+ this._started();
494
+ this._noPending();
495
+ if (this._state.stage !== CONTROLLED_SKILL_PILOT_STAGE.CANDIDATE) {
496
+ fail(
497
+ CONTROLLED_SKILL_PILOT_ERROR.INVALID,
498
+ "pilot is not awaiting review",
499
+ );
500
+ }
501
+ const reviewReceiptDigest = normalizeApproval(
502
+ await this._verifyApproval({
503
+ ...clone(input),
504
+ descriptor: this.descriptor,
505
+ descriptorDigest: this.descriptorDigest,
506
+ }),
507
+ this.descriptor,
508
+ this.descriptorDigest,
509
+ );
510
+ await this._assertActiveUnchanged();
511
+ const next = clone(this._state);
512
+ next.reviewReceiptDigest = reviewReceiptDigest;
513
+ await this._advance(next, CONTROLLED_SKILL_PILOT_STAGE.SHADOW, {
514
+ reviewReceiptDigest,
515
+ });
516
+ return this.view();
517
+ }
518
+
519
+ async recordObservation(input) {
520
+ this._started();
521
+ this._noPending();
522
+ if (
523
+ ![
524
+ CONTROLLED_SKILL_PILOT_STAGE.SHADOW,
525
+ CONTROLLED_SKILL_PILOT_STAGE.CANARY,
526
+ ].includes(this._state.stage)
527
+ ) {
528
+ fail(
529
+ CONTROLLED_SKILL_PILOT_ERROR.INVALID,
530
+ "observations are accepted only during shadow or canary",
531
+ );
532
+ }
533
+ if (this._state.killSwitch) {
534
+ fail(
535
+ CONTROLLED_SKILL_PILOT_ERROR.KILL_SWITCH,
536
+ "pilot kill switch is set",
537
+ );
538
+ }
539
+ const observation = normalizeObservation(
540
+ await this._verifyObservation({
541
+ ...clone(input),
542
+ descriptor: this.descriptor,
543
+ descriptorDigest: this.descriptorDigest,
544
+ stage: this._state.stage,
545
+ }),
546
+ this.descriptor,
547
+ this._state.stage,
548
+ );
549
+ const now = this._timestamp();
550
+ if (
551
+ observation.observedAt < this._state.stageStartedAt ||
552
+ observation.observedAt > now
553
+ ) {
554
+ fail(
555
+ CONTROLLED_SKILL_PILOT_ERROR.INVALID,
556
+ "observation timestamp is outside the current pilot window",
557
+ );
558
+ }
559
+ if (this._state.stage === CONTROLLED_SKILL_PILOT_STAGE.CANARY) {
560
+ const shadowAssignment = this._state.observations.find(
561
+ (row) =>
562
+ row.stage === CONTROLLED_SKILL_PILOT_STAGE.SHADOW &&
563
+ row.subjectDigest === observation.subjectDigest,
564
+ );
565
+ if (
566
+ !shadowAssignment ||
567
+ shadowAssignment.assignmentReceiptDigest !==
568
+ observation.assignmentReceiptDigest
569
+ ) {
570
+ fail(
571
+ CONTROLLED_SKILL_PILOT_ERROR.NOT_OPTED_IN,
572
+ "canary traffic must retain its authenticated shadow cohort assignment",
573
+ );
574
+ }
575
+ }
576
+ const sameSubject = this._state.observations.find(
577
+ (row) =>
578
+ row.stage === observation.stage &&
579
+ row.subjectDigest === observation.subjectDigest,
580
+ );
581
+ if (sameSubject) {
582
+ if (sameSubject.receiptDigest !== observation.receiptDigest) {
583
+ fail(
584
+ CONTROLLED_SKILL_PILOT_ERROR.INVALID,
585
+ "a pilot subject cannot replace its observation receipt",
586
+ );
587
+ }
588
+ return this.view();
589
+ }
590
+ if (this._state.stage === CONTROLLED_SKILL_PILOT_STAGE.CANARY) {
591
+ const canarySubjects = new Set(
592
+ this._state.observations
593
+ .filter((row) => row.stage === CONTROLLED_SKILL_PILOT_STAGE.CANARY)
594
+ .map((row) => row.subjectDigest),
595
+ );
596
+ const canarySubjectLimit = Math.max(
597
+ 1,
598
+ Math.ceil(
599
+ (this.descriptor.cohort.maxSubjects *
600
+ this.descriptor.cohort.canaryPercent) /
601
+ 100,
602
+ ),
603
+ );
604
+ if (canarySubjects.size >= canarySubjectLimit) {
605
+ fail(
606
+ CONTROLLED_SKILL_PILOT_ERROR.GATE_FAILED,
607
+ "pilot canary traffic allocation is full",
608
+ );
609
+ }
610
+ }
611
+ const uniqueSubjects = new Set(
612
+ this._state.observations.map((row) => row.subjectDigest),
613
+ );
614
+ if (
615
+ !uniqueSubjects.has(observation.subjectDigest) &&
616
+ uniqueSubjects.size >= this.descriptor.cohort.maxSubjects
617
+ ) {
618
+ fail(CONTROLLED_SKILL_PILOT_ERROR.GATE_FAILED, "pilot cohort is full");
619
+ }
620
+ const next = clone(this._state);
621
+ next.observations.push(observation);
622
+ await this._commit(next, "pilot.observation-recorded", {
623
+ stage: observation.stage,
624
+ subjectDigest: observation.subjectDigest,
625
+ receiptDigest: observation.receiptDigest,
626
+ });
627
+ return this.view();
628
+ }
629
+
630
+ async advance() {
631
+ this._started();
632
+ this._noPending();
633
+ const target = FORWARD.get(this._state.stage);
634
+ if (!target) {
635
+ fail(
636
+ CONTROLLED_SKILL_PILOT_ERROR.INVALID,
637
+ "pilot cannot advance further",
638
+ );
639
+ }
640
+ if (this._state.stage === CONTROLLED_SKILL_PILOT_STAGE.CANDIDATE) {
641
+ fail(
642
+ CONTROLLED_SKILL_PILOT_ERROR.REVIEW_REQUIRED,
643
+ "shadow requires explicit durable human approval",
644
+ );
645
+ }
646
+ if (this._state.killSwitch) {
647
+ fail(
648
+ CONTROLLED_SKILL_PILOT_ERROR.KILL_SWITCH,
649
+ "pilot kill switch is set",
650
+ );
651
+ }
652
+ const observations = this._stageObservations();
653
+ const metrics = metricsFor(observations);
654
+ const elapsedMs = this._timestamp() - this._state.stageStartedAt;
655
+ const failures = gateFailures(this.descriptor, metrics, elapsedMs);
656
+ if (failures.length > 0) {
657
+ const error = new Error(`pilot gate failed: ${failures.join(", ")}`);
658
+ error.code = CONTROLLED_SKILL_PILOT_ERROR.GATE_FAILED;
659
+ error.failures = failures;
660
+ error.metrics = metrics;
661
+ throw error;
662
+ }
663
+ await this._assertActiveUnchanged();
664
+ const next = clone(this._state);
665
+ await this._advance(next, target, { metrics, elapsedMs });
666
+ return this.view();
667
+ }
668
+
669
+ async engageKillSwitch({ reasonDigest } = {}) {
670
+ this._started();
671
+ this._noPending();
672
+ digest(reasonDigest, "reasonDigest");
673
+ if (this._state.stage === CONTROLLED_SKILL_PILOT_STAGE.ROLLED_BACK) {
674
+ return this.view();
675
+ }
676
+ await this._assertActiveUnchanged();
677
+ const next = clone(this._state);
678
+ next.killSwitch = true;
679
+ await this._advance(next, CONTROLLED_SKILL_PILOT_STAGE.ROLLED_BACK, {
680
+ reasonDigest,
681
+ emergency: true,
682
+ });
683
+ return this.view();
684
+ }
685
+
686
+ async reconcilePendingTransition() {
687
+ this._started();
688
+ if (this._state.pendingTransition === null) return this.view();
689
+ await this._settlePreparedTransition(this._state.pendingTransition);
690
+ return this.view();
691
+ }
692
+
693
+ snapshot() {
694
+ return deepFreeze({
695
+ descriptorDigest: this.descriptorDigest,
696
+ stateDigest: hash(this._state),
697
+ state: clone(this._state),
698
+ });
699
+ }
700
+
701
+ view() {
702
+ const observations = this._stageObservations();
703
+ const shadowObservations = this._state.observations.filter(
704
+ (row) => row.stage === CONTROLLED_SKILL_PILOT_STAGE.SHADOW,
705
+ );
706
+ const canaryObservations = this._state.observations.filter(
707
+ (row) => row.stage === CONTROLLED_SKILL_PILOT_STAGE.CANARY,
708
+ );
709
+ return deepFreeze({
710
+ descriptorDigest: this.descriptorDigest,
711
+ stage: this._state.stage,
712
+ revision: this._state.revision,
713
+ killSwitch: this._state.killSwitch,
714
+ reviewReceiptDigest: this._state.reviewReceiptDigest,
715
+ metrics: {
716
+ current: metricsFor(observations),
717
+ shadow: metricsFor(shadowObservations),
718
+ canary: metricsFor(canaryObservations),
719
+ },
720
+ observationWindow: {
721
+ startedAt: this._state.stageStartedAt,
722
+ elapsedMs:
723
+ this._state.stageStartedAt === null
724
+ ? 0
725
+ : Math.max(0, this._timestamp() - this._state.stageStartedAt),
726
+ },
727
+ candidateDigest: this.descriptor.candidateDigest,
728
+ baselineDigest: this.descriptor.baselineDigest,
729
+ evalReceiptDigest: this.descriptor.evalReceiptDigest,
730
+ whyEvidenceDigest: this.descriptor.whyEvidenceDigest,
731
+ candidateDiffDigest: this.descriptor.candidateDiffDigest,
732
+ permissionDiffDigest: this.descriptor.permissionDiffDigest,
733
+ beforeEvaluationDigest: this.descriptor.beforeEvaluationDigest,
734
+ afterEvaluationDigest: this.descriptor.afterEvaluationDigest,
735
+ reviewPacketDigest: this.descriptor.reviewPacketDigest,
736
+ cohort: clone(this.descriptor.cohort),
737
+ lastTransitionReceiptDigest: this._state.lastTransitionReceiptDigest,
738
+ reconciliationRequired: this._state.pendingTransition !== null,
739
+ });
740
+ }
741
+
742
+ _started() {
743
+ if (this._state.activeStateDigest === null) {
744
+ fail(CONTROLLED_SKILL_PILOT_ERROR.INVALID, "pilot has not started");
745
+ }
746
+ }
747
+
748
+ _noPending() {
749
+ if (this._state.pendingTransition !== null) {
750
+ fail(
751
+ CONTROLLED_SKILL_PILOT_ERROR.PERSISTENCE_FAILED,
752
+ "pilot transition reconciliation is required",
753
+ );
754
+ }
755
+ }
756
+
757
+ _timestamp() {
758
+ const value = Number(this._now());
759
+ if (!Number.isSafeInteger(value) || value < 0) {
760
+ throw new TypeError("pilot clock is invalid");
761
+ }
762
+ return value;
763
+ }
764
+
765
+ _stageObservations() {
766
+ return this._state.observations.filter(
767
+ (row) => row.stage === this._state.stage,
768
+ );
769
+ }
770
+
771
+ async _assertActiveUnchanged() {
772
+ if (hash(await this._readActiveState()) !== this._state.activeStateDigest) {
773
+ fail(
774
+ CONTROLLED_SKILL_PILOT_ERROR.ACTIVE_DRIFT,
775
+ "active Skill changed outside the pilot authority",
776
+ );
777
+ }
778
+ }
779
+
780
+ async _advance(next, target, evidence) {
781
+ const from = this._state.stage;
782
+ if (target !== CONTROLLED_PILOT_ROLLBACK && FORWARD.get(from) !== target) {
783
+ fail(
784
+ CONTROLLED_SKILL_PILOT_ERROR.INVALID,
785
+ "non-canonical pilot transition",
786
+ );
787
+ }
788
+ const request = deepFreeze({
789
+ schema: CONTROLLED_SKILL_PILOT_EVENT_SCHEMA,
790
+ descriptorDigest: this.descriptorDigest,
791
+ tenantId: this.descriptor.tenantId,
792
+ pilotId: this.descriptor.pilotId,
793
+ candidateDigest: this.descriptor.candidateDigest,
794
+ from,
795
+ to: target,
796
+ evidence: clone(evidence),
797
+ requestedAt: this._timestamp(),
798
+ });
799
+ const requestDigest = hash(request);
800
+ next.pendingTransition = deepFreeze({ request, requestDigest });
801
+ await this._commit(next, "pilot.stage-transition-prepared", {
802
+ requestDigest,
803
+ from,
804
+ to: target,
805
+ });
806
+ await this._settlePreparedTransition(this._state.pendingTransition);
807
+ }
808
+
809
+ async _settlePreparedTransition(pending) {
810
+ const { request, requestDigest } = pending;
811
+ const from = request.from;
812
+ const target = request.to;
813
+ const result = await this._transitionStage({ request, requestDigest });
814
+ if (
815
+ result?.authenticated !== true ||
816
+ result?.durable !== true ||
817
+ result.descriptorDigest !== this.descriptorDigest ||
818
+ result.requestDigest !== requestDigest ||
819
+ result.from !== from ||
820
+ result.to !== target ||
821
+ !DIGEST.test(result.receiptDigest ?? "") ||
822
+ ([
823
+ CONTROLLED_SKILL_PILOT_STAGE.ACTIVE,
824
+ CONTROLLED_SKILL_PILOT_STAGE.ROLLED_BACK,
825
+ ].includes(target) &&
826
+ !DIGEST.test(result.activeStateDigest ?? ""))
827
+ ) {
828
+ fail(
829
+ CONTROLLED_SKILL_PILOT_ERROR.AUTHORITY_FAILED,
830
+ "rollout authority did not confirm the exact transition",
831
+ );
832
+ }
833
+ if (
834
+ [
835
+ CONTROLLED_SKILL_PILOT_STAGE.ACTIVE,
836
+ CONTROLLED_SKILL_PILOT_STAGE.ROLLED_BACK,
837
+ ].includes(target)
838
+ ) {
839
+ if (hash(await this._readActiveState()) !== result.activeStateDigest) {
840
+ fail(
841
+ CONTROLLED_SKILL_PILOT_ERROR.AUTHORITY_FAILED,
842
+ "rollout authority active-state acknowledgement does not match readback",
843
+ );
844
+ }
845
+ } else {
846
+ await this._assertActiveUnchanged();
847
+ }
848
+ const next = clone(this._state);
849
+ next.pendingTransition = null;
850
+ next.stage = target;
851
+ next.stageStartedAt = request.requestedAt;
852
+ next.lastTransitionReceiptDigest = result.receiptDigest;
853
+ if (
854
+ [
855
+ CONTROLLED_SKILL_PILOT_STAGE.ACTIVE,
856
+ CONTROLLED_SKILL_PILOT_STAGE.ROLLED_BACK,
857
+ ].includes(target)
858
+ ) {
859
+ next.activeStateDigest = result.activeStateDigest;
860
+ }
861
+ await this._commit(next, "pilot.stage-transitioned", {
862
+ requestDigest,
863
+ transitionReceiptDigest: result.receiptDigest,
864
+ from,
865
+ to: target,
866
+ });
867
+ }
868
+
869
+ async _commit(next, type, evidence) {
870
+ const expectedRevision = this._state.revision;
871
+ next.revision = expectedRevision + 1;
872
+ const stateDigest = hash(next);
873
+ const event = deepFreeze({
874
+ schema: CONTROLLED_SKILL_PILOT_EVENT_SCHEMA,
875
+ descriptorDigest: this.descriptorDigest,
876
+ tenantId: this.descriptor.tenantId,
877
+ pilotId: this.descriptor.pilotId,
878
+ type,
879
+ expectedRevision,
880
+ revision: next.revision,
881
+ stateDigest,
882
+ evidence: clone(evidence),
883
+ committedAt: this._timestamp(),
884
+ });
885
+ const eventDigest = hash(event);
886
+ const acknowledgement = await this._commitState({
887
+ expectedRevision,
888
+ state: deepFreeze(clone(next)),
889
+ stateDigest,
890
+ event,
891
+ eventDigest,
892
+ });
893
+ if (
894
+ acknowledgement?.authenticated !== true ||
895
+ acknowledgement?.durable !== true ||
896
+ acknowledgement.descriptorDigest !== this.descriptorDigest ||
897
+ acknowledgement.revision !== next.revision ||
898
+ acknowledgement.stateDigest !== stateDigest ||
899
+ acknowledgement.eventDigest !== eventDigest
900
+ ) {
901
+ fail(
902
+ CONTROLLED_SKILL_PILOT_ERROR.PERSISTENCE_FAILED,
903
+ "pilot state was not durably authenticated",
904
+ );
905
+ }
906
+ this._state = next;
907
+ }
908
+ }
909
+
910
+ export function createControlledSkillProductionPilot(options) {
911
+ return new ControlledSkillProductionPilot(options);
912
+ }