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,644 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { types as utilTypes } from "node:util";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA,
|
|
6
|
+
isEvolutionLedgerArtifactResolver,
|
|
7
|
+
} from "./evolution-artifact-ports.js";
|
|
8
|
+
import {
|
|
9
|
+
EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA,
|
|
10
|
+
EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA,
|
|
11
|
+
} from "./evolution-ledger.js";
|
|
12
|
+
import {
|
|
13
|
+
isGovernedKnowledgeMergePlan,
|
|
14
|
+
verifyGovernedKnowledgeMergePlan,
|
|
15
|
+
} from "./governed-knowledge-conflict-merge.js";
|
|
16
|
+
import {
|
|
17
|
+
GOVERNED_KNOWLEDGE_MERGE_PUBLISH_REQUEST_SCHEMA,
|
|
18
|
+
GOVERNED_KNOWLEDGE_MERGE_PUBLISH_RESULT_SCHEMA,
|
|
19
|
+
digestGovernedKnowledgeMergePublishResult,
|
|
20
|
+
isGovernedKnowledgeMergePublisherAuthority,
|
|
21
|
+
} from "./governed-knowledge-merge-publisher-authority.js";
|
|
22
|
+
import { GOVERNED_KNOWLEDGE_SYNC_COMMIT_EVENT_TYPE } from "./governed-knowledge-sync-ledger-adapter.js";
|
|
23
|
+
|
|
24
|
+
export const GOVERNED_KNOWLEDGE_MERGE_PREPARED_SCHEMA =
|
|
25
|
+
"chainlesschain.governed-knowledge-merge-prepared/v1";
|
|
26
|
+
export const GOVERNED_KNOWLEDGE_MERGE_SETTLED_SCHEMA =
|
|
27
|
+
"chainlesschain.governed-knowledge-merge-settled/v1";
|
|
28
|
+
export const GOVERNED_KNOWLEDGE_MERGE_PREPARED_EVENT_TYPE =
|
|
29
|
+
"knowledge.merge.prepared";
|
|
30
|
+
export const GOVERNED_KNOWLEDGE_MERGE_SETTLED_EVENT_TYPE =
|
|
31
|
+
"knowledge.merge.settled";
|
|
32
|
+
export const GOVERNED_KNOWLEDGE_MERGE_LEDGER_CORRUPT_CODE =
|
|
33
|
+
"CC_GOVERNED_KNOWLEDGE_MERGE_LEDGER_CORRUPT";
|
|
34
|
+
|
|
35
|
+
const ARTIFACT_TYPE = "governed-knowledge-merge-operation";
|
|
36
|
+
const EXECUTORS = new WeakSet();
|
|
37
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
38
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,255}$/u;
|
|
39
|
+
const PREPARED_KEYS = new Set([
|
|
40
|
+
"deviceId",
|
|
41
|
+
"plan",
|
|
42
|
+
"preparedAt",
|
|
43
|
+
"recordDigest",
|
|
44
|
+
"schema",
|
|
45
|
+
"tenantId",
|
|
46
|
+
]);
|
|
47
|
+
const SETTLED_KEYS = new Set([
|
|
48
|
+
"deviceId",
|
|
49
|
+
"planDigest",
|
|
50
|
+
"publishResult",
|
|
51
|
+
"recordDigest",
|
|
52
|
+
"schema",
|
|
53
|
+
"settledAt",
|
|
54
|
+
"tenantId",
|
|
55
|
+
]);
|
|
56
|
+
const PUBLISH_EVIDENCE_KEYS = new Set([
|
|
57
|
+
"attestation",
|
|
58
|
+
"deviceId",
|
|
59
|
+
"durable",
|
|
60
|
+
"envelopeDigest",
|
|
61
|
+
"idempotent",
|
|
62
|
+
"knowledgeId",
|
|
63
|
+
"mergedContentDigest",
|
|
64
|
+
"operationId",
|
|
65
|
+
"planDigest",
|
|
66
|
+
"providerAuthorityId",
|
|
67
|
+
"providerHandlerArtifactDigest",
|
|
68
|
+
"providerRevision",
|
|
69
|
+
"publishedAt",
|
|
70
|
+
"requestDigest",
|
|
71
|
+
"resultDigest",
|
|
72
|
+
"schema",
|
|
73
|
+
"tenantId",
|
|
74
|
+
"verificationReceiptDigest",
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
function canonical(value) {
|
|
78
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
79
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
80
|
+
return `{${Object.keys(value)
|
|
81
|
+
.sort()
|
|
82
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
83
|
+
.join(",")}}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function hash(domain, value) {
|
|
87
|
+
return `sha256:${createHash("sha256")
|
|
88
|
+
.update(domain)
|
|
89
|
+
.update("\0")
|
|
90
|
+
.update(canonical(value))
|
|
91
|
+
.digest("hex")}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function clone(value) {
|
|
95
|
+
return structuredClone(value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function freeze(value) {
|
|
99
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
100
|
+
Object.freeze(value);
|
|
101
|
+
for (const child of Object.values(value)) freeze(child);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function corrupt(message) {
|
|
107
|
+
const error = new Error(message);
|
|
108
|
+
error.code = GOVERNED_KNOWLEDGE_MERGE_LEDGER_CORRUPT_CODE;
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function exact(value, keys, label) {
|
|
113
|
+
if (
|
|
114
|
+
!value ||
|
|
115
|
+
typeof value !== "object" ||
|
|
116
|
+
Array.isArray(value) ||
|
|
117
|
+
utilTypes.isProxy(value) ||
|
|
118
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(value))
|
|
119
|
+
) {
|
|
120
|
+
corrupt(`${label} is not a plain object`);
|
|
121
|
+
}
|
|
122
|
+
const actual = Reflect.ownKeys(value);
|
|
123
|
+
if (
|
|
124
|
+
actual.length !== keys.size ||
|
|
125
|
+
actual.some((key) => typeof key !== "string" || !keys.has(key))
|
|
126
|
+
) {
|
|
127
|
+
corrupt(`${label} has an invalid shape`);
|
|
128
|
+
}
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function identifier(value, label) {
|
|
133
|
+
if (typeof value !== "string" || !ID.test(value)) {
|
|
134
|
+
throw new TypeError(`${label} is invalid`);
|
|
135
|
+
}
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function capture(owner, method, label) {
|
|
140
|
+
if (
|
|
141
|
+
!owner ||
|
|
142
|
+
typeof owner !== "object" ||
|
|
143
|
+
utilTypes.isProxy(owner) ||
|
|
144
|
+
typeof owner[method] !== "function"
|
|
145
|
+
) {
|
|
146
|
+
throw new TypeError(`${label}.${method}() is required`);
|
|
147
|
+
}
|
|
148
|
+
return (...args) => Reflect.apply(owner[method], owner, args);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function descriptor(input) {
|
|
152
|
+
return freeze({
|
|
153
|
+
tenantId: identifier(input?.tenantId, "tenantId"),
|
|
154
|
+
artifactTenantId: identifier(input?.artifactTenantId, "artifactTenantId"),
|
|
155
|
+
deviceId: identifier(input?.deviceId, "deviceId"),
|
|
156
|
+
streamId: identifier(input?.streamId, "streamId"),
|
|
157
|
+
audience: identifier(input?.audience, "audience"),
|
|
158
|
+
purpose: identifier(input?.purpose, "purpose"),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function preparedCore(value) {
|
|
163
|
+
return {
|
|
164
|
+
schema: value.schema,
|
|
165
|
+
tenantId: value.tenantId,
|
|
166
|
+
deviceId: value.deviceId,
|
|
167
|
+
plan: value.plan,
|
|
168
|
+
preparedAt: value.preparedAt,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function settledCore(value) {
|
|
173
|
+
return {
|
|
174
|
+
schema: value.schema,
|
|
175
|
+
tenantId: value.tenantId,
|
|
176
|
+
deviceId: value.deviceId,
|
|
177
|
+
planDigest: value.planDigest,
|
|
178
|
+
publishResult: value.publishResult,
|
|
179
|
+
settledAt: value.settledAt,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function validatePublishEvidence(value, plan, descriptorValue) {
|
|
184
|
+
exact(value, PUBLISH_EVIDENCE_KEYS, "merge publish evidence");
|
|
185
|
+
const requestCore = {
|
|
186
|
+
schema: GOVERNED_KNOWLEDGE_MERGE_PUBLISH_REQUEST_SCHEMA,
|
|
187
|
+
tenantId: plan.tenantId,
|
|
188
|
+
deviceId: plan.deviceId,
|
|
189
|
+
operationId: `knowledge-merge:${plan.planDigest.slice(7)}`,
|
|
190
|
+
planDigest: plan.planDigest,
|
|
191
|
+
knowledgeId: plan.knowledgeId,
|
|
192
|
+
mergedContentDigest: plan.mergedKnowledge.contentDigest,
|
|
193
|
+
mergedKnowledge: plan.mergedKnowledge,
|
|
194
|
+
};
|
|
195
|
+
if (
|
|
196
|
+
value.schema !== GOVERNED_KNOWLEDGE_MERGE_PUBLISH_RESULT_SCHEMA ||
|
|
197
|
+
value.tenantId !== descriptorValue.tenantId ||
|
|
198
|
+
value.deviceId !== descriptorValue.deviceId ||
|
|
199
|
+
value.operationId !== `knowledge-merge:${plan.planDigest.slice(7)}` ||
|
|
200
|
+
value.planDigest !== plan.planDigest ||
|
|
201
|
+
value.knowledgeId !== plan.knowledgeId ||
|
|
202
|
+
value.mergedContentDigest !== plan.mergedKnowledge.contentDigest ||
|
|
203
|
+
value.durable !== true ||
|
|
204
|
+
value.idempotent !== true ||
|
|
205
|
+
value.requestDigest !==
|
|
206
|
+
hash(GOVERNED_KNOWLEDGE_MERGE_PUBLISH_REQUEST_SCHEMA, requestCore) ||
|
|
207
|
+
!DIGEST.test(value.envelopeDigest ?? "") ||
|
|
208
|
+
!DIGEST.test(value.resultDigest ?? "") ||
|
|
209
|
+
!DIGEST.test(value.verificationReceiptDigest ?? "") ||
|
|
210
|
+
value.resultDigest !== digestGovernedKnowledgeMergePublishResult(value)
|
|
211
|
+
) {
|
|
212
|
+
corrupt("merge publish evidence is not exactly bound");
|
|
213
|
+
}
|
|
214
|
+
return freeze(clone(value));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function validatePrepared(value, descriptorValue) {
|
|
218
|
+
exact(value, PREPARED_KEYS, "prepared merge record");
|
|
219
|
+
const plan = verifyGovernedKnowledgeMergePlan(value.plan);
|
|
220
|
+
if (
|
|
221
|
+
value.schema !== GOVERNED_KNOWLEDGE_MERGE_PREPARED_SCHEMA ||
|
|
222
|
+
value.tenantId !== descriptorValue.tenantId ||
|
|
223
|
+
value.deviceId !== descriptorValue.deviceId ||
|
|
224
|
+
plan.tenantId !== descriptorValue.tenantId ||
|
|
225
|
+
plan.deviceId !== descriptorValue.deviceId ||
|
|
226
|
+
!Number.isFinite(Date.parse(value.preparedAt)) ||
|
|
227
|
+
value.recordDigest !==
|
|
228
|
+
hash(GOVERNED_KNOWLEDGE_MERGE_PREPARED_SCHEMA, preparedCore(value))
|
|
229
|
+
) {
|
|
230
|
+
corrupt("prepared merge record is invalid");
|
|
231
|
+
}
|
|
232
|
+
return freeze(clone(value));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function validateSettled(value, plan, descriptorValue) {
|
|
236
|
+
exact(value, SETTLED_KEYS, "settled merge record");
|
|
237
|
+
if (
|
|
238
|
+
value.schema !== GOVERNED_KNOWLEDGE_MERGE_SETTLED_SCHEMA ||
|
|
239
|
+
value.tenantId !== descriptorValue.tenantId ||
|
|
240
|
+
value.deviceId !== descriptorValue.deviceId ||
|
|
241
|
+
value.planDigest !== plan.planDigest ||
|
|
242
|
+
!Number.isFinite(Date.parse(value.settledAt)) ||
|
|
243
|
+
value.recordDigest !==
|
|
244
|
+
hash(GOVERNED_KNOWLEDGE_MERGE_SETTLED_SCHEMA, settledCore(value))
|
|
245
|
+
) {
|
|
246
|
+
corrupt("settled merge record is invalid");
|
|
247
|
+
}
|
|
248
|
+
validatePublishEvidence(value.publishResult, plan, descriptorValue);
|
|
249
|
+
return freeze(clone(value));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export class GovernedKnowledgeMergeLedgerExecutor {
|
|
253
|
+
constructor({
|
|
254
|
+
descriptor: descriptorInput,
|
|
255
|
+
artifactPorts,
|
|
256
|
+
ledger,
|
|
257
|
+
ledgerArtifactResolver,
|
|
258
|
+
publisherAuthority,
|
|
259
|
+
now = Date.now,
|
|
260
|
+
} = {}) {
|
|
261
|
+
this.descriptor = descriptor(descriptorInput);
|
|
262
|
+
this._put = capture(artifactPorts, "putCanonical", "artifactPorts");
|
|
263
|
+
this._read = capture(ledger, "read", "ledger");
|
|
264
|
+
this._verifyLedger = capture(ledger, "verify", "ledger");
|
|
265
|
+
this._append = capture(ledger, "appendDomainEvent", "ledger");
|
|
266
|
+
if (!isEvolutionLedgerArtifactResolver(ledgerArtifactResolver)) {
|
|
267
|
+
throw new TypeError(
|
|
268
|
+
"a branded EvolutionArtifactPorts ledger resolver is required",
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
if (!isGovernedKnowledgeMergePublisherAuthority(publisherAuthority)) {
|
|
272
|
+
throw new TypeError("a branded knowledge merge publisher is required");
|
|
273
|
+
}
|
|
274
|
+
if (
|
|
275
|
+
publisherAuthority.tenantId !== this.descriptor.tenantId ||
|
|
276
|
+
publisherAuthority.deviceId !== this.descriptor.deviceId
|
|
277
|
+
) {
|
|
278
|
+
throw new TypeError("merge publisher authority boundary is invalid");
|
|
279
|
+
}
|
|
280
|
+
if (typeof now !== "function" || utilTypes.isProxy(now)) {
|
|
281
|
+
throw new TypeError("now must be a non-proxy function");
|
|
282
|
+
}
|
|
283
|
+
this._resolveArtifact = ledgerArtifactResolver;
|
|
284
|
+
this._publish = capture(
|
|
285
|
+
publisherAuthority,
|
|
286
|
+
"publish",
|
|
287
|
+
"publisherAuthority",
|
|
288
|
+
);
|
|
289
|
+
this._now = now;
|
|
290
|
+
Object.freeze(this);
|
|
291
|
+
EXECUTORS.add(this);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
_events(type) {
|
|
295
|
+
const events = this._read();
|
|
296
|
+
if (!Array.isArray(events)) corrupt("EvolutionLedger returned no events");
|
|
297
|
+
return events.filter(
|
|
298
|
+
(event) =>
|
|
299
|
+
event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
|
|
300
|
+
event.type === type &&
|
|
301
|
+
event.tenantId === this.descriptor.tenantId &&
|
|
302
|
+
event.correlationId === this.descriptor.streamId,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
_event(eventId, type) {
|
|
307
|
+
const matches = this._events(type).filter(
|
|
308
|
+
(event) => event.eventId === eventId,
|
|
309
|
+
);
|
|
310
|
+
if (matches.length > 1) corrupt("merge ledger event is ambiguous");
|
|
311
|
+
return matches[0] ?? null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
_resolve(event) {
|
|
315
|
+
const identity = this._verifyLedger();
|
|
316
|
+
const resolution = this._resolveArtifact({
|
|
317
|
+
epoch: identity.epoch,
|
|
318
|
+
ledgerId: identity.ledgerId,
|
|
319
|
+
ref: event.subjectRef,
|
|
320
|
+
tenantId: this.descriptor.artifactTenantId,
|
|
321
|
+
});
|
|
322
|
+
if (
|
|
323
|
+
resolution?.schema !== EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA ||
|
|
324
|
+
resolution.authenticated !== true ||
|
|
325
|
+
resolution.found !== true ||
|
|
326
|
+
resolution.ref !== event.subjectRef.ref ||
|
|
327
|
+
resolution.digest !== event.subjectRef.digest ||
|
|
328
|
+
!Buffer.isBuffer(resolution.bytes)
|
|
329
|
+
) {
|
|
330
|
+
corrupt("merge artifact resolution is unauthenticated or substituted");
|
|
331
|
+
}
|
|
332
|
+
let artifact;
|
|
333
|
+
try {
|
|
334
|
+
artifact = JSON.parse(resolution.bytes.toString("utf8"));
|
|
335
|
+
} catch {
|
|
336
|
+
corrupt("merge artifact is not JSON");
|
|
337
|
+
}
|
|
338
|
+
if (
|
|
339
|
+
artifact?.schema !== EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA ||
|
|
340
|
+
artifact.tenantId !== this.descriptor.artifactTenantId ||
|
|
341
|
+
artifact.audience !== this.descriptor.audience ||
|
|
342
|
+
artifact.purpose !== this.descriptor.purpose ||
|
|
343
|
+
artifact.retention !== "ledger" ||
|
|
344
|
+
artifact.type !== ARTIFACT_TYPE
|
|
345
|
+
) {
|
|
346
|
+
corrupt("merge durable artifact binding is invalid");
|
|
347
|
+
}
|
|
348
|
+
return artifact.value;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
_prepared(planDigest) {
|
|
352
|
+
const event = this._event(
|
|
353
|
+
`${GOVERNED_KNOWLEDGE_MERGE_PREPARED_EVENT_TYPE}.${planDigest.slice(7)}`,
|
|
354
|
+
GOVERNED_KNOWLEDGE_MERGE_PREPARED_EVENT_TYPE,
|
|
355
|
+
);
|
|
356
|
+
if (!event) return null;
|
|
357
|
+
const record = validatePrepared(this._resolve(event), this.descriptor);
|
|
358
|
+
if (
|
|
359
|
+
record.plan.planDigest !== planDigest ||
|
|
360
|
+
event.decision !== "prepared" ||
|
|
361
|
+
!Array.isArray(event.sourceRefs) ||
|
|
362
|
+
event.sourceRefs.length !== 1 ||
|
|
363
|
+
canonical(event.sourceRefs[0]) !==
|
|
364
|
+
canonical(this._conflictEvent(record.plan).subjectRef)
|
|
365
|
+
) {
|
|
366
|
+
corrupt("prepared merge event is invalid");
|
|
367
|
+
}
|
|
368
|
+
return { event, record };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
_settled(plan) {
|
|
372
|
+
const event = this._event(
|
|
373
|
+
`${GOVERNED_KNOWLEDGE_MERGE_SETTLED_EVENT_TYPE}.${plan.planDigest.slice(7)}`,
|
|
374
|
+
GOVERNED_KNOWLEDGE_MERGE_SETTLED_EVENT_TYPE,
|
|
375
|
+
);
|
|
376
|
+
if (!event) return null;
|
|
377
|
+
const record = validateSettled(this._resolve(event), plan, this.descriptor);
|
|
378
|
+
const prepared = this._prepared(plan.planDigest);
|
|
379
|
+
if (
|
|
380
|
+
!prepared ||
|
|
381
|
+
event.decision !== "committed" ||
|
|
382
|
+
!Array.isArray(event.sourceRefs) ||
|
|
383
|
+
event.sourceRefs.length !== 1 ||
|
|
384
|
+
canonical(event.sourceRefs[0]) !== canonical(prepared.event.subjectRef)
|
|
385
|
+
) {
|
|
386
|
+
corrupt("settled merge event lineage is invalid");
|
|
387
|
+
}
|
|
388
|
+
return { event, record };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
_preparedForConflict(envelopeDigest) {
|
|
392
|
+
const matches = [];
|
|
393
|
+
for (const event of this._events(
|
|
394
|
+
GOVERNED_KNOWLEDGE_MERGE_PREPARED_EVENT_TYPE,
|
|
395
|
+
)) {
|
|
396
|
+
const suffix = event.eventId?.slice(
|
|
397
|
+
`${GOVERNED_KNOWLEDGE_MERGE_PREPARED_EVENT_TYPE}.`.length,
|
|
398
|
+
);
|
|
399
|
+
const planDigest = `sha256:${suffix}`;
|
|
400
|
+
if (!DIGEST.test(planDigest))
|
|
401
|
+
corrupt("prepared merge event id is invalid");
|
|
402
|
+
const prepared = this._prepared(planDigest);
|
|
403
|
+
if (prepared.record.plan.conflictEnvelopeDigest === envelopeDigest) {
|
|
404
|
+
matches.push(prepared);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (matches.length > 1) {
|
|
408
|
+
corrupt("a conflict has multiple prepared merge operations");
|
|
409
|
+
}
|
|
410
|
+
return matches[0] ?? null;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
_conflictEvent(plan) {
|
|
414
|
+
const eventId = `${GOVERNED_KNOWLEDGE_SYNC_COMMIT_EVENT_TYPE}.conflict.${plan.conflictEnvelopeDigest.slice(7)}`;
|
|
415
|
+
const matches = this._events(
|
|
416
|
+
GOVERNED_KNOWLEDGE_SYNC_COMMIT_EVENT_TYPE,
|
|
417
|
+
).filter((event) => event.eventId === eventId);
|
|
418
|
+
if (matches.length !== 1) {
|
|
419
|
+
corrupt("merge plan conflict event is missing or ambiguous");
|
|
420
|
+
}
|
|
421
|
+
return matches[0];
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
_timestamp() {
|
|
425
|
+
const milliseconds = Number(this._now());
|
|
426
|
+
if (!Number.isFinite(milliseconds)) {
|
|
427
|
+
throw new TypeError("merge ledger clock is invalid");
|
|
428
|
+
}
|
|
429
|
+
return new Date(milliseconds).toISOString();
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
_publishArtifact(record) {
|
|
433
|
+
const published = this._put(ARTIFACT_TYPE, record, {
|
|
434
|
+
audience: this.descriptor.audience,
|
|
435
|
+
purpose: this.descriptor.purpose,
|
|
436
|
+
retention: "ledger",
|
|
437
|
+
});
|
|
438
|
+
if (
|
|
439
|
+
!published?.ref ||
|
|
440
|
+
published.receipt?.persisted !== true ||
|
|
441
|
+
published.receipt.readbackVerified !== true ||
|
|
442
|
+
published.receipt.integrityVerified !== true ||
|
|
443
|
+
published.receipt.retention !== "ledger"
|
|
444
|
+
) {
|
|
445
|
+
corrupt("merge artifact was not durably read back");
|
|
446
|
+
}
|
|
447
|
+
return published.ref;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async _prepare(plan) {
|
|
451
|
+
const conflictPreparation = this._preparedForConflict(
|
|
452
|
+
plan.conflictEnvelopeDigest,
|
|
453
|
+
);
|
|
454
|
+
if (
|
|
455
|
+
conflictPreparation &&
|
|
456
|
+
conflictPreparation.record.plan.planDigest !== plan.planDigest
|
|
457
|
+
) {
|
|
458
|
+
throw new Error("governed knowledge conflict already has a merge plan");
|
|
459
|
+
}
|
|
460
|
+
const existing = this._prepared(plan.planDigest);
|
|
461
|
+
if (existing) {
|
|
462
|
+
if (canonical(existing.record.plan) !== canonical(plan)) {
|
|
463
|
+
corrupt("prepared merge identity resolved different content");
|
|
464
|
+
}
|
|
465
|
+
return existing;
|
|
466
|
+
}
|
|
467
|
+
if (!isGovernedKnowledgeMergePlan(plan)) {
|
|
468
|
+
throw new TypeError("first merge execution requires a branded plan");
|
|
469
|
+
}
|
|
470
|
+
const conflictEvent = this._conflictEvent(plan);
|
|
471
|
+
const preparedAt = this._timestamp();
|
|
472
|
+
const core = {
|
|
473
|
+
schema: GOVERNED_KNOWLEDGE_MERGE_PREPARED_SCHEMA,
|
|
474
|
+
tenantId: this.descriptor.tenantId,
|
|
475
|
+
deviceId: this.descriptor.deviceId,
|
|
476
|
+
plan: clone(plan),
|
|
477
|
+
preparedAt,
|
|
478
|
+
};
|
|
479
|
+
const record = freeze({
|
|
480
|
+
...core,
|
|
481
|
+
recordDigest: hash(GOVERNED_KNOWLEDGE_MERGE_PREPARED_SCHEMA, core),
|
|
482
|
+
});
|
|
483
|
+
const head = this._verifyLedger();
|
|
484
|
+
const ref = this._publishArtifact(record);
|
|
485
|
+
const eventId = `${GOVERNED_KNOWLEDGE_MERGE_PREPARED_EVENT_TYPE}.${plan.planDigest.slice(7)}`;
|
|
486
|
+
try {
|
|
487
|
+
const receipt = this._append(
|
|
488
|
+
{
|
|
489
|
+
artifactTenantId: this.descriptor.artifactTenantId,
|
|
490
|
+
correlationId: this.descriptor.streamId,
|
|
491
|
+
decision: "prepared",
|
|
492
|
+
eventId,
|
|
493
|
+
reason: "governed knowledge human merge prepared",
|
|
494
|
+
skillName: null,
|
|
495
|
+
sourceRefs: [conflictEvent.subjectRef],
|
|
496
|
+
subjectRef: ref,
|
|
497
|
+
tenantId: this.descriptor.tenantId,
|
|
498
|
+
timestamp: preparedAt,
|
|
499
|
+
type: GOVERNED_KNOWLEDGE_MERGE_PREPARED_EVENT_TYPE,
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
expectedHeadDigest: head.headDigest,
|
|
503
|
+
expectedSequence: head.sequence,
|
|
504
|
+
},
|
|
505
|
+
);
|
|
506
|
+
if (receipt?.authenticated !== true || receipt.durable !== true) {
|
|
507
|
+
corrupt("prepared merge ledger append was not durable");
|
|
508
|
+
}
|
|
509
|
+
} catch (error) {
|
|
510
|
+
const recovered = this._prepared(plan.planDigest);
|
|
511
|
+
if (!recovered || canonical(recovered.record.plan) !== canonical(plan)) {
|
|
512
|
+
throw error;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return this._prepared(plan.planDigest);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async _settle(plan, publishResult) {
|
|
519
|
+
const existing = this._settled(plan);
|
|
520
|
+
if (existing) return existing;
|
|
521
|
+
const prepared = this._prepared(plan.planDigest);
|
|
522
|
+
if (!prepared) corrupt("cannot settle an unprepared merge");
|
|
523
|
+
const settledAt = this._timestamp();
|
|
524
|
+
const core = {
|
|
525
|
+
schema: GOVERNED_KNOWLEDGE_MERGE_SETTLED_SCHEMA,
|
|
526
|
+
tenantId: this.descriptor.tenantId,
|
|
527
|
+
deviceId: this.descriptor.deviceId,
|
|
528
|
+
planDigest: plan.planDigest,
|
|
529
|
+
publishResult: clone(publishResult),
|
|
530
|
+
settledAt,
|
|
531
|
+
};
|
|
532
|
+
const record = freeze({
|
|
533
|
+
...core,
|
|
534
|
+
recordDigest: hash(GOVERNED_KNOWLEDGE_MERGE_SETTLED_SCHEMA, core),
|
|
535
|
+
});
|
|
536
|
+
const head = this._verifyLedger();
|
|
537
|
+
const ref = this._publishArtifact(record);
|
|
538
|
+
const eventId = `${GOVERNED_KNOWLEDGE_MERGE_SETTLED_EVENT_TYPE}.${plan.planDigest.slice(7)}`;
|
|
539
|
+
try {
|
|
540
|
+
const receipt = this._append(
|
|
541
|
+
{
|
|
542
|
+
artifactTenantId: this.descriptor.artifactTenantId,
|
|
543
|
+
correlationId: this.descriptor.streamId,
|
|
544
|
+
decision: "committed",
|
|
545
|
+
eventId,
|
|
546
|
+
reason: "governed knowledge human merge published",
|
|
547
|
+
skillName: null,
|
|
548
|
+
sourceRefs: [prepared.event.subjectRef],
|
|
549
|
+
subjectRef: ref,
|
|
550
|
+
tenantId: this.descriptor.tenantId,
|
|
551
|
+
timestamp: settledAt,
|
|
552
|
+
type: GOVERNED_KNOWLEDGE_MERGE_SETTLED_EVENT_TYPE,
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
expectedHeadDigest: head.headDigest,
|
|
556
|
+
expectedSequence: head.sequence,
|
|
557
|
+
},
|
|
558
|
+
);
|
|
559
|
+
if (receipt?.authenticated !== true || receipt.durable !== true) {
|
|
560
|
+
corrupt("settled merge ledger append was not durable");
|
|
561
|
+
}
|
|
562
|
+
} catch (error) {
|
|
563
|
+
const recovered = this._settled(plan);
|
|
564
|
+
if (
|
|
565
|
+
!recovered ||
|
|
566
|
+
canonical(recovered.record.publishResult) !== canonical(publishResult)
|
|
567
|
+
) {
|
|
568
|
+
throw error;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return this._settled(plan);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
async execute(planInput) {
|
|
575
|
+
const plan = verifyGovernedKnowledgeMergePlan(planInput);
|
|
576
|
+
if (
|
|
577
|
+
plan.tenantId !== this.descriptor.tenantId ||
|
|
578
|
+
plan.deviceId !== this.descriptor.deviceId
|
|
579
|
+
) {
|
|
580
|
+
throw new Error("merge plan crossed its ledger boundary");
|
|
581
|
+
}
|
|
582
|
+
const completed = this._settled(plan);
|
|
583
|
+
if (completed) return this._result(completed.record, true);
|
|
584
|
+
const preparedBefore = this._prepared(plan.planDigest);
|
|
585
|
+
await this._prepare(planInput);
|
|
586
|
+
const publishResult = await this._publish(plan);
|
|
587
|
+
const settled = await this._settle(plan, publishResult);
|
|
588
|
+
return this._result(settled.record, preparedBefore !== null);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async isConflictSettled({ envelopeDigest } = {}) {
|
|
592
|
+
if (!DIGEST.test(envelopeDigest ?? "")) {
|
|
593
|
+
throw new TypeError("conflict envelope digest is invalid");
|
|
594
|
+
}
|
|
595
|
+
return (await this.settledConflictDigests()).includes(envelopeDigest);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
async settledConflictDigests() {
|
|
599
|
+
const digests = [];
|
|
600
|
+
for (const event of this._events(
|
|
601
|
+
GOVERNED_KNOWLEDGE_MERGE_SETTLED_EVENT_TYPE,
|
|
602
|
+
)) {
|
|
603
|
+
const suffix = event.eventId?.slice(
|
|
604
|
+
`${GOVERNED_KNOWLEDGE_MERGE_SETTLED_EVENT_TYPE}.`.length,
|
|
605
|
+
);
|
|
606
|
+
const planDigest = `sha256:${suffix}`;
|
|
607
|
+
if (!DIGEST.test(planDigest))
|
|
608
|
+
corrupt("settled merge event id is invalid");
|
|
609
|
+
const prepared = this._prepared(planDigest);
|
|
610
|
+
if (!prepared) corrupt("settled merge has no prepared operation");
|
|
611
|
+
this._settled(prepared.record.plan);
|
|
612
|
+
digests.push(prepared.record.plan.conflictEnvelopeDigest);
|
|
613
|
+
}
|
|
614
|
+
if (new Set(digests).size !== digests.length) {
|
|
615
|
+
corrupt("a conflict has multiple settled merge operations");
|
|
616
|
+
}
|
|
617
|
+
return freeze(digests);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
async resume({ planDigest } = {}) {
|
|
621
|
+
if (!DIGEST.test(planDigest ?? "")) {
|
|
622
|
+
throw new TypeError("planDigest is invalid");
|
|
623
|
+
}
|
|
624
|
+
const prepared = this._prepared(planDigest);
|
|
625
|
+
if (!prepared) throw new Error("prepared merge operation was not found");
|
|
626
|
+
return this.execute(prepared.record.plan);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
_result(record, recovered) {
|
|
630
|
+
return freeze({
|
|
631
|
+
authenticated: true,
|
|
632
|
+
durable: true,
|
|
633
|
+
recovered,
|
|
634
|
+
planDigest: record.planDigest,
|
|
635
|
+
envelopeDigest: record.publishResult.envelopeDigest,
|
|
636
|
+
resultDigest: record.publishResult.resultDigest,
|
|
637
|
+
verificationReceiptDigest: record.publishResult.verificationReceiptDigest,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
export function isGovernedKnowledgeMergeExecutor(value) {
|
|
643
|
+
return EXECUTORS.has(value);
|
|
644
|
+
}
|