chainlesschain 0.166.18 → 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.
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-CQSBl3hY.js → AIOps-BjMnsUci.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-IQt-vRLt.js → ActionButton-DdYFP03A.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DkHC8O7k.js → Analytics-Bb8TuuK_.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CSti2P2T.js → AppLayout-Kn3TIOtk.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-C57hxn3v.js → Artifacts-4IxpqI_b.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DByLntcf.js → Audit-BOV2caqU.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D1Bd2EOa.js → BackgroundAgents-B86k-ay4.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-VstHzHng.js → Backup-C5_ie1e3.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CLhdexIf.js → BaseInput-xpwg6QCW.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BefC_JZS.js → Chat-CVZOcZau.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DbXMvgmn.js → ChatBubbleRenderer-D8fPYhUu.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CEY982vx.js → Checkbox-MKTq3zdP.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Dcm_DTvJ.js → Codegen-JUk3wzep.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C8SSu4KA.js → Col-JPvTA0kC.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BVV9vwRR.js → Community-Tqgl87NQ.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-B7c5Vo18.js → Compact-BuAFYBmN.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Tq9jSZ5a.js → Compliance-CXS9WIPZ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BJUjT09Q.js → Cowork-Ds2bFHrr.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CjV9PEaS.js → Cron-C_dV_OeW.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dl7ReL8F.js → Crosschain-BsO6tIRo.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CG8PjWmM.js → DID-rNOFqBac.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CDBM6wmF.js → Dashboard-C2fcKKVY.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-8_55bXTD.js → Dropdown-Y7Ndr0X_.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-D3qOU1Cm.js → EmailListRenderer-DcP_uPmL.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bv5oWMZF.js → FamilyGuardDashboard-Cwn3gDzk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-hpZ1xkKd.js → Federation-ClQuOsqb.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BN7GT191.js → FormItemContext-DfwtmlcK.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-PCRhfA7M.js → GenericCardRenderer-zNZhtbC5.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CIlP2vy7.js → Git-BZmdW-G5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-81lgm7YL.js → Governance-CqBk4lEn.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Cs24xMOV.js → Inference-Dbmt3ZXk.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CrJLVCZo.js → KnowledgeGraph-hMTH6qf3.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DLyO8RKT.js → Logs-CkiYgiW2.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DBOqijrP.js → MarkdownRenderer-BL1FElXg.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-Dz7AbQZc.js → Marketplace-CbB6wfin.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BM0aFiWv.js → McpTools-BSwiFtte.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-C9SJzENX.js → Memory-B03PeHrz.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BO2HnNRk.js → MobileBridge-CRGrnd-X.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CK_jMz0l.js → MobileProjects-CE_5v2kO.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CfhrJsdO.js → Mtc-Dp11QVx1.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BE2ELxgI.js → MtcAudit-CYu-3JBu.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CgR_E3Jd.js → Multisig-CGyJ0Xl3.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Cw9445_K.js → NLProgramming-CoWi_ov1.js} +1 -1
- package/src/assets/web-panel/assets/Notes-CgU9DDo9.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-DxHVh4uT.js → NotificationSettings-DX4I2b4W.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CwHc15Zs.js +1 -0
- package/src/assets/web-panel/assets/{Organization-pPXJtWo4.js → Organization-oopLO_tk.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-YamdTJwA.js → Overflow-BFVvjMyf.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BvqP53x7.js → P2P-CBy5t-Tk.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Blz1Xn2n.js → PdhVaultBrowser--YWJNsu6.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CgFRQqFJ.js → Permissions-C2dZ8scb.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CFeo3-6O.js → PersonalDataHub-Bs3l7Hlx.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-BkaRojEK.js → Pipeline-DEBWbZuD.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BNZEx2Qp.js → Privacy-CjHBb6NU.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-HUBOgEEK.js → ProjectInit-D2WipUz5.js} +2 -2
- package/src/assets/web-panel/assets/ProjectSettings-B6WfnrGB.js +2 -0
- package/src/assets/web-panel/assets/{Projects-Dc517BXp.js → Projects-FF_thRi6.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DTLf8bgj.js → Providers-CCv5M_Dv.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BBNjPszk.js → QrScannerModal-CGthxU54.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DCsHvk3G.js → QuickAsk-CnPmXPFb.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Dpr5YSop.js → Recommend-Df_tGEa9.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DmKnvqGg.js → RemoteSession-Z58N0Loe.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CSRfuurX.js → Reputation-CZTBQ2Vt.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CDj3pQ_w.js → Row-CdK3YpCQ.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DI0a_kNq.js → RssFeed-CFMVT5sb.js} +3 -3
- package/src/assets/web-panel/assets/{Search-jAy7B2nU.js → Search-DrF8RIvD.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CkHTqYhc.js → Security-Ddk2f2DM.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CP-0Nzga.js → Services-CCuK-VOo.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BkF5-p3n.js → Skeleton-DxCpHzeM.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BDu-utDE.js → Skills-t2oTDgcv.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CQvq_2Qb.js → Sla-Df63M9_R.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-T7Ap512g.js → SpeechSettings-l7ox6KuX.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Bt-PLvot.js → SyncSettings-COd_tgPp.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-yLEcCogg.js → Tasks-CzDCcrik.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-ByN3fmbr.js → Templates-D-vfxTGA.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DBI7hITH.js → Tenant-BlpT_Gxc.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B77_DlGX.js → Terminal-D5rq52Hg.js} +2 -2
- package/src/assets/web-panel/assets/TimelineRenderer-DdoMndkK.js +1 -0
- package/src/assets/web-panel/assets/{Tokens-BV2N6cR8.js → Tokens-BhgBsI6g.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CjXWGH3p.js → Trigger-DwwzoikZ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-uqXIq3WC.js → Trust-HkTpzXFb.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-D-6qu4vY.js → UkeySign-D9nk6Ehe.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CxGmx_2e.js → VideoEditing-BKk0rfoy.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DSq7WlAg.js → Wallet-IVWIU_Lq.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CDBiD57O.js → WebAuthn-CFTCpfsG.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Z8f63TSb.js → WorkflowEditor-Dnf4Obif.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B-UZFBjy.js → chat-D2snERdj.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CFk7K-7Q.js → colors-DKEjK1N1.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-X0IVMvgi.js → compact-item-BEDLwQdt.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DWg4j2n6.js → createContext-DA9iW1a0.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DyhgpXPf.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CkVCwNNF.js → hasIn-5l2xEcY9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BipwEbTA.js → index-5pW4t1iD.js} +1 -1
- package/src/assets/web-panel/assets/{index-5OcZHdzc.js → index-7P1b8HZo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cvwu_rA_.js → index-B00GeekA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbIAWbma.js → index-B4QYBliR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNKFsBlz.js → index-B7_W_rYd.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoskgPt9.js → index-BO9dQjpt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvOa-IFV.js → index-BZ5lY2zx.js} +1 -1
- package/src/assets/web-panel/assets/{index-_-9k3Tna.js → index-B_eCoZgW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbihMThv.js → index-BgfImyZI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLSBks8h.js → index-Bq5P3piS.js} +1 -1
- package/src/assets/web-panel/assets/{index-LU54bChK.js → index-Bqc8tdIF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Btqk6zWb.js → index-C7sKbM5s.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8uEL8Uw.js → index-CGlotREA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLlP1E4X.js → index-CRPrHE7h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeWKPQGs.js → index-CX1x4AFn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Db_5xhrU.js → index-CbTPvp2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDfSD07S.js → index-CjWltbi_.js} +1 -1
- package/src/assets/web-panel/assets/index-Ck1jhFE0.js +1 -0
- package/src/assets/web-panel/assets/{index-BPBia4b-.js → index-CkMKuqUs.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1ZAOJRW.js → index-CmruhzFi.js} +1 -1
- package/src/assets/web-panel/assets/{index-P83LDnCz.js → index-Csfb-7hw.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcDggpWR.js → index-CxEtQYdi.js} +1 -1
- package/src/assets/web-panel/assets/{index-OjnAwUJo.js → index-D7z4zB_a.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-EJNxgR.js → index-DLoalqRX.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3-B3FWD.js → index-DU2TXJu-.js} +1 -1
- package/src/assets/web-panel/assets/{index-D92g4l3n.js → index-DXet1xol.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ca0mij1n.js → index-Dbd7eEex.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCqpl_E_.js → index-Dbkghqn_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyWlOuak.js → index-Dg2a9owQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUBkvFPH.js → index-DpqtbXdE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhVHoqGL.js → index-DqwPFbOb.js} +3 -3
- package/src/assets/web-panel/assets/{index-BG-GaZri.js → index-DvV03Ayk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMCEXBRh.js → index-NJieh3T1.js} +1 -1
- package/src/assets/web-panel/assets/{index-B273IY-E.js → index-Td8ZwyoC.js} +1 -1
- package/src/assets/web-panel/assets/index-c8jJEHVs.js +1 -0
- package/src/assets/web-panel/assets/{index-BzXjYUmd.js → index-e-e40id6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCLwoATF.js → index-fccZmC_h.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN8HZlLH.js → index-fgYk0QXO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BB4KHHcv.js → index-yYEQXYaU.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CFNgY8lJ.js → initDefaultProps-CPrcB1TC.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D-5RrDzn.js → motion-BQ7mWRh_.js} +1 -1
- package/src/assets/web-panel/assets/{move-DN-L0Bd-.js → move-CzOEq99p.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-6mgLSeCK.js → mtc-parser-BlQI5jrw.js} +1 -1
- package/src/assets/web-panel/assets/{omit-ClWW8eTP.js → omit-DlW4gxmv.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Vystq3R8.js → pickAttrs-BBYms5nP.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D0H9hK4W.js → placementArrow-az2MPJ_7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B3iNRU-a.js → responsiveObserve-D1-ibEol.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CiMXe6am.js → slide-DHGqa4GA.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CGDZJ1uT.js → statusUtils-CYGDo6lD.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-D2zA6NkY.js → styleChecker-Cl2EM9K6.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C1sYU6QE.js → useFlexGapSupport-DdYhzuv1.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BzUHSjg2.js → useFs-DWumPuBW.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CxB5yZCq.js → usePersonalDataHub-DxAO-Aqi.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BfUfMwtc.js → vnode-CplsQf_N.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CFYmj1TO.js → zoom-Cw5HXNSG.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/commands/agent.js +19 -1
- package/src/commands/evolution-knowledge.js +54 -0
- package/src/commands/evolution-workbench.js +83 -0
- package/src/commands/evolution.js +6 -1
- package/src/commands/serve.js +16 -0
- package/src/commands/skill.js +158 -16
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/session-protocol.js +2 -0
- package/src/gateways/ws/ws-agent-handler.js +124 -69
- package/src/gateways/ws/ws-server.js +19 -0
- package/src/generated/cc-agent-protocol.schema.json +7 -1
- package/src/harness/jsonl-session-store.js +25 -1
- package/src/index.js +1 -1
- package/src/lib/app-server/cli-agent-kernel-adapter.js +8 -0
- package/src/lib/app-server/graph-runtime.js +40 -1
- package/src/lib/app-server/server.js +181 -3
- package/src/lib/app-server/websocket-transport.js +2 -0
- package/src/lib/evolution/agent-evolution-runtime-composition-brand.js +17 -0
- package/src/lib/evolution/agent-evolution-runtime-composition.js +165 -1
- package/src/lib/evolution/controlled-skill-production-pilot.js +912 -0
- package/src/lib/evolution/evolution-artifact-ports.js +21 -0
- package/src/lib/evolution/evolution-raw-crypto-shred.js +185 -0
- package/src/lib/evolution/evolution-workbench-batch-executor.js +195 -0
- package/src/lib/evolution/evolution-workbench-cli-host.js +169 -0
- package/src/lib/evolution/evolution-workbench-metrics-ledger-adapter.js +648 -0
- package/src/lib/evolution/evolution-workbench-metrics.js +943 -0
- package/src/lib/evolution/evolution-workbench-projection.js +734 -0
- package/src/lib/evolution/evolution-workbench-version-control.js +272 -0
- package/src/lib/evolution/governed-knowledge-conflict-merge.js +352 -0
- package/src/lib/evolution/governed-knowledge-dependency-authority.js +273 -0
- package/src/lib/evolution/governed-knowledge-dependency-ledger-executor.js +646 -0
- package/src/lib/evolution/governed-knowledge-merge-ledger-executor.js +644 -0
- package/src/lib/evolution/governed-knowledge-merge-publisher-authority.js +282 -0
- package/src/lib/evolution/governed-knowledge-node-crypto-authority.js +348 -0
- package/src/lib/evolution/governed-knowledge-rbac-approval-authority.js +621 -0
- package/src/lib/evolution/governed-knowledge-review-host.js +249 -0
- package/src/lib/evolution/governed-knowledge-sync-ledger-adapter.js +643 -0
- package/src/lib/evolution/governed-knowledge-sync-merge-publisher.js +259 -0
- package/src/lib/evolution/governed-knowledge-sync.js +485 -0
- package/src/lib/evolution/governed-knowledge-trust-ledger.js +707 -0
- package/src/lib/evolution/governed-skill-marketplace.js +430 -0
- package/src/lib/evolution/governed-wiki-pruning.js +435 -0
- package/src/lib/evolution/skill-outcome-index-authority.js +268 -0
- package/src/lib/evolution/skill-outcome-source-catalog-authority.js +237 -0
- package/src/lib/public-ide-capability-manifest.js +4 -0
- package/src/lib/skill-outcome-authority.js +43 -0
- package/src/lib/skill-outcome-transcript-authority.js +252 -0
- package/src/lib/skill-retrieval-router-benchmark.js +135 -0
- package/src/lib/skill-retrieval-router.js +235 -0
- package/src/lib/skill-vector-authority.js +325 -0
- package/src/lib/skill-vector-process-authority.js +386 -0
- package/src/repl/agent-repl.js +7 -1
- package/src/runtime/agent-core.js +72 -6
- package/src/runtime/agent-runtime.js +42 -0
- package/src/runtime/headless-runner.js +32 -0
- package/src/runtime/headless-stream.js +36 -1
- package/src/runtime/runtime-factory.js +62 -4
- package/src/assets/web-panel/assets/Notes-DZimkTrb.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-Iy-pnX56.js +0 -1
- package/src/assets/web-panel/assets/ProjectSettings-CFMmhROS.js +0 -2
- package/src/assets/web-panel/assets/TimelineRenderer-CsLTB_QO.js +0 -1
- package/src/assets/web-panel/assets/devWarning-B2IW1J_J.js +0 -1
- package/src/assets/web-panel/assets/index-BCp2ir-1.js +0 -1
- package/src/assets/web-panel/assets/index-Bw4iuzRD.js +0 -1
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { types as utilTypes } from "node:util";
|
|
3
|
+
|
|
4
|
+
export const SKILL_OUTCOME_SOURCE_CATALOG_SCHEMA =
|
|
5
|
+
"chainlesschain.skill-outcome-source-catalog/v1";
|
|
6
|
+
export const SKILL_OUTCOME_SOURCE_CATALOG_ATTESTATION_SCHEMA =
|
|
7
|
+
"chainlesschain.skill-outcome-source-catalog-attestation/v1";
|
|
8
|
+
|
|
9
|
+
const AUTHORITIES = new WeakSet();
|
|
10
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
11
|
+
const SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,255}$/u;
|
|
12
|
+
const MAX_SOURCES = 128;
|
|
13
|
+
const CATALOG_KEYS = new Set([
|
|
14
|
+
"attestation",
|
|
15
|
+
"catalogDigest",
|
|
16
|
+
"catalogId",
|
|
17
|
+
"entries",
|
|
18
|
+
"issuedAt",
|
|
19
|
+
"revision",
|
|
20
|
+
"schema",
|
|
21
|
+
"tenantId",
|
|
22
|
+
]);
|
|
23
|
+
const ENTRY_KEYS = new Set(["runId", "skillNames"]);
|
|
24
|
+
const ATTESTATION_KEYS = new Set(["algorithm", "keyId", "schema", "value"]);
|
|
25
|
+
const VERIFICATION_KEYS = new Set([
|
|
26
|
+
"authenticated",
|
|
27
|
+
"catalogDigest",
|
|
28
|
+
"catalogId",
|
|
29
|
+
"durable",
|
|
30
|
+
"receiptDigest",
|
|
31
|
+
"revision",
|
|
32
|
+
"tenantId",
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
function canonical(value) {
|
|
36
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
37
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
38
|
+
return `{${Object.keys(value)
|
|
39
|
+
.sort()
|
|
40
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
41
|
+
.join(",")}}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hash(value) {
|
|
45
|
+
return `sha256:${createHash("sha256")
|
|
46
|
+
.update(SKILL_OUTCOME_SOURCE_CATALOG_SCHEMA)
|
|
47
|
+
.update("\0")
|
|
48
|
+
.update(canonical(value))
|
|
49
|
+
.digest("hex")}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function exact(value, keys, label) {
|
|
53
|
+
if (
|
|
54
|
+
!value ||
|
|
55
|
+
typeof value !== "object" ||
|
|
56
|
+
Array.isArray(value) ||
|
|
57
|
+
utilTypes.isProxy(value) ||
|
|
58
|
+
Reflect.ownKeys(value).length !== keys.size ||
|
|
59
|
+
Reflect.ownKeys(value).some(
|
|
60
|
+
(key) => typeof key !== "string" || !keys.has(key),
|
|
61
|
+
)
|
|
62
|
+
) {
|
|
63
|
+
throw new TypeError(`${label} is invalid`);
|
|
64
|
+
}
|
|
65
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
66
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
67
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
|
|
68
|
+
throw new TypeError(`${label}.${String(key)} is invalid`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function identifier(value, label) {
|
|
75
|
+
if (typeof value !== "string" || !SAFE_ID.test(value)) {
|
|
76
|
+
throw new TypeError(`${label} is invalid`);
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function capture(owner, method, label) {
|
|
82
|
+
if (!owner || typeof owner !== "object" || utilTypes.isProxy(owner)) {
|
|
83
|
+
throw new TypeError(`${label}.${method}() is required`);
|
|
84
|
+
}
|
|
85
|
+
const operation = owner[method];
|
|
86
|
+
if (typeof operation !== "function" || utilTypes.isProxy(operation)) {
|
|
87
|
+
throw new TypeError(`${label}.${method}() is required`);
|
|
88
|
+
}
|
|
89
|
+
return Object.freeze((...args) => Reflect.apply(operation, owner, args));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function digestSkillOutcomeSourceCatalog(value) {
|
|
93
|
+
return hash({
|
|
94
|
+
schema: value.schema,
|
|
95
|
+
tenantId: value.tenantId,
|
|
96
|
+
catalogId: value.catalogId,
|
|
97
|
+
revision: value.revision,
|
|
98
|
+
issuedAt: value.issuedAt,
|
|
99
|
+
entries: value.entries,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function verifyCatalog(value, tenantId) {
|
|
104
|
+
exact(value, CATALOG_KEYS, "Skill outcome source catalog");
|
|
105
|
+
if (
|
|
106
|
+
value.schema !== SKILL_OUTCOME_SOURCE_CATALOG_SCHEMA ||
|
|
107
|
+
value.tenantId !== tenantId ||
|
|
108
|
+
!SAFE_ID.test(value.catalogId ?? "") ||
|
|
109
|
+
!Number.isSafeInteger(value.revision) ||
|
|
110
|
+
value.revision < 1 ||
|
|
111
|
+
typeof value.issuedAt !== "string" ||
|
|
112
|
+
!Number.isFinite(Date.parse(value.issuedAt)) ||
|
|
113
|
+
!Array.isArray(value.entries) ||
|
|
114
|
+
utilTypes.isProxy(value.entries) ||
|
|
115
|
+
value.entries.length < 1 ||
|
|
116
|
+
value.entries.length > MAX_SOURCES ||
|
|
117
|
+
!DIGEST.test(value.catalogDigest ?? "")
|
|
118
|
+
) {
|
|
119
|
+
throw new TypeError("Skill outcome source catalog is invalid or unbounded");
|
|
120
|
+
}
|
|
121
|
+
const runIds = new Set();
|
|
122
|
+
let sourceCount = 0;
|
|
123
|
+
const entries = value.entries.map((input, index) => {
|
|
124
|
+
const entry = exact(input, ENTRY_KEYS, `catalog.entries[${index}]`);
|
|
125
|
+
const runId = identifier(entry.runId, `catalog.entries[${index}].runId`);
|
|
126
|
+
if (runIds.has(runId)) {
|
|
127
|
+
throw new TypeError(
|
|
128
|
+
"Skill outcome source catalog contains a duplicate run",
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
runIds.add(runId);
|
|
132
|
+
if (
|
|
133
|
+
!Array.isArray(entry.skillNames) ||
|
|
134
|
+
utilTypes.isProxy(entry.skillNames) ||
|
|
135
|
+
entry.skillNames.length < 1 ||
|
|
136
|
+
entry.skillNames.length > MAX_SOURCES
|
|
137
|
+
) {
|
|
138
|
+
throw new TypeError(
|
|
139
|
+
`catalog.entries[${index}].skillNames is invalid or unbounded`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const skillNames = entry.skillNames.map((skillName, skillIndex) =>
|
|
143
|
+
identifier(
|
|
144
|
+
skillName,
|
|
145
|
+
`catalog.entries[${index}].skillNames[${skillIndex}]`,
|
|
146
|
+
),
|
|
147
|
+
);
|
|
148
|
+
if (new Set(skillNames).size !== skillNames.length) {
|
|
149
|
+
throw new TypeError(
|
|
150
|
+
"Skill outcome source catalog contains a duplicate Skill",
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
sourceCount += skillNames.length;
|
|
154
|
+
if (sourceCount > MAX_SOURCES) {
|
|
155
|
+
throw new TypeError(
|
|
156
|
+
"Skill outcome source catalog is invalid or unbounded",
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return Object.freeze({ runId, skillNames: Object.freeze(skillNames) });
|
|
160
|
+
});
|
|
161
|
+
exact(
|
|
162
|
+
value.attestation,
|
|
163
|
+
ATTESTATION_KEYS,
|
|
164
|
+
"Skill outcome source catalog attestation",
|
|
165
|
+
);
|
|
166
|
+
if (
|
|
167
|
+
value.attestation.schema !==
|
|
168
|
+
SKILL_OUTCOME_SOURCE_CATALOG_ATTESTATION_SCHEMA ||
|
|
169
|
+
!SAFE_ID.test(value.attestation.algorithm ?? "") ||
|
|
170
|
+
!SAFE_ID.test(value.attestation.keyId ?? "") ||
|
|
171
|
+
typeof value.attestation.value !== "string" ||
|
|
172
|
+
value.attestation.value.length < 16 ||
|
|
173
|
+
value.attestation.value.length > 4096 ||
|
|
174
|
+
value.catalogDigest !== digestSkillOutcomeSourceCatalog(value)
|
|
175
|
+
) {
|
|
176
|
+
throw new Error("Skill outcome source catalog integrity is invalid");
|
|
177
|
+
}
|
|
178
|
+
return Object.freeze({ ...value, entries: Object.freeze(entries) });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function createSkillOutcomeSourceCatalogAuthority({
|
|
182
|
+
tenantId: tenantIdInput,
|
|
183
|
+
loader,
|
|
184
|
+
verifier,
|
|
185
|
+
} = {}) {
|
|
186
|
+
const tenantId = identifier(tenantIdInput, "tenantId");
|
|
187
|
+
const load = capture(loader, "load", "catalog loader");
|
|
188
|
+
const verify = capture(verifier, "verify", "catalog verifier");
|
|
189
|
+
const authority = Object.freeze({
|
|
190
|
+
async loadCatalog() {
|
|
191
|
+
const catalog = verifyCatalog(await load({ tenantId }), tenantId);
|
|
192
|
+
const verification = exact(
|
|
193
|
+
await verify({
|
|
194
|
+
tenantId,
|
|
195
|
+
catalogId: catalog.catalogId,
|
|
196
|
+
revision: catalog.revision,
|
|
197
|
+
catalogDigest: catalog.catalogDigest,
|
|
198
|
+
attestation: catalog.attestation,
|
|
199
|
+
}),
|
|
200
|
+
VERIFICATION_KEYS,
|
|
201
|
+
"Skill outcome source catalog verification",
|
|
202
|
+
);
|
|
203
|
+
if (
|
|
204
|
+
verification.authenticated !== true ||
|
|
205
|
+
verification.durable !== true ||
|
|
206
|
+
verification.tenantId !== tenantId ||
|
|
207
|
+
verification.catalogId !== catalog.catalogId ||
|
|
208
|
+
verification.revision !== catalog.revision ||
|
|
209
|
+
verification.catalogDigest !== catalog.catalogDigest ||
|
|
210
|
+
!DIGEST.test(verification.receiptDigest ?? "")
|
|
211
|
+
) {
|
|
212
|
+
throw new Error("Skill outcome source catalog is not authoritative");
|
|
213
|
+
}
|
|
214
|
+
return Object.freeze({
|
|
215
|
+
authenticated: true,
|
|
216
|
+
durable: true,
|
|
217
|
+
tenantId,
|
|
218
|
+
catalogId: catalog.catalogId,
|
|
219
|
+
revision: catalog.revision,
|
|
220
|
+
catalogDigest: catalog.catalogDigest,
|
|
221
|
+
receiptDigest: verification.receiptDigest,
|
|
222
|
+
entries: catalog.entries,
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
AUTHORITIES.add(authority);
|
|
227
|
+
return authority;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function captureSkillOutcomeSourceCatalogAuthority(value) {
|
|
231
|
+
if (!AUTHORITIES.has(value)) {
|
|
232
|
+
throw new TypeError(
|
|
233
|
+
"a branded Skill outcome source catalog authority is required",
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
return value;
|
|
237
|
+
}
|
|
@@ -59,6 +59,8 @@ const VSCODE_COMMANDS = [
|
|
|
59
59
|
"chainlesschain.appServerPilot.interrupt",
|
|
60
60
|
"chainlesschain.usage.show",
|
|
61
61
|
"chainlesschain.plugins.manage",
|
|
62
|
+
"chainlesschain.skills.retrieve",
|
|
63
|
+
"chainlesschain.evolution.workbench",
|
|
62
64
|
"chainlesschain.worktree.tasks",
|
|
63
65
|
"chainlesschain.chrome.connector",
|
|
64
66
|
"chainlesschain.artifacts.show",
|
|
@@ -114,6 +116,8 @@ const JETBRAINS_ACTIONS = [
|
|
|
114
116
|
"chainlesschain.policy.Viewer",
|
|
115
117
|
"chainlesschain.context.Center",
|
|
116
118
|
"chainlesschain.plugins.Manage",
|
|
119
|
+
"chainlesschain.skills.Retrieve",
|
|
120
|
+
"chainlesschain.evolution.Workbench",
|
|
117
121
|
"chainlesschain.worktree.Tasks",
|
|
118
122
|
"chainlesschain.chrome.Connector",
|
|
119
123
|
"chainlesschain.workspace.ScanAutoExec",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildSkillOutcomeIndexAuthority,
|
|
3
|
+
unavailableSkillOutcomeIndexAuthority,
|
|
4
|
+
} from "./evolution/skill-outcome-index-authority.js";
|
|
5
|
+
import {
|
|
6
|
+
buildSkillOutcomeTranscriptAuthority,
|
|
7
|
+
unavailableSkillOutcomeTranscriptAuthority,
|
|
8
|
+
} from "./skill-outcome-transcript-authority.js";
|
|
9
|
+
|
|
10
|
+
export function resolveSkillOutcomeAuthority(options = {}, dependencies = {}) {
|
|
11
|
+
if (
|
|
12
|
+
options &&
|
|
13
|
+
typeof options === "object" &&
|
|
14
|
+
Object.prototype.hasOwnProperty.call(options, "index")
|
|
15
|
+
) {
|
|
16
|
+
const buildIndex =
|
|
17
|
+
dependencies.buildSkillOutcomeIndexAuthority ||
|
|
18
|
+
buildSkillOutcomeIndexAuthority;
|
|
19
|
+
const unavailableIndex =
|
|
20
|
+
dependencies.unavailableSkillOutcomeIndexAuthority ||
|
|
21
|
+
unavailableSkillOutcomeIndexAuthority;
|
|
22
|
+
try {
|
|
23
|
+
return buildIndex(options.index, dependencies.indexDependencies);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return unavailableIndex(error);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const buildTranscript =
|
|
30
|
+
dependencies.buildSkillOutcomeTranscriptAuthority ||
|
|
31
|
+
buildSkillOutcomeTranscriptAuthority;
|
|
32
|
+
const unavailableTranscript =
|
|
33
|
+
dependencies.unavailableSkillOutcomeTranscriptAuthority ||
|
|
34
|
+
unavailableSkillOutcomeTranscriptAuthority;
|
|
35
|
+
try {
|
|
36
|
+
return buildTranscript(
|
|
37
|
+
options?.transcriptOptions,
|
|
38
|
+
dependencies.transcriptDependencies,
|
|
39
|
+
);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return unavailableTranscript(error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import skillInvocationReceipt from "@chainlesschain/session-core/skill-invocation-receipt";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
listSessionAuthoritySummaries,
|
|
6
|
+
readVerifiedProjection,
|
|
7
|
+
} from "../harness/jsonl-session-store.js";
|
|
8
|
+
import { canonicalJson } from "./scheduler-kernel/contract.js";
|
|
9
|
+
|
|
10
|
+
const { verifySkillInvocationReceipt } = skillInvocationReceipt;
|
|
11
|
+
|
|
12
|
+
export const SKILL_OUTCOME_AUTHORITY_SCHEMA =
|
|
13
|
+
"chainlesschain.skill-outcome-transcript-authority/v1";
|
|
14
|
+
export const MAX_OUTCOME_AUTHORITY_SESSIONS = 128;
|
|
15
|
+
export const MAX_OUTCOME_AUTHORITY_RECEIPTS = 10_000;
|
|
16
|
+
|
|
17
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
18
|
+
const TRANSCRIPT_HASH = /^[a-f0-9]{64}$/u;
|
|
19
|
+
|
|
20
|
+
function unavailable(message, code = "CC_SKILL_OUTCOME_AUTHORITY_UNAVAILABLE") {
|
|
21
|
+
const error = new Error(message);
|
|
22
|
+
error.code = code;
|
|
23
|
+
return error;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function verifiedReceipt(receipt) {
|
|
27
|
+
verifySkillInvocationReceipt(receipt);
|
|
28
|
+
if (
|
|
29
|
+
!Array.isArray(receipt.selectedSkillDigests) ||
|
|
30
|
+
receipt.selectedSkillDigests.length !== 1 ||
|
|
31
|
+
!DIGEST.test(receipt.selectedSkillDigests[0] || "")
|
|
32
|
+
) {
|
|
33
|
+
throw unavailable("Skill outcome receipt has an invalid selection binding");
|
|
34
|
+
}
|
|
35
|
+
if (
|
|
36
|
+
!Array.isArray(receipt.graderReceipts) ||
|
|
37
|
+
receipt.graderReceipts.length > 64 ||
|
|
38
|
+
receipt.graderReceipts.some((digest) => !DIGEST.test(digest || "")) ||
|
|
39
|
+
(receipt.userCorrectionRef !== null &&
|
|
40
|
+
(typeof receipt.userCorrectionRef !== "string" ||
|
|
41
|
+
receipt.userCorrectionRef.length < 1 ||
|
|
42
|
+
receipt.userCorrectionRef.length > 256)) ||
|
|
43
|
+
(receipt.attributionEligible === true &&
|
|
44
|
+
(receipt.attributionStatus !== "complete" ||
|
|
45
|
+
!Array.isArray(receipt.missingAttribution) ||
|
|
46
|
+
receipt.missingAttribution.length !== 0))
|
|
47
|
+
) {
|
|
48
|
+
throw unavailable("Skill outcome receipt has an invalid attribution state");
|
|
49
|
+
}
|
|
50
|
+
return receipt;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function transcriptReceiptProjection(receipts, capacity) {
|
|
54
|
+
return {
|
|
55
|
+
accept(event) {
|
|
56
|
+
const receipt = event?.data?.skill_invocation_receipt;
|
|
57
|
+
if (receipt === undefined) return;
|
|
58
|
+
if (event.type !== "tool_call" || event.data?.tool !== "run_skill") {
|
|
59
|
+
throw unavailable(
|
|
60
|
+
"Skill outcome receipt is bound to a non-Skill event",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (receipts.length >= capacity) {
|
|
64
|
+
throw unavailable(
|
|
65
|
+
"Skill outcome receipt capacity exceeded",
|
|
66
|
+
"CC_SKILL_OUTCOME_AUTHORITY_CAPACITY",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
receipts.push(verifiedReceipt(receipt));
|
|
70
|
+
},
|
|
71
|
+
finish(authority) {
|
|
72
|
+
if (
|
|
73
|
+
!authority ||
|
|
74
|
+
!Number.isSafeInteger(authority.eventCount) ||
|
|
75
|
+
authority.eventCount < 0 ||
|
|
76
|
+
(authority.headHash !== null &&
|
|
77
|
+
!TRANSCRIPT_HASH.test(authority.headHash || ""))
|
|
78
|
+
) {
|
|
79
|
+
throw unavailable("Verified transcript returned invalid authority");
|
|
80
|
+
}
|
|
81
|
+
return Object.freeze({
|
|
82
|
+
headHash: authority.headHash,
|
|
83
|
+
eventCount: authority.eventCount,
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Build bounded outcome metrics only from fully verified canonical transcripts.
|
|
91
|
+
* Any damaged/blocked selected session or projection failure disables the whole
|
|
92
|
+
* sample instead of silently ranking from a favorable partial subset.
|
|
93
|
+
*/
|
|
94
|
+
export function buildSkillOutcomeTranscriptAuthority(
|
|
95
|
+
options = {},
|
|
96
|
+
dependencies = {},
|
|
97
|
+
) {
|
|
98
|
+
const maxSessions =
|
|
99
|
+
options.maxSessions === undefined
|
|
100
|
+
? MAX_OUTCOME_AUTHORITY_SESSIONS
|
|
101
|
+
: Number(options.maxSessions);
|
|
102
|
+
const maxReceipts =
|
|
103
|
+
options.maxReceipts === undefined
|
|
104
|
+
? MAX_OUTCOME_AUTHORITY_RECEIPTS
|
|
105
|
+
: Number(options.maxReceipts);
|
|
106
|
+
if (
|
|
107
|
+
!Number.isSafeInteger(maxSessions) ||
|
|
108
|
+
maxSessions < 1 ||
|
|
109
|
+
maxSessions > MAX_OUTCOME_AUTHORITY_SESSIONS ||
|
|
110
|
+
!Number.isSafeInteger(maxReceipts) ||
|
|
111
|
+
maxReceipts < 1 ||
|
|
112
|
+
maxReceipts > MAX_OUTCOME_AUTHORITY_RECEIPTS
|
|
113
|
+
) {
|
|
114
|
+
throw new TypeError("Skill outcome authority bounds are invalid");
|
|
115
|
+
}
|
|
116
|
+
const list =
|
|
117
|
+
dependencies.listSessionAuthoritySummaries || listSessionAuthoritySummaries;
|
|
118
|
+
const read = dependencies.readVerifiedProjection || readVerifiedProjection;
|
|
119
|
+
if (typeof list !== "function" || typeof read !== "function") {
|
|
120
|
+
throw new TypeError(
|
|
121
|
+
"Skill outcome transcript authority ports are required",
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
const rows = list({ limit: maxSessions });
|
|
125
|
+
if (!Array.isArray(rows) || rows.length > maxSessions) {
|
|
126
|
+
throw unavailable(
|
|
127
|
+
"Skill outcome session authority is invalid or unbounded",
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
const sessionIds = new Set();
|
|
131
|
+
for (const row of rows) {
|
|
132
|
+
if (
|
|
133
|
+
!row ||
|
|
134
|
+
typeof row.id !== "string" ||
|
|
135
|
+
row.id.length < 1 ||
|
|
136
|
+
row.id.length > 256 ||
|
|
137
|
+
sessionIds.has(row.id) ||
|
|
138
|
+
row._store !== "jsonl" ||
|
|
139
|
+
row._presence !== "present" ||
|
|
140
|
+
row._blocked !== false
|
|
141
|
+
) {
|
|
142
|
+
throw unavailable(
|
|
143
|
+
"Skill outcome session authority contains a blocked row",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
sessionIds.add(row.id);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const receipts = [];
|
|
150
|
+
const sessions = rows.map((row) => {
|
|
151
|
+
const authority = read(row.id, () =>
|
|
152
|
+
transcriptReceiptProjection(receipts, maxReceipts),
|
|
153
|
+
);
|
|
154
|
+
return Object.freeze({
|
|
155
|
+
sessionId: row.id,
|
|
156
|
+
headHash: authority.headHash,
|
|
157
|
+
eventCount: authority.eventCount,
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
const uniqueReceipts = new Map();
|
|
161
|
+
let duplicateReceiptCount = 0;
|
|
162
|
+
for (const receipt of receipts) {
|
|
163
|
+
if (uniqueReceipts.has(receipt.receiptDigest)) {
|
|
164
|
+
duplicateReceiptCount += 1;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
uniqueReceipts.set(receipt.receiptDigest, receipt);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const totals = new Map();
|
|
171
|
+
let attributionEligibleReceiptCount = 0;
|
|
172
|
+
let outcomeEligibleReceiptCount = 0;
|
|
173
|
+
for (const receipt of uniqueReceipts.values()) {
|
|
174
|
+
if (receipt.attributionEligible !== true) continue;
|
|
175
|
+
attributionEligibleReceiptCount += 1;
|
|
176
|
+
const hasOutcomeEvidence =
|
|
177
|
+
receipt.graderReceipts.length > 0 || receipt.userCorrectionRef !== null;
|
|
178
|
+
if (
|
|
179
|
+
!hasOutcomeEvidence ||
|
|
180
|
+
!["completed", "failed"].includes(receipt.executionStatus)
|
|
181
|
+
) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
outcomeEligibleReceiptCount += 1;
|
|
185
|
+
const digest = receipt.selectedSkillDigests[0];
|
|
186
|
+
const prior = totals.get(digest) || {
|
|
187
|
+
samples: 0,
|
|
188
|
+
successes: 0,
|
|
189
|
+
corrections: 0,
|
|
190
|
+
};
|
|
191
|
+
prior.samples += 1;
|
|
192
|
+
if (receipt.executionStatus === "completed") prior.successes += 1;
|
|
193
|
+
if (receipt.userCorrectionRef !== null) prior.corrections += 1;
|
|
194
|
+
totals.set(digest, prior);
|
|
195
|
+
}
|
|
196
|
+
const metrics = Object.fromEntries(
|
|
197
|
+
[...totals.entries()]
|
|
198
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
199
|
+
.map(([digest, value]) => [
|
|
200
|
+
digest,
|
|
201
|
+
Object.freeze({
|
|
202
|
+
samples: value.samples,
|
|
203
|
+
successRate: value.successes / value.samples,
|
|
204
|
+
correctionRate: value.corrections / value.samples,
|
|
205
|
+
}),
|
|
206
|
+
]),
|
|
207
|
+
);
|
|
208
|
+
const source = sessions
|
|
209
|
+
.map(({ sessionId, headHash, eventCount }) => ({
|
|
210
|
+
sessionId,
|
|
211
|
+
headHash,
|
|
212
|
+
eventCount,
|
|
213
|
+
}))
|
|
214
|
+
.sort((left, right) => left.sessionId.localeCompare(right.sessionId));
|
|
215
|
+
const sourceDigest = `sha256:${createHash("sha256")
|
|
216
|
+
.update(`${SKILL_OUTCOME_AUTHORITY_SCHEMA}\0${canonicalJson(source)}`)
|
|
217
|
+
.digest("hex")}`;
|
|
218
|
+
return Object.freeze({
|
|
219
|
+
schema: SKILL_OUTCOME_AUTHORITY_SCHEMA,
|
|
220
|
+
status: "verified",
|
|
221
|
+
metrics: Object.freeze(metrics),
|
|
222
|
+
evidence: Object.freeze({
|
|
223
|
+
schema: SKILL_OUTCOME_AUTHORITY_SCHEMA,
|
|
224
|
+
status: "verified",
|
|
225
|
+
sourceDigest,
|
|
226
|
+
selectedSessionCount: sessions.length,
|
|
227
|
+
receiptCount: receipts.length,
|
|
228
|
+
uniqueReceiptCount: uniqueReceipts.size,
|
|
229
|
+
attributionEligibleReceiptCount,
|
|
230
|
+
outcomeEligibleReceiptCount,
|
|
231
|
+
duplicateReceiptCount,
|
|
232
|
+
maxSessions,
|
|
233
|
+
maxReceipts,
|
|
234
|
+
}),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function unavailableSkillOutcomeTranscriptAuthority(error) {
|
|
239
|
+
return Object.freeze({
|
|
240
|
+
schema: SKILL_OUTCOME_AUTHORITY_SCHEMA,
|
|
241
|
+
status: "unavailable",
|
|
242
|
+
metrics: null,
|
|
243
|
+
evidence: Object.freeze({
|
|
244
|
+
schema: SKILL_OUTCOME_AUTHORITY_SCHEMA,
|
|
245
|
+
status: "unavailable",
|
|
246
|
+
code:
|
|
247
|
+
typeof error?.code === "string" && error.code.startsWith("CC_SKILL_")
|
|
248
|
+
? error.code
|
|
249
|
+
: "CC_SKILL_OUTCOME_AUTHORITY_UNAVAILABLE",
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { performance } from "node:perf_hooks";
|
|
3
|
+
|
|
4
|
+
import { routeSkillDescriptors } from "./skill-retrieval-router.js";
|
|
5
|
+
|
|
6
|
+
export const SKILL_RETRIEVAL_BENCHMARK_SCHEMA =
|
|
7
|
+
"chainlesschain.skill-retrieval-benchmark/v1";
|
|
8
|
+
|
|
9
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
10
|
+
|
|
11
|
+
function canonical(value) {
|
|
12
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
13
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
14
|
+
return `{${Object.keys(value)
|
|
15
|
+
.sort()
|
|
16
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
17
|
+
.join(",")}}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function hash(value) {
|
|
21
|
+
return `sha256:${createHash("sha256")
|
|
22
|
+
.update(SKILL_RETRIEVAL_BENCHMARK_SCHEMA)
|
|
23
|
+
.update("\0")
|
|
24
|
+
.update(canonical(value))
|
|
25
|
+
.digest("hex")}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function finiteRatio(value, name) {
|
|
29
|
+
const number = Number(value);
|
|
30
|
+
if (!Number.isFinite(number) || number < 0 || number > 1)
|
|
31
|
+
throw new TypeError(`${name} must be between zero and one`);
|
|
32
|
+
return number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeThresholds(input) {
|
|
36
|
+
const recallAt5 = finiteRatio(input?.recallAt5, "recallAt5");
|
|
37
|
+
const falseInvocationRate = finiteRatio(
|
|
38
|
+
input?.falseInvocationRate,
|
|
39
|
+
"falseInvocationRate",
|
|
40
|
+
);
|
|
41
|
+
const p95Ms = Number(input?.p95Ms);
|
|
42
|
+
if (!Number.isFinite(p95Ms) || p95Ms <= 0)
|
|
43
|
+
throw new TypeError("p95Ms must be positive");
|
|
44
|
+
return Object.freeze({ recallAt5, falseInvocationRate, p95Ms });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function runSkillRetrievalBenchmark({
|
|
48
|
+
skills,
|
|
49
|
+
cases,
|
|
50
|
+
thresholds,
|
|
51
|
+
clock = () => performance.now(),
|
|
52
|
+
} = {}) {
|
|
53
|
+
if (
|
|
54
|
+
!Array.isArray(skills) ||
|
|
55
|
+
skills.length < 2 ||
|
|
56
|
+
skills.length > 10_000 ||
|
|
57
|
+
!Array.isArray(cases) ||
|
|
58
|
+
cases.length < 1 ||
|
|
59
|
+
cases.length > 10_000 ||
|
|
60
|
+
typeof clock !== "function"
|
|
61
|
+
)
|
|
62
|
+
throw new TypeError("Skill retrieval benchmark input is invalid");
|
|
63
|
+
const gate = normalizeThresholds(thresholds);
|
|
64
|
+
const corpusDigests = new Set(
|
|
65
|
+
skills.map((skill) => skill.executionIdentity?.contentDigest),
|
|
66
|
+
);
|
|
67
|
+
const normalizedCases = cases.map((item, index) => {
|
|
68
|
+
if (
|
|
69
|
+
typeof item?.query !== "string" ||
|
|
70
|
+
item.query.trim() === "" ||
|
|
71
|
+
!DIGEST.test(item?.expectedDigest ?? "")
|
|
72
|
+
)
|
|
73
|
+
throw new TypeError(`benchmark case ${index} is invalid`);
|
|
74
|
+
if (!corpusDigests.has(item.expectedDigest))
|
|
75
|
+
throw new TypeError(`benchmark case ${index} is absent from the corpus`);
|
|
76
|
+
return { query: item.query, expectedDigest: item.expectedDigest };
|
|
77
|
+
});
|
|
78
|
+
const plan = Object.freeze({
|
|
79
|
+
skillCorpusDigest: hash(
|
|
80
|
+
skills.map((skill) => ({
|
|
81
|
+
id: skill.id,
|
|
82
|
+
digest: skill.executionIdentity?.contentDigest ?? null,
|
|
83
|
+
description: skill.description ?? "",
|
|
84
|
+
})),
|
|
85
|
+
),
|
|
86
|
+
caseCorpusDigest: hash(normalizedCases),
|
|
87
|
+
caseCount: normalizedCases.length,
|
|
88
|
+
thresholds: gate,
|
|
89
|
+
});
|
|
90
|
+
const latencies = [];
|
|
91
|
+
let recalled = 0;
|
|
92
|
+
let falseInvocations = 0;
|
|
93
|
+
let abstentions = 0;
|
|
94
|
+
for (const item of normalizedCases) {
|
|
95
|
+
const startedAt = Number(clock());
|
|
96
|
+
const result = routeSkillDescriptors({
|
|
97
|
+
skills,
|
|
98
|
+
query: item.query,
|
|
99
|
+
topK: 5,
|
|
100
|
+
ambiguityMargin: 0,
|
|
101
|
+
});
|
|
102
|
+
const endedAt = Number(clock());
|
|
103
|
+
if (
|
|
104
|
+
!Number.isFinite(startedAt) ||
|
|
105
|
+
!Number.isFinite(endedAt) ||
|
|
106
|
+
endedAt < startedAt
|
|
107
|
+
)
|
|
108
|
+
throw new Error("Skill retrieval benchmark clock is invalid");
|
|
109
|
+
latencies.push(endedAt - startedAt);
|
|
110
|
+
if (result.candidates.some(({ digest }) => digest === item.expectedDigest))
|
|
111
|
+
recalled += 1;
|
|
112
|
+
if (result.selected === null) abstentions += 1;
|
|
113
|
+
else if (result.selected.digest !== item.expectedDigest)
|
|
114
|
+
falseInvocations += 1;
|
|
115
|
+
}
|
|
116
|
+
latencies.sort((a, b) => a - b);
|
|
117
|
+
const recallAt5 = recalled / normalizedCases.length;
|
|
118
|
+
const falseInvocationRate = falseInvocations / normalizedCases.length;
|
|
119
|
+
const p95Ms = latencies[Math.max(0, Math.ceil(latencies.length * 0.95) - 1)];
|
|
120
|
+
const core = {
|
|
121
|
+
schema: SKILL_RETRIEVAL_BENCHMARK_SCHEMA,
|
|
122
|
+
plan,
|
|
123
|
+
metrics: {
|
|
124
|
+
recallAt5,
|
|
125
|
+
falseInvocationRate,
|
|
126
|
+
p95Ms,
|
|
127
|
+
abstentionRate: abstentions / normalizedCases.length,
|
|
128
|
+
},
|
|
129
|
+
passed:
|
|
130
|
+
recallAt5 >= gate.recallAt5 &&
|
|
131
|
+
falseInvocationRate < gate.falseInvocationRate &&
|
|
132
|
+
p95Ms < gate.p95Ms,
|
|
133
|
+
};
|
|
134
|
+
return Object.freeze({ ...core, reportDigest: hash(core) });
|
|
135
|
+
}
|