chainlesschain 0.166.21 → 0.166.24
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/README.md +67 -9
- package/package.json +4 -3
- package/src/assets/web-panel/assets/{AIOps-BjMnsUci.js → AIOps-DR-MWcZc.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DdYFP03A.js → ActionButton-DT8B7sEb.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Bb8TuuK_.js → Analytics-asjh3dQJ.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Kn3TIOtk.js → AppLayout-DivQ491i.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-4IxpqI_b.js → Artifacts-DPH2uUmy.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BOV2caqU.js → Audit-Bp2nLyc-.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-B86k-ay4.js → BackgroundAgents-CHS28khl.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-C5_ie1e3.js → Backup-CKeaFSfz.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-xpwg6QCW.js → BaseInput-CxwM9BAH.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CVZOcZau.js → Chat-DYLDwaCv.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-D8fPYhUu.js → ChatBubbleRenderer-DdBJDBP0.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-MKTq3zdP.js → Checkbox-uYTWOB8j.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-JUk3wzep.js → Codegen-CvYa_dwT.js} +1 -1
- package/src/assets/web-panel/assets/{Col-JPvTA0kC.js → Col-CanMAX4m.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Tqgl87NQ.js → Community-B4WaDtHw.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BuAFYBmN.js → Compact-K93Uof_3.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CXS9WIPZ.js → Compliance-CKeDLgUW.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Ds2bFHrr.js → Cowork-P93grAeB.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-C_dV_OeW.js → Cron-BSHnMtDn.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BsO6tIRo.js → Crosschain-epAOpUVJ.js} +1 -1
- package/src/assets/web-panel/assets/{DID-rNOFqBac.js → DID-ByjXfP7t.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-C2fcKKVY.js → Dashboard-QztTU8tb.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Y7Ndr0X_.js → Dropdown-DhUc9yhN.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DcP_uPmL.js → EmailListRenderer-C2sLhJJN.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Cwn3gDzk.js → FamilyGuardDashboard-CdfbWNDn.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-ClQuOsqb.js → Federation-CcF_R7NW.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DfwtmlcK.js → FormItemContext-Cm_X2IBk.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-zNZhtbC5.js → GenericCardRenderer-DUi4NWlb.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BZmdW-G5.js → Git-4Sq5FjBt.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CqBk4lEn.js → Governance-Dx2_v4V6.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Dbmt3ZXk.js → Inference-7Vr1xekR.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-hMTH6qf3.js → KnowledgeGraph-Cnd2XOzf.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CkiYgiW2.js → Logs-B66QPVf-.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BL1FElXg.js → MarkdownRenderer-PLsEvhly.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CbB6wfin.js → Marketplace-BMIK9BmC.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BSwiFtte.js → McpTools-BDbyp3J_.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-B03PeHrz.js → Memory-CJdzfZGi.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CRGrnd-X.js → MobileBridge-C2TH5Y3-.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CE_5v2kO.js → MobileProjects-D1dYXkvV.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Dp11QVx1.js → Mtc-B-4A1I1j.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CYu-3JBu.js → MtcAudit-Bgcc9UOl.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CGyJ0Xl3.js → Multisig-DqOe-etP.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CoWi_ov1.js → NLProgramming-7VnhzE_6.js} +1 -1
- package/src/assets/web-panel/assets/Notes-BxawpeUQ.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-DX4I2b4W.js → NotificationSettings-Cr08G2aE.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Ce8bEGlK.js +1 -0
- package/src/assets/web-panel/assets/{Organization-oopLO_tk.js → Organization-BC7lveGv.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BFVvjMyf.js → Overflow-CakOW-G0.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CBy5t-Tk.js → P2P-Cf8CaOBZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser--YWJNsu6.js → PdhVaultBrowser-Dc7b98W9.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C2dZ8scb.js → Permissions-DGJyMEfS.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Bs3l7Hlx.js → PersonalDataHub-DNIwSdwu.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-DEBWbZuD.js → Pipeline-5B1S12wa.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CjHBb6NU.js → Privacy-CMB6Ke5t.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-D2WipUz5.js → ProjectInit-D5PqTFiT.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B6WfnrGB.js → ProjectSettings-CbKNdSjV.js} +2 -2
- package/src/assets/web-panel/assets/Projects-ccXaHzYL.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CCv5M_Dv.js → Providers-CJF5_-Gs.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CGthxU54.js → QrScannerModal-CT6iEAdi.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CnPmXPFb.js → QuickAsk-Ci0h9mJ_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Df_tGEa9.js → Recommend-Da5mobZu.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Z58N0Loe.js → RemoteSession-BaCY8eey.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CZTBQ2Vt.js → Reputation-CaITfTsI.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CdK3YpCQ.js → Row-DtUDamyP.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CFMVT5sb.js → RssFeed-DX27gFpg.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DrF8RIvD.js → Search-DFL69osN.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Ddk2f2DM.js → Security-BqGeoWv-.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CCuK-VOo.js → Services-3z1WnEAc.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DxCpHzeM.js → Skeleton-C_OJQQ9Z.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-t2oTDgcv.js → Skills-BY7aT6Mo.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Df63M9_R.js → Sla-BZv7DSaD.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-6lJKLhCn.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-COd_tgPp.js → SyncSettings-B6D7STlI.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CzDCcrik.js → Tasks-Co_FCZAO.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D-vfxTGA.js → Templates-CnY-9fgz.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BlpT_Gxc.js → Tenant-B71yXfZ8.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D5rq52Hg.js → Terminal-Dd_P7awo.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DdoMndkK.js → TimelineRenderer-CvIEMyli.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BhgBsI6g.js → Tokens-DknFBGOi.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DwwzoikZ.js → Trigger-D_4nJONB.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-HkTpzXFb.js → Trust-BNl21fa7.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-D9nk6Ehe.js → UkeySign-CFrCI7uK.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BKk0rfoy.js → VideoEditing-BVfY6JLg.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-IVWIU_Lq.js → Wallet-Cj9CAK0J.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CFTCpfsG.js → WebAuthn-DcqZlzA3.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Dnf4Obif.js → WorkflowEditor-Dfr_dMld.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D2snERdj.js → chat-Yv6UF0AD.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DKEjK1N1.js → colors-CDW_-1fs.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BEDLwQdt.js → compact-item-BYOQvd-6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DA9iW1a0.js → createContext-BCGO0BiP.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-H-kXSuf-.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-5l2xEcY9.js → hasIn-DY-70cfQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7_W_rYd.js → index-366wfQBU.js} +1 -1
- package/src/assets/web-panel/assets/index-B0o4MeNK.js +1 -0
- package/src/assets/web-panel/assets/{index-CxEtQYdi.js → index-B9ZogJJM.js} +1 -1
- package/src/assets/web-panel/assets/{index-B00GeekA.js → index-B9m5QAMg.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7sKbM5s.js → index-BBs2mv5M.js} +1 -1
- package/src/assets/web-panel/assets/{index-CX1x4AFn.js → index-BFv1hzF6.js} +1 -1
- package/src/assets/web-panel/assets/index-BVafOL_I.js +1 -0
- package/src/assets/web-panel/assets/{index-DU2TXJu-.js → index-BXlEx4UH.js} +1 -1
- package/src/assets/web-panel/assets/{index-e-e40id6.js → index-BayRTE5w.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXet1xol.js → index-Bb9nyts1.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7z4zB_a.js → index-Bf_Va0S-.js} +1 -1
- package/src/assets/web-panel/assets/{index-fccZmC_h.js → index-Br3wQLVY.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqc8tdIF.js → index-BvK4fjkk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BO9dQjpt.js → index-C40UdtlS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Csfb-7hw.js → index-C4UJA2ju.js} +1 -1
- package/src/assets/web-panel/assets/{index-Td8ZwyoC.js → index-CB_Iw73G.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZ5lY2zx.js → index-CCwWp3mT.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpqtbXdE.js → index-CFa2fPCk.js} +1 -1
- package/src/assets/web-panel/assets/{index-NJieh3T1.js → index-CIyHxV4u.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbkghqn_.js → index-CUP-A2_h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqwPFbOb.js → index-CUo27q9J.js} +3 -3
- package/src/assets/web-panel/assets/{index-B4QYBliR.js → index-CaT8trvf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgfImyZI.js → index-CnZNbcux.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbd7eEex.js → index-Cy2NE6AO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbTPvp2_.js → index-CzeEEazr.js} +1 -1
- package/src/assets/web-panel/assets/{index-5pW4t1iD.js → index-D--TEyDj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dg2a9owQ.js → index-DCtsjhhT.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_eCoZgW.js → index-DLOf7BSz.js} +1 -1
- package/src/assets/web-panel/assets/{index-7P1b8HZo.js → index-DM5c4pc-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRPrHE7h.js → index-DRFC2Qt0.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bq5P3piS.js → index-DT_qVaaV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjWltbi_.js → index-DUDoRk9r.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkMKuqUs.js → index-Dg-AQYDf.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLoalqRX.js → index-DuIPq5MX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGlotREA.js → index-NYVBUAVN.js} +1 -1
- package/src/assets/web-panel/assets/{index-yYEQXYaU.js → index-NaCESahy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmruhzFi.js → index-RjIMPG0u.js} +1 -1
- package/src/assets/web-panel/assets/{index-fgYk0QXO.js → index-Y9akzgFO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvV03Ayk.js → index-hZ0Eyrrw.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CPrcB1TC.js → initDefaultProps-CG99CcR4.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BQ7mWRh_.js → motion-Z7MH0_0G.js} +1 -1
- package/src/assets/web-panel/assets/{move-CzOEq99p.js → move-BX67lOdq.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BlQI5jrw.js → mtc-parser-CmAbG1fE.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DlW4gxmv.js → omit-DiU5tI1_.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BBYms5nP.js → pickAttrs-BGfvLrYL.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-az2MPJ_7.js → placementArrow-CggLEgaJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D1-ibEol.js → responsiveObserve-t3nlghPZ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DHGqa4GA.js → slide-BkV4dL9s.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CYGDo6lD.js → statusUtils-qec1PUoC.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Cl2EM9K6.js → styleChecker-ChjX6T8D.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DdYhzuv1.js → useFlexGapSupport-B1jLoZcM.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DWumPuBW.js → useFs-C3X53s4E.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DxAO-Aqi.js → usePersonalDataHub-DOvbbnkZ.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CplsQf_N.js → vnode-Ie0TEVFT.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Cw5HXNSG.js → zoom-CRUMVS8l.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +18 -1
- package/src/commands/evolution-benchmark.js +72 -0
- package/src/commands/evolution.js +2 -0
- package/src/commands/governed-skill-marketplace.js +142 -0
- package/src/commands/marketplace.js +4 -1
- package/src/commands/serve.js +41 -0
- package/src/commands/skill.js +3 -0
- package/src/data/changelog.json +39 -0
- package/src/gateways/ws/ws-agent-handler.js +59 -2
- package/src/gateways/ws/ws-server.js +2 -0
- package/src/harness/golden-transcript.js +1 -0
- package/src/harness/prompt-compressor.js +51 -5
- package/src/harness/provider-backed-compaction.js +28 -1
- package/src/harness/remote-session-registry.js +15 -3
- package/src/index.js +30 -4
- package/src/lazy-dispatch.js +15 -1
- package/src/lib/advisor-runtime.js +55 -2
- package/src/lib/app-server/cli-agent-kernel-adapter.js +4 -0
- package/src/lib/app-server/graph-runtime.js +32 -0
- package/src/lib/app-server/server.js +45 -1
- package/src/lib/app-server/websocket-transport.js +23 -0
- package/src/lib/autonomous-agent.js +63 -13
- package/src/lib/cowork/ab-comparator-cli.js +4 -3
- package/src/lib/cowork/debate-review-cli.js +4 -3
- package/src/lib/cowork/decision-kb-cli.js +5 -0
- package/src/lib/cowork-adapter.js +38 -16
- package/src/lib/evolution/agent-evolution-ingress.js +95 -15
- package/src/lib/evolution/agent-evolution-runtime-composition.js +82 -0
- package/src/lib/evolution/agent-evolution-session-lifecycle.js +46 -0
- package/src/lib/evolution/agent-model-projection.js +217 -0
- package/src/lib/evolution/bounded-descriptor-read.js +29 -0
- package/src/lib/evolution/controlled-skill-pilot-ledger-adapter.js +551 -0
- package/src/lib/evolution/controlled-skill-production-pilot.js +308 -18
- package/src/lib/evolution/evidence-backed-wiki-maintainer.js +10 -1
- package/src/lib/evolution/evidence-json-text.js +236 -0
- package/src/lib/evolution/evolution-artifact-ports.js +202 -21
- package/src/lib/evolution/evolution-deployment-loader.js +369 -0
- package/src/lib/evolution/evolution-eval-child-evidence-ledger-adapter.js +373 -0
- package/src/lib/evolution/evolution-eval-gate.js +14 -1
- package/src/lib/evolution/evolution-eval-process-supervisor-worker.mjs +14 -0
- package/src/lib/evolution/evolution-eval-process-supervisor.js +607 -0
- package/src/lib/evolution/evolution-evidence-artifact-adapter.js +14 -1
- package/src/lib/evolution/evolution-evidence-projector.js +240 -37
- package/src/lib/evolution/evolution-file-witness.js +153 -30
- package/src/lib/evolution/evolution-ledger-ports.js +1027 -66
- package/src/lib/evolution/evolution-ledger.js +66 -2
- package/src/lib/evolution/evolution-raw-crypto-shred.js +29 -15
- package/src/lib/evolution/evolution-raw-deletion-ledger-adapter.js +865 -0
- package/src/lib/evolution/evolution-release-train-domain-stages.js +769 -0
- package/src/lib/evolution/evolution-release-train-ledger-adapter.js +335 -0
- package/src/lib/evolution/evolution-release-train-stage-output-ledger-adapter.js +333 -0
- package/src/lib/evolution/evolution-release-train.js +586 -0
- package/src/lib/evolution/evolution-workbench-batch-executor.js +101 -144
- package/src/lib/evolution/evolution-workbench-control-ports.js +203 -0
- package/src/lib/evolution/evolution-workbench-file-resources.js +403 -0
- package/src/lib/evolution/evolution-workbench-projection.js +152 -25
- package/src/lib/evolution/evolution-workbench-registry-source.js +482 -0
- package/src/lib/evolution/evolution-workbench-review-ledger-adapter.js +823 -0
- package/src/lib/evolution/evolution-workbench-review-protocol.js +157 -0
- package/src/lib/evolution/evolution-workbench-rollback-authorization.js +57 -0
- package/src/lib/evolution/evolution-workbench-rollback-ledger-adapter.js +1016 -0
- package/src/lib/evolution/evolution-workbench-runtime.js +133 -0
- package/src/lib/evolution/evolution-workbench-version-control.js +70 -36
- package/src/lib/evolution/evolvable-artifact-ledger-adapter.js +736 -0
- package/src/lib/evolution/governed-knowledge-artifact-lifecycle.js +364 -0
- package/src/lib/evolution/governed-knowledge-candidate-rejection.js +343 -0
- package/src/lib/evolution/governed-knowledge-dependency-authority.js +227 -44
- package/src/lib/evolution/governed-knowledge-dependency-ledger-executor.js +95 -83
- package/src/lib/evolution/governed-knowledge-merge-ledger-executor.js +29 -2
- package/src/lib/evolution/governed-knowledge-merge-publisher-authority.js +31 -3
- package/src/lib/evolution/governed-knowledge-record.js +148 -0
- package/src/lib/evolution/governed-knowledge-revocation-record.js +135 -0
- package/src/lib/evolution/governed-knowledge-skill-rollback.js +475 -0
- package/src/lib/evolution/governed-knowledge-sync-ledger-adapter.js +92 -6
- package/src/lib/evolution/governed-knowledge-sync-merge-publisher.js +57 -4
- package/src/lib/evolution/governed-knowledge-sync.js +332 -99
- package/src/lib/evolution/governed-knowledge-wiki-tombstone.js +462 -0
- package/src/lib/evolution/governed-skill-marketplace-badge.js +208 -0
- package/src/lib/evolution/governed-skill-marketplace-candidate.js +330 -0
- package/src/lib/evolution/governed-skill-marketplace-cli-host.js +308 -0
- package/src/lib/evolution/governed-skill-marketplace-ledger-adapter.js +420 -0
- package/src/lib/evolution/governed-skill-marketplace.js +288 -5
- package/src/lib/evolution/governed-wiki-pruning-journal.js +302 -0
- package/src/lib/evolution/governed-wiki-pruning-ledger-adapter.js +459 -0
- package/src/lib/evolution/governed-wiki-pruning-maintenance.js +576 -0
- package/src/lib/evolution/governed-wiki-pruning-plan-authority.js +169 -0
- package/src/lib/evolution/governed-wiki-pruning-raw-shred.js +207 -0
- package/src/lib/evolution/governed-wiki-pruning-retrieval.js +587 -0
- package/src/lib/evolution/governed-wiki-pruning-runtime.js +153 -0
- package/src/lib/evolution/governed-wiki-pruning-skill-rollback.js +360 -0
- package/src/lib/evolution/governed-wiki-pruning.js +322 -143
- package/src/lib/evolution/independent-skill-revocation-source.js +231 -0
- package/src/lib/evolution/knowledge-wiki-source-admission.js +124 -0
- package/src/lib/evolution/knowledge-wiki-source-provenance.js +359 -0
- package/src/lib/evolution/progressive-canary-external-watchdog.js +578 -0
- package/src/lib/evolution/progressive-canary-traffic-worker.js +628 -0
- package/src/lib/evolution/progressive-canary-watchdog-file-store.js +285 -0
- package/src/lib/evolution/progressive-canary-watchdog-node-pki.js +265 -0
- package/src/lib/evolution/skill-candidate-registry.js +22 -0
- package/src/lib/evolution/skill-promotion-controller.js +25 -0
- package/src/lib/evolution/skill-promotion-review-ledger-adapter.js +100 -0
- package/src/lib/evolution/skill-registry-transition-ledger-adapter.js +131 -2
- package/src/lib/evolution/skill-release-registry.js +25 -4
- package/src/lib/evolution/skill-retrieval-revocation-authority.js +361 -0
- package/src/lib/evolution/skill-retrieval-revocation-ledger-adapter.js +346 -0
- package/src/lib/evolution/skill-revocation-propagation.js +467 -0
- package/src/lib/evolution/skill-target-matrix-eval.js +162 -11
- package/src/lib/evolution/skill-wiki-reconciliation.js +985 -0
- package/src/lib/evolution/skill-writer-inventory-manifest.js +15 -12
- package/src/lib/evolution/statistical-progressive-canary.js +845 -0
- package/src/lib/evolution/structured-memory-agent-control-plane.js +120 -0
- package/src/lib/evolution/structured-memory-authority-ledger-adapter.js +5 -1
- package/src/lib/evolution/structured-memory-promotion-receipt-writer.js +126 -0
- package/src/lib/evolution/wiki-informed-skill-proposer.js +127 -21
- package/src/lib/evolution/wiki-maintainer-ledger-adapter.js +760 -100
- package/src/lib/evolution/wiki-revision-protocol.js +120 -0
- package/src/lib/evolution/wiki-skill-proposal-ledger-adapter.js +307 -0
- package/src/lib/evolution/wiki-target-tombstone-revision.js +101 -0
- package/src/lib/evolution/wikiskill-benchmark-cli-host.js +178 -0
- package/src/lib/evolution/wikiskill-benchmark-execution-host.js +702 -0
- package/src/lib/evolution/wikiskill-benchmark-ledger-adapter.js +613 -0
- package/src/lib/evolution/wikiskill-benchmark.js +574 -0
- package/src/lib/goal-assess.js +17 -10
- package/src/lib/interactive-planner.js +9 -1
- package/src/lib/iteration-budget.js +16 -2
- package/src/lib/micro-compact.js +4 -1
- package/src/lib/model-failure-policy.js +21 -0
- package/src/lib/process-execution-broker/index.js +1 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +33 -15
- package/src/lib/read-file-page.js +191 -0
- package/src/lib/runnable-provider.js +2 -1
- package/src/lib/session-host-lease.js +11 -16
- package/src/lib/skill-retrieval-router.js +22 -1
- package/src/repl/agent-repl.js +127 -33
- package/src/runtime/agent-core.js +224 -80
- package/src/runtime/agent-runtime.js +43 -0
- package/src/runtime/coding-agent-contract-shared.cjs +7 -1
- package/src/runtime/fallback-model.js +143 -62
- package/src/runtime/headless-runner.js +54 -10
- package/src/runtime/headless-stream.js +53 -6
- package/src/runtime/runtime-factory.js +41 -2
- package/src/assets/web-panel/assets/Notes-CgU9DDo9.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-CwHc15Zs.js +0 -1
- package/src/assets/web-panel/assets/Projects-FF_thRi6.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-l7ox6KuX.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DyhgpXPf.js +0 -1
- package/src/assets/web-panel/assets/index-Ck1jhFE0.js +0 -1
- package/src/assets/web-panel/assets/index-c8jJEHVs.js +0 -1
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { types } from "node:util";
|
|
3
|
+
import {
|
|
4
|
+
EvolutionLedger,
|
|
5
|
+
EVOLUTION_LEDGER_MAX_EVENTS,
|
|
6
|
+
EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA,
|
|
7
|
+
EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA,
|
|
8
|
+
} from "./evolution-ledger.js";
|
|
9
|
+
import {
|
|
10
|
+
EvolutionArtifactPorts,
|
|
11
|
+
EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA,
|
|
12
|
+
isEvolutionLedgerArtifactResolver,
|
|
13
|
+
} from "./evolution-artifact-ports.js";
|
|
14
|
+
import { captureSkillReleaseRegistryReader } from "./skill-release-registry.js";
|
|
15
|
+
import { captureSkillReleaseOperationReader } from "./evolution-ledger-ports.js";
|
|
16
|
+
import { captureSkillRollbackProvider } from "./skill-promotion-controller.js";
|
|
17
|
+
import {
|
|
18
|
+
verifySkillMutationRequest,
|
|
19
|
+
digestSkillMutationTransitionSubject,
|
|
20
|
+
} from "./skill-mutation-authority.js";
|
|
21
|
+
import { verifySkillPromotionReviewDecision } from "./skill-promotion-review.js";
|
|
22
|
+
import { captureWorkbenchProjectionReader } from "./evolution-workbench-review-ledger-adapter.js";
|
|
23
|
+
import {
|
|
24
|
+
EvolutionWorkbenchRollbackExecutor,
|
|
25
|
+
verifyEvolutionWorkbenchRollbackPlan,
|
|
26
|
+
buildEvolutionWorkbenchRollbackPlan,
|
|
27
|
+
buildEvolutionWorkbenchRollbackRequest,
|
|
28
|
+
buildEvolutionWorkbenchRollbackReceipt,
|
|
29
|
+
} from "./evolution-workbench-version-control.js";
|
|
30
|
+
import {
|
|
31
|
+
verifyWorkbenchRollbackAuthorization,
|
|
32
|
+
WORKBENCH_ROLLBACK_POLICY_SCHEMA,
|
|
33
|
+
} from "./evolution-workbench-rollback-authorization.js";
|
|
34
|
+
import {
|
|
35
|
+
capturePruningData as capture,
|
|
36
|
+
pruningCanonical as canonical,
|
|
37
|
+
} from "./governed-wiki-pruning-journal.js";
|
|
38
|
+
|
|
39
|
+
export const WORKBENCH_ROLLBACK_PREPARATION_SCHEMA =
|
|
40
|
+
"chainlesschain.evolution-workbench-rollback-preparation/v1";
|
|
41
|
+
export const WORKBENCH_ROLLBACK_SETTLEMENT_SCHEMA =
|
|
42
|
+
"chainlesschain.evolution-workbench-rollback-settlement/v1";
|
|
43
|
+
const TYPES = {
|
|
44
|
+
prepared: [
|
|
45
|
+
"evolution-workbench-rollback-preparation",
|
|
46
|
+
"evolution.workbench.rollback.prepared",
|
|
47
|
+
WORKBENCH_ROLLBACK_PREPARATION_SCHEMA,
|
|
48
|
+
],
|
|
49
|
+
committed: [
|
|
50
|
+
"evolution-workbench-rollback-settlement",
|
|
51
|
+
"evolution.workbench.rollback.committed",
|
|
52
|
+
WORKBENCH_ROLLBACK_SETTLEMENT_SCHEMA,
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
56
|
+
// Only this adapter can mint a mutation context, after it authenticated the
|
|
57
|
+
// durable human preparation and exact current active/LKG state. The token is
|
|
58
|
+
// invisible in the existing wire shape and cannot be reconstructed from JSON.
|
|
59
|
+
const MUTATION_CONTEXTS = new WeakMap();
|
|
60
|
+
export function consumeWorkbenchRollbackMutationContext(
|
|
61
|
+
value,
|
|
62
|
+
registry,
|
|
63
|
+
ledger,
|
|
64
|
+
descriptor,
|
|
65
|
+
) {
|
|
66
|
+
const context = MUTATION_CONTEXTS.get(value);
|
|
67
|
+
if (
|
|
68
|
+
!context ||
|
|
69
|
+
context.registry !== registry ||
|
|
70
|
+
context.ledger !== ledger ||
|
|
71
|
+
canonical(context.descriptor) !== canonical(descriptor)
|
|
72
|
+
)
|
|
73
|
+
throw new TypeError(
|
|
74
|
+
"a live same-store, same-scope Workbench rollback mutation context is required",
|
|
75
|
+
);
|
|
76
|
+
MUTATION_CONTEXTS.delete(value);
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
const same = (a, b) => canonical(a) === canonical(b);
|
|
80
|
+
const compare = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
81
|
+
const sortedRefs = (refs) =>
|
|
82
|
+
[...refs].sort(
|
|
83
|
+
(a, b) => compare(a.ref, b.ref) || compare(a.digest, b.digest),
|
|
84
|
+
);
|
|
85
|
+
function fail(message) {
|
|
86
|
+
const error = new Error(message);
|
|
87
|
+
error.code = "CC_EVOLUTION_WORKBENCH_ROLLBACK_INVALID";
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
function fixed(owner, name) {
|
|
91
|
+
if (!owner || types.isProxy(owner))
|
|
92
|
+
throw new TypeError(`${name} fixed port is required`);
|
|
93
|
+
const method = Object.getOwnPropertyDescriptor(owner, name)?.value;
|
|
94
|
+
if (typeof method !== "function" || types.isProxy(method))
|
|
95
|
+
throw new TypeError(`${name} fixed own method is required`);
|
|
96
|
+
return method.bind(owner);
|
|
97
|
+
}
|
|
98
|
+
function bindRegistry(registry, transactionLedger, tenantId) {
|
|
99
|
+
const reader = captureSkillReleaseRegistryReader(registry);
|
|
100
|
+
if (
|
|
101
|
+
reader.tenantId !== tenantId ||
|
|
102
|
+
!reader.matchesTransactionLedger(transactionLedger)
|
|
103
|
+
)
|
|
104
|
+
throw new TypeError(
|
|
105
|
+
"Workbench rollback Registry/transaction Ledger binding differs",
|
|
106
|
+
);
|
|
107
|
+
return {
|
|
108
|
+
registry: reader,
|
|
109
|
+
operations: captureSkillReleaseOperationReader(transactionLedger),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The Workbench journal never substitutes for Registry effect evidence. Both
|
|
114
|
+
// readers must re-open real release bytes and authenticate the same Ledger.
|
|
115
|
+
export class EvolutionWorkbenchRollbackLedgerAdapter {
|
|
116
|
+
#registryIdentity;
|
|
117
|
+
#ledgerIdentity;
|
|
118
|
+
#ledger;
|
|
119
|
+
#put;
|
|
120
|
+
#resolve;
|
|
121
|
+
#projection;
|
|
122
|
+
#writer;
|
|
123
|
+
#reader;
|
|
124
|
+
#rollback;
|
|
125
|
+
#authorize;
|
|
126
|
+
#human;
|
|
127
|
+
#verifyHuman;
|
|
128
|
+
#now;
|
|
129
|
+
constructor({
|
|
130
|
+
descriptor,
|
|
131
|
+
artifactPorts,
|
|
132
|
+
ledger,
|
|
133
|
+
ledgerArtifactResolver,
|
|
134
|
+
projectionReader,
|
|
135
|
+
releaseRegistry,
|
|
136
|
+
transactionLedger,
|
|
137
|
+
rollbackProvider,
|
|
138
|
+
authorizationProvider,
|
|
139
|
+
verifierReleaseRegistry,
|
|
140
|
+
verifierTransactionLedger,
|
|
141
|
+
humanRollbackProvider,
|
|
142
|
+
humanRollbackVerifier,
|
|
143
|
+
now = Date.now,
|
|
144
|
+
} = {}) {
|
|
145
|
+
this.descriptor = capture(descriptor);
|
|
146
|
+
this.#projection = captureWorkbenchProjectionReader(projectionReader);
|
|
147
|
+
if (
|
|
148
|
+
!same(this.descriptor, this.#projection.descriptor) ||
|
|
149
|
+
!this.#projection.matchesLedger(ledger)
|
|
150
|
+
)
|
|
151
|
+
throw new TypeError(
|
|
152
|
+
"Workbench rollback requires the exact retained projection Ledger and scope",
|
|
153
|
+
);
|
|
154
|
+
if (
|
|
155
|
+
!(ledger instanceof EvolutionLedger) ||
|
|
156
|
+
types.isProxy(ledger) ||
|
|
157
|
+
!(artifactPorts instanceof EvolutionArtifactPorts) ||
|
|
158
|
+
types.isProxy(artifactPorts) ||
|
|
159
|
+
!isEvolutionLedgerArtifactResolver(ledgerArtifactResolver)
|
|
160
|
+
)
|
|
161
|
+
throw new TypeError(
|
|
162
|
+
"Workbench rollback requires actual Ledger/ArtifactPorts",
|
|
163
|
+
);
|
|
164
|
+
if (
|
|
165
|
+
releaseRegistry === verifierReleaseRegistry ||
|
|
166
|
+
transactionLedger === verifierTransactionLedger
|
|
167
|
+
)
|
|
168
|
+
throw new TypeError(
|
|
169
|
+
"Workbench rollback requires independent Registry/transaction readers",
|
|
170
|
+
);
|
|
171
|
+
this.#writer = bindRegistry(
|
|
172
|
+
releaseRegistry,
|
|
173
|
+
transactionLedger,
|
|
174
|
+
descriptor.tenantId,
|
|
175
|
+
);
|
|
176
|
+
this.#reader = bindRegistry(
|
|
177
|
+
verifierReleaseRegistry,
|
|
178
|
+
verifierTransactionLedger,
|
|
179
|
+
descriptor.tenantId,
|
|
180
|
+
);
|
|
181
|
+
if (
|
|
182
|
+
!this.#writer.operations.matchesLedger(ledger) ||
|
|
183
|
+
this.#reader.operations.matchesLedger(ledger)
|
|
184
|
+
)
|
|
185
|
+
throw new TypeError(
|
|
186
|
+
"Workbench release writer must share the projection Ledger, with an independent verifier",
|
|
187
|
+
);
|
|
188
|
+
this.#rollback = captureSkillRollbackProvider(
|
|
189
|
+
rollbackProvider,
|
|
190
|
+
releaseRegistry,
|
|
191
|
+
).rollback;
|
|
192
|
+
this.#authorize = fixed(authorizationProvider, "authorizeRollback");
|
|
193
|
+
this.#human = fixed(humanRollbackProvider, "authorize");
|
|
194
|
+
this.#verifyHuman = fixed(humanRollbackVerifier, "verify");
|
|
195
|
+
if (typeof now !== "function" || types.isProxy(now))
|
|
196
|
+
throw new TypeError("Workbench rollback clock is required");
|
|
197
|
+
this.#now = now;
|
|
198
|
+
this.#registryIdentity = releaseRegistry;
|
|
199
|
+
this.#ledgerIdentity = ledger;
|
|
200
|
+
this.#ledger = Object.freeze({
|
|
201
|
+
read: () =>
|
|
202
|
+
EvolutionLedger.prototype.read.call(ledger, {
|
|
203
|
+
limit: EVOLUTION_LEDGER_MAX_EVENTS,
|
|
204
|
+
}),
|
|
205
|
+
verify: EvolutionLedger.prototype.verify.bind(ledger),
|
|
206
|
+
append: EvolutionLedger.prototype.appendDomainEvent.bind(ledger),
|
|
207
|
+
});
|
|
208
|
+
this.#put =
|
|
209
|
+
EvolutionArtifactPorts.prototype.putCanonical.bind(artifactPorts);
|
|
210
|
+
this.#resolve = ledgerArtifactResolver;
|
|
211
|
+
this.#sameLedger();
|
|
212
|
+
Object.freeze(this);
|
|
213
|
+
}
|
|
214
|
+
#sameLedger() {
|
|
215
|
+
const left = this.#writer.operations.currentContext().checkpoint;
|
|
216
|
+
const right = this.#reader.operations.currentContext().checkpoint;
|
|
217
|
+
if (
|
|
218
|
+
["epoch", "ledgerId", "identityDigest", "sequence", "headDigest"].some(
|
|
219
|
+
(key) => left[key] !== right[key],
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
fail(
|
|
223
|
+
"Workbench independent release readers disagree on the current Ledger",
|
|
224
|
+
);
|
|
225
|
+
return left;
|
|
226
|
+
}
|
|
227
|
+
#stable(head) {
|
|
228
|
+
if (this.#ledger.verify().headDigest !== head.headDigest)
|
|
229
|
+
fail("Workbench rollback Ledger changed during authentication");
|
|
230
|
+
}
|
|
231
|
+
#scope(value) {
|
|
232
|
+
if (
|
|
233
|
+
["tenantId", "runId", "skillName"].some(
|
|
234
|
+
(key) => value?.[key] !== this.descriptor[key],
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
fail("Workbench rollback record scope differs");
|
|
238
|
+
return value;
|
|
239
|
+
}
|
|
240
|
+
#snapshot() {
|
|
241
|
+
const head = this.#ledger.verify();
|
|
242
|
+
const events = this.#ledger.read();
|
|
243
|
+
if (events.length !== head.sequence)
|
|
244
|
+
fail("Workbench rollback Ledger history is incomplete");
|
|
245
|
+
const selected = events.filter(
|
|
246
|
+
(event) =>
|
|
247
|
+
event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
|
|
248
|
+
Object.values(TYPES).some(([, type]) => type === event.type) &&
|
|
249
|
+
event.tenantId === this.descriptor.tenantId &&
|
|
250
|
+
event.correlationId === this.descriptor.streamId,
|
|
251
|
+
);
|
|
252
|
+
if (selected.length > 10_000)
|
|
253
|
+
fail("Workbench rollback history exceeds its budget");
|
|
254
|
+
const rows = selected.map((event) => {
|
|
255
|
+
const [kind, [type, , schema]] = Object.entries(TYPES).find(
|
|
256
|
+
([, spec]) => spec[1] === event.type,
|
|
257
|
+
);
|
|
258
|
+
const resolved = this.#resolve({
|
|
259
|
+
epoch: head.epoch,
|
|
260
|
+
ledgerId: head.ledgerId,
|
|
261
|
+
tenantId: this.descriptor.artifactTenantId,
|
|
262
|
+
ref: event.subjectRef,
|
|
263
|
+
});
|
|
264
|
+
if (
|
|
265
|
+
resolved?.schema !== EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA ||
|
|
266
|
+
resolved.authenticated !== true ||
|
|
267
|
+
resolved.found !== true ||
|
|
268
|
+
resolved.ref !== event.subjectRef.ref ||
|
|
269
|
+
resolved.digest !== event.subjectRef.digest ||
|
|
270
|
+
!Buffer.isBuffer(resolved.bytes) ||
|
|
271
|
+
resolved.bytes.length > 1024 * 1024 ||
|
|
272
|
+
`sha256:${createHash("sha256").update(resolved.bytes).digest("hex")}` !==
|
|
273
|
+
event.subjectRef.digest
|
|
274
|
+
)
|
|
275
|
+
fail("Workbench rollback artifact resolution is invalid");
|
|
276
|
+
const record = capture(JSON.parse(resolved.bytes.toString("utf8")));
|
|
277
|
+
if (
|
|
278
|
+
canonical(record) !== resolved.bytes.toString("utf8") ||
|
|
279
|
+
record.schema !== EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA ||
|
|
280
|
+
record.tenantId !== this.descriptor.artifactTenantId ||
|
|
281
|
+
record.audience !== this.descriptor.audience ||
|
|
282
|
+
record.purpose !== "evolution-ledger" ||
|
|
283
|
+
record.retention !== "ledger" ||
|
|
284
|
+
record.type !== type
|
|
285
|
+
)
|
|
286
|
+
fail("Workbench rollback artifact durable binding is invalid");
|
|
287
|
+
const value = this.#scope(record.value);
|
|
288
|
+
if (
|
|
289
|
+
value.schema !== schema ||
|
|
290
|
+
!DIGEST.test(value.planDigest ?? "") ||
|
|
291
|
+
event.eventId !== `${event.type}.${value.planDigest.slice(7)}` ||
|
|
292
|
+
event.artifactTenantId !== this.descriptor.artifactTenantId ||
|
|
293
|
+
event.skillName !== this.descriptor.skillName ||
|
|
294
|
+
event.decision !== "committed" ||
|
|
295
|
+
event.reason !== type ||
|
|
296
|
+
event.sourceRefs.length !== (kind === "prepared" ? 4 : 2)
|
|
297
|
+
)
|
|
298
|
+
fail("Workbench rollback event binding is invalid");
|
|
299
|
+
return { kind, event, value };
|
|
300
|
+
});
|
|
301
|
+
this.#stable(head);
|
|
302
|
+
return { head, events, rows };
|
|
303
|
+
}
|
|
304
|
+
#find(kind, planDigest, snapshot) {
|
|
305
|
+
const rows = snapshot.rows.filter(
|
|
306
|
+
(row) => row.kind === kind && row.value.planDigest === planDigest,
|
|
307
|
+
);
|
|
308
|
+
if (rows.length > 1) fail("Workbench rollback has duplicate records");
|
|
309
|
+
return rows[0] ?? null;
|
|
310
|
+
}
|
|
311
|
+
#append(kind, value, refs, head) {
|
|
312
|
+
this.#stable(head);
|
|
313
|
+
const [type, eventType] = TYPES[kind];
|
|
314
|
+
const sourceRefs = sortedRefs(refs);
|
|
315
|
+
const published = this.#put(type, capture(value), {
|
|
316
|
+
audience: this.descriptor.audience,
|
|
317
|
+
purpose: "evolution-ledger",
|
|
318
|
+
retention: "ledger",
|
|
319
|
+
});
|
|
320
|
+
if (
|
|
321
|
+
published?.receipt?.persisted !== true ||
|
|
322
|
+
published.receipt.readbackVerified !== true ||
|
|
323
|
+
published.receipt.integrityVerified !== true ||
|
|
324
|
+
published.receipt.retention !== "ledger"
|
|
325
|
+
)
|
|
326
|
+
fail("Workbench rollback artifact is not durable");
|
|
327
|
+
const readback = () => {
|
|
328
|
+
const result = this.#find(kind, value.planDigest, this.#snapshot());
|
|
329
|
+
if (
|
|
330
|
+
!result ||
|
|
331
|
+
!same(result.value, value) ||
|
|
332
|
+
!same(result.event.sourceRefs, sourceRefs)
|
|
333
|
+
)
|
|
334
|
+
fail("Workbench rollback append has no exact durable readback");
|
|
335
|
+
return result;
|
|
336
|
+
};
|
|
337
|
+
try {
|
|
338
|
+
const result = this.#ledger.append(
|
|
339
|
+
{
|
|
340
|
+
type: eventType,
|
|
341
|
+
eventId: `${eventType}.${value.planDigest.slice(7)}`,
|
|
342
|
+
tenantId: this.descriptor.tenantId,
|
|
343
|
+
artifactTenantId: this.descriptor.artifactTenantId,
|
|
344
|
+
correlationId: this.descriptor.streamId,
|
|
345
|
+
skillName: this.descriptor.skillName,
|
|
346
|
+
decision: "committed",
|
|
347
|
+
reason: type,
|
|
348
|
+
timestamp: new Date(Number(this.#now())).toISOString(),
|
|
349
|
+
subjectRef: published.ref,
|
|
350
|
+
sourceRefs,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
expectedHeadDigest: head.headDigest,
|
|
354
|
+
expectedSequence: head.sequence,
|
|
355
|
+
},
|
|
356
|
+
);
|
|
357
|
+
if (result?.authenticated !== true || result.durable !== true)
|
|
358
|
+
fail("Workbench rollback append is not durable");
|
|
359
|
+
} catch (cause) {
|
|
360
|
+
try {
|
|
361
|
+
return readback();
|
|
362
|
+
} catch {
|
|
363
|
+
throw cause;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return readback();
|
|
367
|
+
}
|
|
368
|
+
async #context(input) {
|
|
369
|
+
const plan = verifyEvolutionWorkbenchRollbackPlan(
|
|
370
|
+
input,
|
|
371
|
+
this.descriptor.tenantId,
|
|
372
|
+
);
|
|
373
|
+
const snapshot = this.#snapshot();
|
|
374
|
+
const retained = this.#projection.read({
|
|
375
|
+
tenantId: plan.tenantId,
|
|
376
|
+
projectionDigest: plan.sourceProjectionDigest,
|
|
377
|
+
});
|
|
378
|
+
if (
|
|
379
|
+
plan.skillName !== this.descriptor.skillName ||
|
|
380
|
+
buildEvolutionWorkbenchRollbackPlan(retained.projection, plan)
|
|
381
|
+
.planDigest !== plan.planDigest
|
|
382
|
+
)
|
|
383
|
+
fail("Workbench rollback plan differs from its retained source");
|
|
384
|
+
const fromReview = await this.#projection.readReview(plan.fromPacketDigest);
|
|
385
|
+
const toReview = await this.#projection.readReview(plan.toPacketDigest);
|
|
386
|
+
for (const [prefix, review] of [
|
|
387
|
+
["from", fromReview],
|
|
388
|
+
["to", toReview],
|
|
389
|
+
]) {
|
|
390
|
+
if (
|
|
391
|
+
review.packet.candidateId !== plan[`${prefix}CandidateId`] ||
|
|
392
|
+
review.packet.candidateContentDigest !==
|
|
393
|
+
plan[`${prefix}ContentDigest`] ||
|
|
394
|
+
review.packet.skillName !== plan.skillName ||
|
|
395
|
+
review.packetSequence >= retained.sequence
|
|
396
|
+
)
|
|
397
|
+
fail(
|
|
398
|
+
"Workbench rollback Review packet differs from the planned candidate",
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
const target = retained.projection.candidates.find(
|
|
402
|
+
(item) => item.packetDigest === plan.toPacketDigest,
|
|
403
|
+
);
|
|
404
|
+
if (
|
|
405
|
+
!toReview.decision ||
|
|
406
|
+
toReview.decision.decision !== "approved" ||
|
|
407
|
+
target.decision.receiptDigest !== toReview.decision.receiptDigest ||
|
|
408
|
+
toReview.decisionSequence >= retained.sequence
|
|
409
|
+
)
|
|
410
|
+
fail("Workbench rollback target lacks exact durable human approval");
|
|
411
|
+
this.#stable(snapshot.head);
|
|
412
|
+
return { plan, retained, fromReview, toReview, snapshot };
|
|
413
|
+
}
|
|
414
|
+
#releases(plan, basis) {
|
|
415
|
+
const output = [];
|
|
416
|
+
for (const reader of [this.#writer, this.#reader]) {
|
|
417
|
+
const from = reader.registry.readRelease(basis.fromReleaseDigest);
|
|
418
|
+
const target = reader.registry.readRelease(basis.targetReleaseDigest);
|
|
419
|
+
if (
|
|
420
|
+
!from ||
|
|
421
|
+
!target ||
|
|
422
|
+
from.releaseDigest === target.releaseDigest ||
|
|
423
|
+
from.tenantId !== plan.tenantId ||
|
|
424
|
+
target.tenantId !== plan.tenantId ||
|
|
425
|
+
from.skillName !== plan.skillName ||
|
|
426
|
+
target.skillName !== plan.skillName ||
|
|
427
|
+
from.contentDigest !== plan.fromContentDigest ||
|
|
428
|
+
target.contentDigest !== plan.toContentDigest ||
|
|
429
|
+
from.candidate.candidateId !== plan.fromCandidateId ||
|
|
430
|
+
target.candidate.candidateId !== plan.toCandidateId
|
|
431
|
+
)
|
|
432
|
+
fail("Workbench rollback releases differ from the planned candidates");
|
|
433
|
+
output.push({ from, target });
|
|
434
|
+
}
|
|
435
|
+
if (!same(output[0], output[1]))
|
|
436
|
+
fail("Workbench independent release content/lock differs");
|
|
437
|
+
return output[0];
|
|
438
|
+
}
|
|
439
|
+
#basis(plan, active, request) {
|
|
440
|
+
const targetReleaseDigest = active.state.lastKnownGoodReleaseDigest;
|
|
441
|
+
const partial = {
|
|
442
|
+
fromReleaseDigest: active.release.releaseDigest,
|
|
443
|
+
targetReleaseDigest,
|
|
444
|
+
};
|
|
445
|
+
const { target } = this.#releases(plan, partial);
|
|
446
|
+
if (active.state.stateDigest !== plan.expectedActiveStateDigest)
|
|
447
|
+
fail("Workbench rollback active state changed from the approved plan");
|
|
448
|
+
return capture({
|
|
449
|
+
...partial,
|
|
450
|
+
tenantId: plan.tenantId,
|
|
451
|
+
skillName: plan.skillName,
|
|
452
|
+
operationId: `workbench-rollback:${request.requestDigest.slice(7)}`,
|
|
453
|
+
operation: "rollback",
|
|
454
|
+
targetScope: "active",
|
|
455
|
+
expectedTargetDigest: plan.fromContentDigest,
|
|
456
|
+
expectedTargetRevision: active.state.revision,
|
|
457
|
+
expectedActiveStateDigest: active.state.stateDigest,
|
|
458
|
+
dependencyLockDigest: target.dependencyLockDigest,
|
|
459
|
+
transitionSubjectDigest: digestSkillMutationTransitionSubject({
|
|
460
|
+
tenantId: plan.tenantId,
|
|
461
|
+
skillName: plan.skillName,
|
|
462
|
+
operation: "rollback",
|
|
463
|
+
candidateId: null,
|
|
464
|
+
rollbackTargetReleaseDigest: targetReleaseDigest,
|
|
465
|
+
dependencyLockDigest: target.dependencyLockDigest,
|
|
466
|
+
expectedActiveContentDigest: plan.fromContentDigest,
|
|
467
|
+
expectedActiveRevision: active.state.revision,
|
|
468
|
+
}),
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
#active(skillName) {
|
|
472
|
+
this.#sameLedger();
|
|
473
|
+
const left = this.#writer.registry.readActive(skillName);
|
|
474
|
+
const right = this.#reader.registry.readActive(skillName);
|
|
475
|
+
if (!left || !same(left, right))
|
|
476
|
+
fail("Workbench independent active state differs");
|
|
477
|
+
return left;
|
|
478
|
+
}
|
|
479
|
+
#policy(prepared) {
|
|
480
|
+
return canonical({
|
|
481
|
+
schema: WORKBENCH_ROLLBACK_POLICY_SCHEMA,
|
|
482
|
+
tenantId: this.descriptor.tenantId,
|
|
483
|
+
planDigest: prepared.value.planDigest,
|
|
484
|
+
authorizationReceiptDigest: prepared.value.authorization.receiptDigest,
|
|
485
|
+
preparationRef: prepared.event.subjectRef,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
#proof(context, prepared, requireCurrent = false) {
|
|
489
|
+
const { plan, snapshot } = context;
|
|
490
|
+
const { basis, request } = prepared.value;
|
|
491
|
+
this.#sameLedger();
|
|
492
|
+
const results = [this.#writer, this.#reader].map(
|
|
493
|
+
(reader) =>
|
|
494
|
+
reader.operations.resolveOperation({
|
|
495
|
+
tenantId: plan.tenantId,
|
|
496
|
+
skillName: plan.skillName,
|
|
497
|
+
operationId: basis.operationId,
|
|
498
|
+
context: reader.operations.currentContext(),
|
|
499
|
+
}).result,
|
|
500
|
+
);
|
|
501
|
+
if (!same(results[0], results[1]))
|
|
502
|
+
fail("Workbench independent rollback effect differs");
|
|
503
|
+
const result = results[0];
|
|
504
|
+
if (!result) {
|
|
505
|
+
this.#stable(snapshot.head);
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
if (result.projection.status !== "committed")
|
|
509
|
+
fail(
|
|
510
|
+
"Workbench release transaction is pending; reopen Registry for recovery",
|
|
511
|
+
);
|
|
512
|
+
const { intent, previous, projection, finalizationEvidence } = result;
|
|
513
|
+
const { target } = this.#releases(plan, basis);
|
|
514
|
+
const expectedBasis = this.#basis(
|
|
515
|
+
plan,
|
|
516
|
+
{
|
|
517
|
+
state: previous,
|
|
518
|
+
release: this.#writer.registry.readRelease(
|
|
519
|
+
previous.activeReleaseDigest,
|
|
520
|
+
),
|
|
521
|
+
},
|
|
522
|
+
request,
|
|
523
|
+
);
|
|
524
|
+
if (
|
|
525
|
+
!same(expectedBasis, basis) ||
|
|
526
|
+
intent.operation !== "rollback" ||
|
|
527
|
+
intent.operationId !== basis.operationId ||
|
|
528
|
+
intent.targetReleaseDigest !== basis.targetReleaseDigest ||
|
|
529
|
+
intent.expectedParentDigest !== plan.fromContentDigest ||
|
|
530
|
+
intent.dependencyLockDigest !== target.dependencyLockDigest ||
|
|
531
|
+
result.preparationCheckpoint.sequence <= prepared.event.sequence ||
|
|
532
|
+
intent.mutationRequest.receipts.policyReceipt !==
|
|
533
|
+
this.#policy(prepared) ||
|
|
534
|
+
intent.mutationRequest.transitionSubjectDigest !==
|
|
535
|
+
basis.transitionSubjectDigest ||
|
|
536
|
+
!finalizationEvidence ||
|
|
537
|
+
finalizationEvidence.eventDigest !== projection.headDigest
|
|
538
|
+
)
|
|
539
|
+
fail(
|
|
540
|
+
"Workbench release transaction is not the exact authorized rollback",
|
|
541
|
+
);
|
|
542
|
+
const finalizations = snapshot.events.filter(
|
|
543
|
+
(event) =>
|
|
544
|
+
event.eventDigest === finalizationEvidence.eventDigest &&
|
|
545
|
+
event.type === "skill.release.finalize",
|
|
546
|
+
);
|
|
547
|
+
if (finalizations.length !== 1)
|
|
548
|
+
fail("Workbench rollback finalization is absent from this Ledger");
|
|
549
|
+
if (requireCurrent) {
|
|
550
|
+
const active = this.#active(plan.skillName);
|
|
551
|
+
if (
|
|
552
|
+
projection.current !== true ||
|
|
553
|
+
active.state.transactionId !== intent.transactionId ||
|
|
554
|
+
active.state.stateDigest !== projection.stateDigest ||
|
|
555
|
+
active.release.releaseDigest !== basis.targetReleaseDigest
|
|
556
|
+
)
|
|
557
|
+
fail(
|
|
558
|
+
"Workbench rollback effect is no longer the current active release",
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
this.#stable(snapshot.head);
|
|
562
|
+
return { result, finalizationRef: finalizations[0].subjectRef };
|
|
563
|
+
}
|
|
564
|
+
#activeAtPreparation(plan, prepared) {
|
|
565
|
+
const event = prepared.event;
|
|
566
|
+
const values = [this.#writer, this.#reader].map((reader) => {
|
|
567
|
+
const history = reader.operations.readReleaseHistory({
|
|
568
|
+
tenantId: plan.tenantId,
|
|
569
|
+
skillName: plan.skillName,
|
|
570
|
+
context: {
|
|
571
|
+
mode: "checkpoint",
|
|
572
|
+
checkpoint: {
|
|
573
|
+
epoch: event.epoch,
|
|
574
|
+
ledgerId: event.ledgerId,
|
|
575
|
+
identityDigest: event.identityDigest,
|
|
576
|
+
sequence: event.sequence,
|
|
577
|
+
headDigest: event.eventDigest,
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
});
|
|
581
|
+
const last = history.operations
|
|
582
|
+
.filter((operation) => operation.projection.status === "committed")
|
|
583
|
+
.at(-1);
|
|
584
|
+
const state = last
|
|
585
|
+
? {
|
|
586
|
+
revision: last.projection.revision,
|
|
587
|
+
stateDigest: last.projection.stateDigest,
|
|
588
|
+
activeReleaseDigest: last.intent.targetReleaseDigest,
|
|
589
|
+
lastKnownGoodReleaseDigest:
|
|
590
|
+
last.intent.operation === "rollback"
|
|
591
|
+
? last.intent.targetReleaseDigest
|
|
592
|
+
: (last.previous.activeReleaseDigest ??
|
|
593
|
+
last.intent.targetReleaseDigest),
|
|
594
|
+
}
|
|
595
|
+
: history.migration?.value.state;
|
|
596
|
+
if (!state) fail("Workbench preparation has no historical active state");
|
|
597
|
+
return {
|
|
598
|
+
state,
|
|
599
|
+
release: reader.registry.readRelease(state.activeReleaseDigest),
|
|
600
|
+
};
|
|
601
|
+
});
|
|
602
|
+
if (!same(values[0], values[1]))
|
|
603
|
+
fail("Workbench historical preparation states differ");
|
|
604
|
+
return values[0];
|
|
605
|
+
}
|
|
606
|
+
async #load(context, historicalPreparation = false) {
|
|
607
|
+
const { plan, retained, fromReview, toReview, snapshot } = context;
|
|
608
|
+
const prepared = this.#find("prepared", plan.planDigest, snapshot);
|
|
609
|
+
const committed = this.#find("committed", plan.planDigest, snapshot);
|
|
610
|
+
if (!prepared) {
|
|
611
|
+
if (committed) fail("Workbench rollback settlement lacks preparation");
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
const { authorization, basis } = prepared.value;
|
|
615
|
+
const request = buildEvolutionWorkbenchRollbackRequest(
|
|
616
|
+
plan,
|
|
617
|
+
authorization.receiptDigest,
|
|
618
|
+
);
|
|
619
|
+
const expected = this.#preparationValue(
|
|
620
|
+
plan,
|
|
621
|
+
request,
|
|
622
|
+
authorization,
|
|
623
|
+
basis,
|
|
624
|
+
);
|
|
625
|
+
if (
|
|
626
|
+
!same(prepared.value, expected) ||
|
|
627
|
+
prepared.event.sequence <= retained.sequence ||
|
|
628
|
+
!same(
|
|
629
|
+
prepared.event.sourceRefs,
|
|
630
|
+
sortedRefs([
|
|
631
|
+
retained.artifactRef,
|
|
632
|
+
fromReview.packetRef,
|
|
633
|
+
toReview.packetRef,
|
|
634
|
+
toReview.decisionRef,
|
|
635
|
+
]),
|
|
636
|
+
)
|
|
637
|
+
)
|
|
638
|
+
fail("Workbench rollback preparation lineage differs");
|
|
639
|
+
const proof = this.#proof(context, prepared);
|
|
640
|
+
const authorizationTime = proof
|
|
641
|
+
? Date.parse(proof.result.intent.authorityReceipt.occurredAt)
|
|
642
|
+
: historicalPreparation
|
|
643
|
+
? Date.parse(prepared.event.timestamp)
|
|
644
|
+
: Number(this.#now());
|
|
645
|
+
verifyWorkbenchRollbackAuthorization(
|
|
646
|
+
authorization,
|
|
647
|
+
plan,
|
|
648
|
+
authorizationTime,
|
|
649
|
+
);
|
|
650
|
+
verifySkillPromotionReviewDecision(
|
|
651
|
+
toReview.decision,
|
|
652
|
+
toReview.packet,
|
|
653
|
+
authorizationTime,
|
|
654
|
+
);
|
|
655
|
+
if ((await this.#verifyHuman({ plan, authorization })) !== true)
|
|
656
|
+
fail("Workbench rollback human signature verification failed");
|
|
657
|
+
if (!proof) {
|
|
658
|
+
verifyWorkbenchRollbackAuthorization(
|
|
659
|
+
authorization,
|
|
660
|
+
plan,
|
|
661
|
+
historicalPreparation ? authorizationTime : Number(this.#now()),
|
|
662
|
+
);
|
|
663
|
+
verifySkillPromotionReviewDecision(
|
|
664
|
+
toReview.decision,
|
|
665
|
+
toReview.packet,
|
|
666
|
+
historicalPreparation ? authorizationTime : Number(this.#now()),
|
|
667
|
+
);
|
|
668
|
+
if (
|
|
669
|
+
!same(
|
|
670
|
+
this.#basis(
|
|
671
|
+
plan,
|
|
672
|
+
historicalPreparation
|
|
673
|
+
? this.#activeAtPreparation(plan, prepared)
|
|
674
|
+
: this.#active(plan.skillName),
|
|
675
|
+
request,
|
|
676
|
+
),
|
|
677
|
+
basis,
|
|
678
|
+
)
|
|
679
|
+
)
|
|
680
|
+
fail("Workbench rollback preparation target changed");
|
|
681
|
+
}
|
|
682
|
+
if (committed) {
|
|
683
|
+
if (
|
|
684
|
+
!proof ||
|
|
685
|
+
!same(committed.value, this.#settlementValue(plan, request, proof)) ||
|
|
686
|
+
!same(
|
|
687
|
+
committed.event.sourceRefs,
|
|
688
|
+
sortedRefs([prepared.event.subjectRef, proof.finalizationRef]),
|
|
689
|
+
) ||
|
|
690
|
+
committed.event.sequence <= proof.result.projection.sequence
|
|
691
|
+
)
|
|
692
|
+
fail("Workbench rollback settlement has no exact Registry effect");
|
|
693
|
+
}
|
|
694
|
+
this.#stable(snapshot.head);
|
|
695
|
+
return { prepared, committed, proof, request, authorization, basis };
|
|
696
|
+
}
|
|
697
|
+
#preparationValue(plan, request, authorization, basis) {
|
|
698
|
+
return capture({
|
|
699
|
+
schema: WORKBENCH_ROLLBACK_PREPARATION_SCHEMA,
|
|
700
|
+
tenantId: this.descriptor.tenantId,
|
|
701
|
+
runId: this.descriptor.runId,
|
|
702
|
+
skillName: this.descriptor.skillName,
|
|
703
|
+
planDigest: plan.planDigest,
|
|
704
|
+
plan,
|
|
705
|
+
request,
|
|
706
|
+
authorization,
|
|
707
|
+
basis,
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
#settlementValue(plan, request, proof) {
|
|
711
|
+
const { intent, projection } = proof.result;
|
|
712
|
+
const receipt = buildEvolutionWorkbenchRollbackReceipt(
|
|
713
|
+
plan,
|
|
714
|
+
request,
|
|
715
|
+
projection.receiptDigest,
|
|
716
|
+
{
|
|
717
|
+
stateDigest: projection.stateDigest,
|
|
718
|
+
contentDigest: plan.toContentDigest,
|
|
719
|
+
},
|
|
720
|
+
);
|
|
721
|
+
return capture({
|
|
722
|
+
schema: WORKBENCH_ROLLBACK_SETTLEMENT_SCHEMA,
|
|
723
|
+
tenantId: this.descriptor.tenantId,
|
|
724
|
+
runId: this.descriptor.runId,
|
|
725
|
+
skillName: this.descriptor.skillName,
|
|
726
|
+
planDigest: plan.planDigest,
|
|
727
|
+
transactionId: intent.transactionId,
|
|
728
|
+
intentDigest: intent.intentDigest,
|
|
729
|
+
receipt,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
async authorizeHumanRollback({ plan: input }) {
|
|
733
|
+
const context = await this.#context(input);
|
|
734
|
+
const existing = await this.#load(context);
|
|
735
|
+
let authorization = existing?.authorization;
|
|
736
|
+
if (!existing) {
|
|
737
|
+
const { plan, retained, fromReview, toReview, snapshot } = context;
|
|
738
|
+
// Preflight exact active/LKG identities before presenting a human prompt.
|
|
739
|
+
const active = this.#active(plan.skillName);
|
|
740
|
+
this.#basis(plan, active, { requestDigest: plan.planDigest });
|
|
741
|
+
verifySkillPromotionReviewDecision(
|
|
742
|
+
toReview.decision,
|
|
743
|
+
toReview.packet,
|
|
744
|
+
Number(this.#now()),
|
|
745
|
+
);
|
|
746
|
+
authorization = verifyWorkbenchRollbackAuthorization(
|
|
747
|
+
await this.#human({ plan }),
|
|
748
|
+
plan,
|
|
749
|
+
Number(this.#now()),
|
|
750
|
+
);
|
|
751
|
+
if ((await this.#verifyHuman({ plan, authorization })) !== true)
|
|
752
|
+
fail("Workbench rollback human signature verification failed");
|
|
753
|
+
verifyWorkbenchRollbackAuthorization(
|
|
754
|
+
authorization,
|
|
755
|
+
plan,
|
|
756
|
+
Number(this.#now()),
|
|
757
|
+
);
|
|
758
|
+
const request = buildEvolutionWorkbenchRollbackRequest(
|
|
759
|
+
plan,
|
|
760
|
+
authorization.receiptDigest,
|
|
761
|
+
);
|
|
762
|
+
const basis = this.#basis(plan, this.#active(plan.skillName), request);
|
|
763
|
+
this.#stable(snapshot.head);
|
|
764
|
+
this.#append(
|
|
765
|
+
"prepared",
|
|
766
|
+
this.#preparationValue(plan, request, authorization, basis),
|
|
767
|
+
[
|
|
768
|
+
retained.artifactRef,
|
|
769
|
+
fromReview.packetRef,
|
|
770
|
+
toReview.packetRef,
|
|
771
|
+
toReview.decisionRef,
|
|
772
|
+
],
|
|
773
|
+
snapshot.head,
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
return capture({
|
|
777
|
+
authenticated: true,
|
|
778
|
+
durable: true,
|
|
779
|
+
automated: false,
|
|
780
|
+
planDigest: input.planDigest,
|
|
781
|
+
receiptDigest: authorization.receiptDigest,
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
async #requestContext(input) {
|
|
785
|
+
const request = capture(input);
|
|
786
|
+
const snapshot = this.#snapshot();
|
|
787
|
+
const prepared = this.#find("prepared", request.planDigest, snapshot);
|
|
788
|
+
if (!prepared || !same(prepared.value.request, request))
|
|
789
|
+
fail("Workbench rollback request has no exact durable preparation");
|
|
790
|
+
const context = await this.#context(prepared.value.plan);
|
|
791
|
+
return { context, state: await this.#load(context) };
|
|
792
|
+
}
|
|
793
|
+
async applyRollback(input) {
|
|
794
|
+
let { context, state } = await this.#requestContext(input);
|
|
795
|
+
if (!state.proof) {
|
|
796
|
+
const policyReceipt = this.#policy(state.prepared);
|
|
797
|
+
const deadline = Math.min(
|
|
798
|
+
Date.parse(state.authorization.expiresAt),
|
|
799
|
+
Date.parse(context.toReview.decision.expiresAt),
|
|
800
|
+
);
|
|
801
|
+
const expected = capture({
|
|
802
|
+
...state.basis,
|
|
803
|
+
policyReceipt,
|
|
804
|
+
planDigest: context.plan.planDigest,
|
|
805
|
+
authorizationReceiptDigest: state.authorization.receiptDigest,
|
|
806
|
+
expiresAt: new Date(deadline).toISOString(),
|
|
807
|
+
});
|
|
808
|
+
MUTATION_CONTEXTS.set(expected, {
|
|
809
|
+
registry: this.#registryIdentity,
|
|
810
|
+
ledger: this.#ledgerIdentity,
|
|
811
|
+
descriptor: this.descriptor,
|
|
812
|
+
});
|
|
813
|
+
let raw;
|
|
814
|
+
try {
|
|
815
|
+
raw = await this.#authorize(expected);
|
|
816
|
+
} finally {
|
|
817
|
+
// Legacy authority ports need not consume the token, but may not keep
|
|
818
|
+
// it alive after this exact request has returned or failed.
|
|
819
|
+
MUTATION_CONTEXTS.delete(expected);
|
|
820
|
+
}
|
|
821
|
+
if (!raw || types.isProxy(raw))
|
|
822
|
+
fail("Workbench mutation authorization must be own data");
|
|
823
|
+
const fields = Object.getOwnPropertyDescriptors(raw);
|
|
824
|
+
if (
|
|
825
|
+
Reflect.ownKeys(fields).length !== 2 ||
|
|
826
|
+
!fields.request ||
|
|
827
|
+
!fields.capability ||
|
|
828
|
+
[fields.request, fields.capability].some(
|
|
829
|
+
(field) => !("value" in field) || !field.enumerable,
|
|
830
|
+
)
|
|
831
|
+
)
|
|
832
|
+
fail(
|
|
833
|
+
"Workbench mutation authorization requires exact request/capability fields",
|
|
834
|
+
);
|
|
835
|
+
const request = verifySkillMutationRequest(fields.request.value);
|
|
836
|
+
if (Date.parse(request.expiresAt) > deadline)
|
|
837
|
+
fail("Workbench mutation authorization outlives human approval");
|
|
838
|
+
for (const key of [
|
|
839
|
+
"tenantId",
|
|
840
|
+
"skillName",
|
|
841
|
+
"operationId",
|
|
842
|
+
"operation",
|
|
843
|
+
"targetScope",
|
|
844
|
+
"expectedTargetDigest",
|
|
845
|
+
"expectedTargetRevision",
|
|
846
|
+
"transitionSubjectDigest",
|
|
847
|
+
])
|
|
848
|
+
if (request[key] !== state.basis[key])
|
|
849
|
+
fail("Workbench mutation authority authorized another transition");
|
|
850
|
+
if (request.receipts.policyReceipt !== policyReceipt)
|
|
851
|
+
fail(
|
|
852
|
+
"Workbench mutation policy is not bound to the persisted human authorization",
|
|
853
|
+
);
|
|
854
|
+
// Capability issuance may append audit records. Refresh all inputs after
|
|
855
|
+
// it, including current revocation/freshness, before consuming authority.
|
|
856
|
+
({ context, state } = await this.#requestContext(input));
|
|
857
|
+
if (state.proof)
|
|
858
|
+
fail("Workbench rollback changed while mutation authority was pending");
|
|
859
|
+
verifyWorkbenchRollbackAuthorization(
|
|
860
|
+
state.authorization,
|
|
861
|
+
context.plan,
|
|
862
|
+
Number(this.#now()),
|
|
863
|
+
);
|
|
864
|
+
verifySkillPromotionReviewDecision(
|
|
865
|
+
context.toReview.decision,
|
|
866
|
+
context.toReview.packet,
|
|
867
|
+
Number(this.#now()),
|
|
868
|
+
);
|
|
869
|
+
await this.#rollback({
|
|
870
|
+
authorization: { request, capability: fields.capability.value },
|
|
871
|
+
targetReleaseDigest: state.basis.targetReleaseDigest,
|
|
872
|
+
});
|
|
873
|
+
({ context, state } = await this.#requestContext(input));
|
|
874
|
+
}
|
|
875
|
+
const proof = this.#proof(context, state.prepared, true);
|
|
876
|
+
if (!proof)
|
|
877
|
+
fail(
|
|
878
|
+
"Workbench rollback has no independently authenticated Registry effect",
|
|
879
|
+
);
|
|
880
|
+
return capture({
|
|
881
|
+
authenticated: true,
|
|
882
|
+
durable: true,
|
|
883
|
+
requestDigest: state.request.requestDigest,
|
|
884
|
+
receiptDigest: proof.result.projection.receiptDigest,
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
async readActiveState({ tenantId, skillName }) {
|
|
888
|
+
if (
|
|
889
|
+
tenantId !== this.descriptor.tenantId ||
|
|
890
|
+
skillName !== this.descriptor.skillName
|
|
891
|
+
)
|
|
892
|
+
fail("Workbench active-state scope differs");
|
|
893
|
+
const active = this.#active(skillName);
|
|
894
|
+
return capture({
|
|
895
|
+
authenticated: true,
|
|
896
|
+
durable: true,
|
|
897
|
+
tenantId,
|
|
898
|
+
skillName,
|
|
899
|
+
contentDigest: active.release.contentDigest,
|
|
900
|
+
stateDigest: active.state.stateDigest,
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
async commitRollback({ receipt: input }) {
|
|
904
|
+
const receipt = capture(input);
|
|
905
|
+
const prepared = this.#find(
|
|
906
|
+
"prepared",
|
|
907
|
+
receipt.planDigest,
|
|
908
|
+
this.#snapshot(),
|
|
909
|
+
);
|
|
910
|
+
if (!prepared) fail("Workbench rollback receipt has no preparation");
|
|
911
|
+
const context = await this.#context(prepared.value.plan);
|
|
912
|
+
const state = await this.#load(context);
|
|
913
|
+
await this.#settle(context, state, receipt, true);
|
|
914
|
+
return {
|
|
915
|
+
authenticated: true,
|
|
916
|
+
durable: true,
|
|
917
|
+
receiptDigest: receipt.receiptDigest,
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
async #settle(context, state, expectedReceipt, requireCurrent) {
|
|
921
|
+
const proof = this.#proof(context, state.prepared, requireCurrent);
|
|
922
|
+
if (!proof) fail("Workbench rollback receipt has no Registry effect");
|
|
923
|
+
const value = this.#settlementValue(context.plan, state.request, proof);
|
|
924
|
+
if (expectedReceipt !== null && !same(expectedReceipt, value.receipt))
|
|
925
|
+
fail("Workbench rollback receipt differs from actual Registry effect");
|
|
926
|
+
if (!state.committed)
|
|
927
|
+
this.#append(
|
|
928
|
+
"committed",
|
|
929
|
+
value,
|
|
930
|
+
[state.prepared.event.subjectRef, proof.finalizationRef],
|
|
931
|
+
context.snapshot.head,
|
|
932
|
+
);
|
|
933
|
+
const readback = await this.#load(await this.#context(context.plan));
|
|
934
|
+
if (!readback.committed)
|
|
935
|
+
fail("Workbench rollback settlement was not durably read back");
|
|
936
|
+
return value.receipt;
|
|
937
|
+
}
|
|
938
|
+
createExecutor() {
|
|
939
|
+
return new EvolutionWorkbenchRollbackExecutor({
|
|
940
|
+
tenantId: this.descriptor.tenantId,
|
|
941
|
+
ports: {
|
|
942
|
+
loadProjection: async (input) =>
|
|
943
|
+
this.#projection.read(input).projection,
|
|
944
|
+
authorizeHumanRollback: this.authorizeHumanRollback.bind(this),
|
|
945
|
+
applyRollback: this.applyRollback.bind(this),
|
|
946
|
+
readActiveState: this.readActiveState.bind(this),
|
|
947
|
+
commitRollback: this.commitRollback.bind(this),
|
|
948
|
+
},
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
// Unlike resume(), startup reconciliation cannot request authority or switch
|
|
952
|
+
// Registry state. Expired/stale pending plans remain pending for explicit action.
|
|
953
|
+
async reconcileCommitted() {
|
|
954
|
+
const snapshot = this.#snapshot();
|
|
955
|
+
for (const row of snapshot.rows)
|
|
956
|
+
if (
|
|
957
|
+
row.kind === "committed" &&
|
|
958
|
+
!this.#find("prepared", row.value.planDigest, snapshot)
|
|
959
|
+
)
|
|
960
|
+
fail("Workbench rollback settlement lacks preparation");
|
|
961
|
+
const plans = snapshot.rows
|
|
962
|
+
.filter((row) => row.kind === "prepared")
|
|
963
|
+
.map((row) => row.value.plan);
|
|
964
|
+
const settledReceipts = [];
|
|
965
|
+
const deferredPlanDigests = [];
|
|
966
|
+
for (const plan of plans) {
|
|
967
|
+
const context = await this.#context(plan);
|
|
968
|
+
const state = await this.#load(context, true);
|
|
969
|
+
if (!state) fail("Workbench recovery preparation is missing");
|
|
970
|
+
if (!state.proof) deferredPlanDigests.push(plan.planDigest);
|
|
971
|
+
else if (!state.committed)
|
|
972
|
+
settledReceipts.push(await this.#settle(context, state, null, false));
|
|
973
|
+
}
|
|
974
|
+
return capture({ settledReceipts, deferredPlanDigests });
|
|
975
|
+
}
|
|
976
|
+
async resume() {
|
|
977
|
+
const snapshot = this.#snapshot();
|
|
978
|
+
for (const row of snapshot.rows)
|
|
979
|
+
if (
|
|
980
|
+
row.kind === "committed" &&
|
|
981
|
+
!this.#find("prepared", row.value.planDigest, snapshot)
|
|
982
|
+
)
|
|
983
|
+
fail("Workbench rollback settlement lacks preparation");
|
|
984
|
+
const plans = snapshot.rows
|
|
985
|
+
.filter((row) => row.kind === "prepared")
|
|
986
|
+
.map((row) => row.value.plan);
|
|
987
|
+
const receipts = [];
|
|
988
|
+
for (const plan of plans) {
|
|
989
|
+
const context = await this.#context(plan);
|
|
990
|
+
const state = await this.#load(context);
|
|
991
|
+
if (!state.committed) {
|
|
992
|
+
// A later legitimate release must not strand a completed rollback's
|
|
993
|
+
// accounting. Authenticate the historical effect and only settle it;
|
|
994
|
+
// explicit execute() still requires the effect to be current.
|
|
995
|
+
receipts.push(
|
|
996
|
+
state.proof
|
|
997
|
+
? await this.#settle(context, state, null, false)
|
|
998
|
+
: await this.createExecutor().execute(plan),
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return Object.freeze(receipts);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
export function createEvolutionWorkbenchRollbackRuntime(options) {
|
|
1007
|
+
const adapter = new EvolutionWorkbenchRollbackLedgerAdapter(options);
|
|
1008
|
+
return Object.freeze({
|
|
1009
|
+
rollbackExecutor: adapter.createExecutor(),
|
|
1010
|
+
activeStateReader: Object.freeze({
|
|
1011
|
+
read: adapter.readActiveState.bind(adapter),
|
|
1012
|
+
}),
|
|
1013
|
+
reconcileCommitted: adapter.reconcileCommitted.bind(adapter),
|
|
1014
|
+
resume: adapter.resume.bind(adapter),
|
|
1015
|
+
});
|
|
1016
|
+
}
|