chainlesschain 0.166.91 → 0.166.93
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 +17 -17
- package/package.json +3 -3
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DgV7xb8F.js → AIOps-oo9rE0gh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CgANpkKu.js → ActionButton-CVJVVv4i.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DnvpX7RB.js → Analytics-CUXuwmia.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-C2bHccBM.js → AppLayout-iM4PvCuY.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BIhijC9g.js → Artifacts-DKUIJbf9.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CKRjWGdp.js → Audit-C4_SzFN2.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CblYtgBE.js → BackgroundAgents-C3427uy-.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cq35b78a.js → Backup-BpEQQiog.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DcB7NoRz.js → BaseInput-C_exQomZ.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-tc3b-s7i.js → Chat-DzpkLtWa.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DX4XmTWm.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-BLD5bH5u.js → Checkbox-CxAC1CU8.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BLOsoazN.js → Codegen-wDFAGCLp.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bdr7JwIx.js → Col-BvwirhMf.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C84BsWE0.js → Community-BJuA7paY.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dzdwd04z.js → Compact-DzV35_u2.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CCG-R0EV.js → Compliance-CIDPPvr9.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BYj72SK0.js → Cowork-DyTMxP3N.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B6iKAwOf.js → Cron-PcNLjMFx.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BJ-oDC6u.js → Crosschain-B_O7ck6Z.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BnMckGLr.js → DID-CII35Me1.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cyje-gCO.js → Dashboard-DU56fkNz.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BpNlenjK.js → Dropdown-DHC8HVeJ.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BhonO7Nv.js → EmailListRenderer-oUOHFNsD.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DVoNU-Id.js → EvolutionSettings-D7RCAWNl.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-tdn-KC67.js → FamilyGuardDashboard-CGONPZxC.js} +1 -1
- package/src/assets/web-panel/assets/{Federation--EEVrHhz.js → Federation-BbDlPWcl.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cy8zr0-4.js → FormItemContext-BBJbFQQT.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BuUhpgFi.js → GenericCardRenderer-iuxAero4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Ctd3E5Pe.js → Git-Dw0prdY5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Ce7dV6aU.js → Governance-DOGqi_uV.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CD1vExIH.js → Inference-BY5oUGGj.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Dn64OdQ7.js → KnowledgeGraph-CcE2EVYX.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-PmElVRrT.js → Logs-DyfN4R5w.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BFiVKf5t.js → MarkdownRenderer-Bj62Aq0M.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-OW4jTXwx.js → Marketplace-CuuuAXUh.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BEq2Ib4x.js → McpTools-948Fithv.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Can_P2oK.js → Memory-D4PINvyy.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DJ8R-dn3.js → MobileBridge-ECKMaLzX.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B7kV9GOt.js → MobileProjects-CB5MAcvD.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BfxamolS.js → Mtc-BRzIM3HJ.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-DHtuv7av.js → MtcAudit-CGeAXJGn.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DLkLpvxc.js → Multisig-C_qJ-8K-.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-u4XtJTIt.js → NLProgramming-DAEyCn7T.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BwuuPJLS.js → Notes-DmD3MEec.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-HEeu-E9v.js → NotificationSettings-Cv4Q3VC9.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BNlpaFjH.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Yh-czs3b.js → Organization-DqAFdz6p.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DmE8mYVM.js → Overflow-8Ye9cIcE.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWVck8WN.js → P2P-755SfHoJ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DgFqekod.js → PdhVaultBrowser-CgZLiucX.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-BtJBVOHV.js → Permissions-C-vFF_rL.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-6VBObXzd.js → PersonalDataHub-Diz1oXM3.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-D222FmqY.js → Pipeline-D4kIzsZG.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bi9FMikp.js → Privacy-QKLkSAUH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bo52H47H.js → ProjectInit-I0S9o_RT.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BPkesfOc.js → ProjectSettings-DdgV3-Ho.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-GynohSFX.js → Projects-BJHHegtj.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DVdMg04n.js → Providers-uVa1zfbS.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DqJCb595.js → QrScannerModal-YLVpOChR.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-J7loQbXi.js → QuickAsk-535AYH61.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BI5aURVc.js → Recommend-C_P6eNSw.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BN2sqGvz.js → RemoteSession-EXH1SbNj.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BGOND-Fi.js → Reputation-Cxc7d3eU.js} +1 -1
- package/src/assets/web-panel/assets/{Row-77dfwaUk.js → Row-EDqJy-wS.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-FtBAxS3g.js → RssFeed-C03Xeg9_.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BaYVLFb7.js → Search-DsIga9DK.js} +1 -1
- package/src/assets/web-panel/assets/{Security-LE3Vv6ab.js → Security-DgArMFc-.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5pP-Whz.js → Services-MooDpHBP.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CLqKUVsF.js → Skeleton-B10P1Dr6.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BPjN0SX5.js → Skills-DHLHEkLl.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-14jD70kg.js → Sla-D4RT7d4g.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Dr9ij42W.js → SpeechSettings-D8u6F-LV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BzLHP7B8.js → SyncSettings-4nvNzRq8.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-YqV9b0rV.js → Tasks-CmCb8zNO.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CxxAE4PK.js → Templates-CzESIa21.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CRb3PcKJ.js → Tenant-Ch_N3p4d.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CTzPpBaP.js → Terminal-BZccUf_X.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DjFUj_hy.js → TimelineRenderer-FrKcNy_3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bbb8tPvx.js → Tokens-4xvLpXfD.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CSeWGM0W.js → Trigger-84UjyxXd.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-JgESMBo3.js → Trust-M6UtHnji.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CiObLk0T.js → UkeySign-L_xEgtCg.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CFEZaQ2x.js → VideoEditing-BLJCX9ru.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DR8ZGDNn.js → Wallet-DwL6uJCj.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DxZukvu7.js → WebAuthn-Bmn9pdzz.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CKgSZQwn.js → WorkflowEditor-DSsZ5xG1.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CTxEQE66.js → chat--FGNUaa8.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CAjKMUu3.js → colors-DeuwNdqX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BXuz49at.js → compact-item-I4XKxRFU.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CFN_Hwr9.js → createContext-RoD2p5Ba.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ctnml4IW.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BwoSBSfP.js → hasIn-BsvyddUM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CB3kVd9c.js → index-0tRU1Sv-.js} +1 -1
- package/src/assets/web-panel/assets/{index-o9DpkZKf.js → index-4xHc2WjT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmQITjMU.js → index-B8-eGLN9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY-gBSm8.js → index-BS_uqSTa.js} +1 -1
- package/src/assets/web-panel/assets/{index-F2E5RCwz.js → index-BYEVBlCl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF9lWi1o.js → index-BcBM065G.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu2P6u8m.js → index-BnrL4s-3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv7V2kg6.js → index-BrZPb0On.js} +1 -1
- package/src/assets/web-panel/assets/index-C7PN8mh1.js +1 -0
- package/src/assets/web-panel/assets/{index-DViK2bkv.js → index-CBazK4-7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmXpdcHI.js → index-CPS3zv1c.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqv_Cray.js → index-CSrZiiAs.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7kp-zRE.js → index-CVwZMt9Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0QbLlWn.js → index-CdgKZYgm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjF5BOZx.js → index-CesTu01s.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSmFby3Q.js → index-CiHlSuMl.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2o_BBjg.js → index-CsLVac9n.js} +1 -1
- package/src/assets/web-panel/assets/{index-CehdwJ_Q.js → index-D1ONyBTW.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bj4hIiLW.js → index-D4IZsKbF.js} +1 -1
- package/src/assets/web-panel/assets/{index-_ZtCyUdz.js → index-D4P4vpmv.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9yR7zqr.js → index-D6J8dz7X.js} +1 -1
- package/src/assets/web-panel/assets/{index-u9_DM3ZC.js → index-DChy2sHE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8er4W9u.js → index-DKUCl_Lk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK4ftQ4d.js → index-DRluW3_r.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2tEnBPx.js → index-DWUmhNO-.js} +1 -1
- package/src/assets/web-panel/assets/{index-IY9bd5az.js → index-DXnpVGG3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp5y7lX_.js → index-DYOpAS6-.js} +1 -1
- package/src/assets/web-panel/assets/{index-T3MTE6jB.js → index-DiH-3cR2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxunxaTw.js → index-DlEfwgzr.js} +1 -1
- package/src/assets/web-panel/assets/index-KnbBJAO-.js +1 -0
- package/src/assets/web-panel/assets/{index-DTX9CJPx.js → index-R4St_zjR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Tz5dheZa.js → index-ScgoDU9V.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmkbAADP.js → index-UWdT_lty.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bw9s2d3c.js → index-VAlor744.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN53dE_u.js → index-Wco_uvRo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpdDnZX_.js → index-ZgFED_Zd.js} +1 -1
- package/src/assets/web-panel/assets/{index-IahILygB.js → index-jaHeti4i.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cgk0YEiq.js → index-rJDabtw4.js} +1 -1
- package/src/assets/web-panel/assets/{index-t2Ch_JKn.js → index-vRiGKIP0.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BoiGJDoO.js → initDefaultProps-BHT0PacY.js} +1 -1
- package/src/assets/web-panel/assets/{motion-5eL4E0pA.js → motion-CBYsMtsC.js} +1 -1
- package/src/assets/web-panel/assets/{move-DjggDi_1.js → move-DnHfFV4K.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Ce8Vo2T3.js → mtc-parser-DfGkRYrx.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D1yOBaO2.js → omit-SjLcPQA9.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-8NLceQe8.js → pickAttrs-CCZHF4ep.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CsIdBRmQ.js → placementArrow-DjCGn2sJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-GM5NE8En.js → responsiveObserve-BCFCl2on.js} +1 -1
- package/src/assets/web-panel/assets/{slide-44yj3u49.js → slide-DsfmuIZu.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B8tqtWcX.js → statusUtils-hPKuJUia.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-NhDPBbyB.js → styleChecker-DOXKH7Kf.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C8Qz1GtN.js → useFlexGapSupport-B_G7yqio.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-ClUv4kih.js → useFs-BXOTOm2l.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BwkOVEh6.js → usePersonalDataHub-CRvie3g7.js} +1 -1
- package/src/assets/web-panel/assets/{vnode--gMF33R0.js → vnode-D9_zMmww.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DXg3TqOP.js → zoom-C4tW03qI.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +52 -0
- package/src/lib/artifact-store.js +51 -3
- package/src/lib/bounded-artifact-file-read.js +131 -0
- package/src/lib/evolution/evolution-artifact-ports.js +235 -129
- package/src/lib/evolution/evolution-eval-cohort-enrollment.js +713 -47
- package/src/lib/evolution/evolution-eval-gate.js +146 -0
- package/src/lib/evolution/evolution-eval-launch-admission.js +168 -90
- package/src/lib/evolution/evolution-eval-ledger-capture.js +50 -0
- package/src/lib/evolution/evolution-eval-readonly-audit.js +106 -0
- package/src/lib/evolution/evolution-ledger-file-backend.js +20 -0
- package/src/lib/evolution/evolution-ledger-ports.js +59 -27
- package/src/lib/evolution/evolution-ledger-v2-journal.js +55 -18
- package/src/lib/evolution/evolution-workbench-file-resources.js +19 -1
- package/src/lib/evolution/rrsi-cohort-registration.js +275 -0
- package/src/lib/evolution/rrsi-contracts.js +742 -0
- package/src/lib/evolution/rrsi-data.js +196 -0
- package/src/lib/evolution/rrsi-evaluation-adapter.js +275 -0
- package/src/lib/evolution/rrsi-evaluation-variants.js +267 -0
- package/src/lib/evolution/rrsi-group-statistics.js +553 -0
- package/src/lib/evolution/rrsi-history-ledger-adapter.js +3286 -0
- package/src/lib/evolution/rrsi-installation-route-contracts.js +275 -0
- package/src/lib/evolution/rrsi-installation-route-reader.js +282 -0
- package/src/lib/evolution/rrsi-native-batch-evidence.js +520 -0
- package/src/lib/evolution/rrsi-native-eval-row-collector.js +538 -0
- package/src/lib/evolution/rrsi-native-evaluation-batch.js +547 -0
- package/src/lib/evolution/rrsi-native-evaluation-plan.js +431 -0
- package/src/lib/evolution/rrsi-native-group-statistics-plan.js +121 -0
- package/src/lib/evolution/rrsi-native-group-statistics.js +482 -0
- package/src/lib/evolution/rrsi-native-quality-receipt-contracts.js +321 -0
- package/src/lib/evolution/rrsi-native-quality-receipt.js +256 -0
- package/src/lib/evolution/rrsi-native-statistics-protocol.js +330 -0
- package/src/lib/evolution/rrsi-observed-text-index.js +978 -0
- package/src/lib/evolution/rrsi-parent-binding.js +290 -0
- package/src/lib/evolution/rrsi-pm-execution-bridge.js +500 -0
- package/src/lib/evolution/rrsi-pm-training-mapping.js +134 -0
- package/src/lib/evolution/rrsi-preparation-contracts.js +213 -0
- package/src/lib/evolution/rrsi-registry-history-binding.js +193 -0
- package/src/lib/evolution/rrsi-registry-runtime-policy.js +648 -0
- package/src/lib/evolution/rrsi-registry-store-policy.js +1271 -0
- package/src/lib/evolution/rrsi-runtime-composition.js +79 -0
- package/src/lib/evolution/rrsi-selector.js +434 -0
- package/src/lib/evolution/rrsi-statistics-simulation.js +354 -0
- package/src/lib/evolution/rrsi-tenant-index-anchor-contracts.js +223 -0
- package/src/lib/evolution/rrsi-tenant-index-anchor-history.js +157 -0
- package/src/lib/evolution/skill-candidate-registry.js +216 -29
- package/src/lib/evolution/skill-registry-maintenance.js +80 -0
- package/src/lib/evolution/skill-registry-writer-control.js +138 -0
- package/src/lib/evolution/skill-release-registry.js +414 -169
- package/src/lib/formal-quality-eval-runtime.js +2 -14
- package/src/lib/goal-store.js +225 -16
- package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +291 -30
- package/src/lib/record-replay/skill-recorder.js +38 -3
- package/src/lib/remote-read-loop-guard.js +227 -24
- package/src/lib/scheduler-kernel/authority-resolver.js +12 -163
- package/src/lib/scheduler-kernel/contract.js +27 -414
- package/src/lib/scheduler-kernel/runtime.js +21 -823
- package/src/lib/scheduler-kernel/service.js +11 -328
- package/src/lib/scheduler-kernel/source-locator-path.js +7 -142
- package/src/lib/scheduler-kernel/store.js +67 -5931
- package/src/lib/secure-fs.js +16 -1314
- package/src/lib/task-progress-tracker.js +6 -1
- package/src/lib/with-file-lock.js +122 -20
- package/src/runtime/agent-core.js +71 -23
- package/src/assets/web-panel/assets/ChatBubbleRenderer-fcc_Tvqu.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BtvN-Qwh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +0 -1
- package/src/assets/web-panel/assets/index-CCsRfd0k.js +0 -1
- package/src/assets/web-panel/assets/index-CsmiZIQ4.js +0 -1
|
@@ -1,832 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
RUNTIME_CONTROL_SCHEMA_VERSION,
|
|
5
|
-
RUNTIME_CONTROL_SAFE_POINTS,
|
|
6
|
-
RUNTIME_PAUSE_RESUME,
|
|
7
|
-
SchedulerKernelError,
|
|
8
|
-
canonicalJson,
|
|
9
|
-
normalizeEpochMs,
|
|
10
|
-
normalizeIdentifier,
|
|
11
|
-
normalizeJson,
|
|
12
|
-
normalizeRuntimeControlCapability,
|
|
13
|
-
} from "./contract.js";
|
|
1
|
+
// CLI composition retains the existing Graph mode and authority defaults.
|
|
2
|
+
// The host-neutral runtime never imports CLI Graph or rollout-store modules.
|
|
3
|
+
import schedulerRuntime from "@chainlesschain/session-core/scheduler-runtime";
|
|
14
4
|
import {
|
|
15
5
|
SchedulerOccurrenceGraphAuthority,
|
|
16
6
|
schedulerGraphAuthorityMode,
|
|
17
7
|
} from "./graph-authority-adapter.js";
|
|
18
8
|
|
|
19
|
-
export const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
function runtimeError(code, message, details = undefined, cause = undefined) {
|
|
39
|
-
return new SchedulerKernelError(
|
|
40
|
-
code,
|
|
41
|
-
message,
|
|
42
|
-
details,
|
|
43
|
-
cause ? { cause } : undefined,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function assertStore(store) {
|
|
48
|
-
const required = [
|
|
49
|
-
"claimNext",
|
|
50
|
-
"claimOccurrence",
|
|
51
|
-
"getJob",
|
|
52
|
-
"getOccurrence",
|
|
53
|
-
"renew",
|
|
54
|
-
"settle",
|
|
55
|
-
];
|
|
56
|
-
if (
|
|
57
|
-
!store ||
|
|
58
|
-
required.some((method) => typeof store[method] !== "function")
|
|
59
|
-
) {
|
|
60
|
-
throw runtimeError(
|
|
61
|
-
"SCHEDULER_RUNTIME_INVALID_STORE",
|
|
62
|
-
"Scheduler runtime requires a compatible scheduler store",
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
return store;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function normalizeLeaseMs(value = DEFAULT_RUNTIME_LEASE_MS) {
|
|
69
|
-
if (!Number.isSafeInteger(value) || value < MIN_RUNTIME_LEASE_MS) {
|
|
70
|
-
throw runtimeError(
|
|
71
|
-
"SCHEDULER_RUNTIME_INVALID_LEASE",
|
|
72
|
-
`leaseMs must be an integer >= ${MIN_RUNTIME_LEASE_MS}`,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
return value;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function normalizeRenewInterval(value, leaseMs) {
|
|
79
|
-
const interval =
|
|
80
|
-
value === undefined ? Math.max(250, Math.floor(leaseMs / 3)) : value;
|
|
81
|
-
if (!Number.isSafeInteger(interval) || interval < 1 || interval >= leaseMs) {
|
|
82
|
-
throw runtimeError(
|
|
83
|
-
"SCHEDULER_RUNTIME_INVALID_RENEW_INTERVAL",
|
|
84
|
-
"renewIntervalMs must be a positive integer smaller than leaseMs",
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
return interval;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function normalizeRunLimit(value = DEFAULT_RUN_LIMIT) {
|
|
91
|
-
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_RUN_LIMIT) {
|
|
92
|
-
throw runtimeError(
|
|
93
|
-
"SCHEDULER_RUNTIME_INVALID_LIMIT",
|
|
94
|
-
`limit must be an integer between 1 and ${MAX_RUN_LIMIT}`,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
return value;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function normalizeAdapter(adapter) {
|
|
101
|
-
if (!adapter || typeof adapter !== "object" || Array.isArray(adapter)) {
|
|
102
|
-
throw runtimeError(
|
|
103
|
-
"SCHEDULER_RUNTIME_INVALID_ADAPTER",
|
|
104
|
-
"Scheduler adapter must be an object",
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
const kind = normalizeIdentifier(adapter.kind, "adapter.kind", {
|
|
108
|
-
maxLength: 128,
|
|
109
|
-
});
|
|
110
|
-
if (typeof adapter.execute !== "function") {
|
|
111
|
-
throw runtimeError(
|
|
112
|
-
"SCHEDULER_RUNTIME_INVALID_ADAPTER",
|
|
113
|
-
`Scheduler adapter must implement execute(): ${kind}`,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
const runtimeControl = normalizeRuntimeControlCapability(
|
|
117
|
-
adapter.runtimeControl,
|
|
118
|
-
);
|
|
119
|
-
if (
|
|
120
|
-
runtimeControl.safePoints.includes(
|
|
121
|
-
RUNTIME_CONTROL_SAFE_POINTS.ADAPTER_CHECKPOINT,
|
|
122
|
-
) &&
|
|
123
|
-
typeof adapter.resume !== "function"
|
|
124
|
-
) {
|
|
125
|
-
throw runtimeError(
|
|
126
|
-
"SCHEDULER_RUNTIME_INVALID_ADAPTER",
|
|
127
|
-
`Scheduler adapter must implement resume() for adapter checkpoints: ${kind}`,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
return { kind, adapter, runtimeControl };
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function normalizeAdapters(adapters = []) {
|
|
134
|
-
const map = new Map();
|
|
135
|
-
const values = adapters instanceof Map ? adapters.values() : adapters;
|
|
136
|
-
if (!values || typeof values[Symbol.iterator] !== "function") {
|
|
137
|
-
throw runtimeError(
|
|
138
|
-
"SCHEDULER_RUNTIME_INVALID_ADAPTER",
|
|
139
|
-
"adapters must be iterable",
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
for (const value of values) {
|
|
143
|
-
const { kind, adapter } = normalizeAdapter(value);
|
|
144
|
-
if (map.has(kind)) {
|
|
145
|
-
throw runtimeError(
|
|
146
|
-
"SCHEDULER_RUNTIME_DUPLICATE_ADAPTER",
|
|
147
|
-
`Scheduler adapter is registered more than once: ${kind}`,
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
map.set(kind, adapter);
|
|
151
|
-
}
|
|
152
|
-
return map;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function safeError(error, fallbackCode = "execution_failed") {
|
|
156
|
-
const code =
|
|
157
|
-
typeof error?.code === "string" && error.code.trim()
|
|
158
|
-
? error.code.trim().slice(0, 128)
|
|
159
|
-
: fallbackCode;
|
|
160
|
-
const message =
|
|
161
|
-
typeof error?.message === "string" && error.message
|
|
162
|
-
? error.message.slice(0, 2_000)
|
|
163
|
-
: String(error ?? "Execution failed").slice(0, 2_000);
|
|
164
|
-
let details;
|
|
165
|
-
try {
|
|
166
|
-
if (error?.details !== undefined) {
|
|
167
|
-
details = normalizeJson(error.details, "runtime.error.details");
|
|
168
|
-
}
|
|
169
|
-
} catch {
|
|
170
|
-
details = { omitted: "invalid_error_details" };
|
|
171
|
-
}
|
|
172
|
-
const base = {
|
|
173
|
-
code,
|
|
174
|
-
message,
|
|
175
|
-
...(typeof error?.name === "string"
|
|
176
|
-
? { name: error.name.slice(0, 128) }
|
|
177
|
-
: {}),
|
|
178
|
-
};
|
|
179
|
-
try {
|
|
180
|
-
return normalizeJson(
|
|
181
|
-
{ ...base, ...(details === undefined ? {} : { details }) },
|
|
182
|
-
"runtime.error",
|
|
183
|
-
);
|
|
184
|
-
} catch {
|
|
185
|
-
return normalizeJson(
|
|
186
|
-
{ ...base, details: { omitted: "error_details_too_large" } },
|
|
187
|
-
"runtime.error",
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function executionPolicy(error, adapter, context) {
|
|
193
|
-
let policy = null;
|
|
194
|
-
if (typeof adapter?.classifyError === "function") {
|
|
195
|
-
policy = adapter.classifyError(error, context);
|
|
196
|
-
}
|
|
197
|
-
if (policy !== null && policy !== undefined) {
|
|
198
|
-
if (typeof policy !== "object" || Array.isArray(policy)) {
|
|
199
|
-
throw runtimeError(
|
|
200
|
-
"SCHEDULER_RUNTIME_INVALID_ERROR_POLICY",
|
|
201
|
-
"adapter.classifyError() must return an object",
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
return {
|
|
205
|
-
retryable: policy.retryable !== false,
|
|
206
|
-
...(policy.retryAt === undefined
|
|
207
|
-
? {}
|
|
208
|
-
: { retryAt: normalizeEpochMs(policy.retryAt, "retryAt") }),
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
return {
|
|
212
|
-
retryable: error?.retryable !== false,
|
|
213
|
-
...(error?.retryAt === undefined
|
|
214
|
-
? {}
|
|
215
|
-
: { retryAt: normalizeEpochMs(error.retryAt, "retryAt") }),
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function createLinkedAbortController(signal) {
|
|
220
|
-
const controller = new AbortController();
|
|
221
|
-
const abort = () => controller.abort(signal?.reason);
|
|
222
|
-
if (signal?.aborted) abort();
|
|
223
|
-
else signal?.addEventListener?.("abort", abort, { once: true });
|
|
224
|
-
return {
|
|
225
|
-
controller,
|
|
226
|
-
dispose() {
|
|
227
|
-
signal?.removeEventListener?.("abort", abort);
|
|
228
|
-
},
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function settledResult(occurrence, extra = {}) {
|
|
233
|
-
return {
|
|
234
|
-
status: occurrence.status,
|
|
235
|
-
occurrence,
|
|
236
|
-
result: occurrence.result,
|
|
237
|
-
error: occurrence.lastError,
|
|
238
|
-
...extra,
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Host-owned execution service for scheduler occurrences.
|
|
244
|
-
*
|
|
245
|
-
* The runtime is deliberately stricter than the SQLite store: it resolves the
|
|
246
|
-
* exact job revision, requires an explicit authorization decision, selects a
|
|
247
|
-
* registered adapter, renews the durable lease while the adapter is running,
|
|
248
|
-
* and settles only under the same owner/fence token. Adapters receive the
|
|
249
|
-
* occurrence snapshots, never mutable host-side schedule definitions by
|
|
250
|
-
* implication.
|
|
251
|
-
*/
|
|
252
|
-
export class SchedulerRuntime {
|
|
253
|
-
constructor({
|
|
254
|
-
store,
|
|
255
|
-
adapters = [],
|
|
256
|
-
authorize,
|
|
257
|
-
ownerId = `scheduler-runtime:${process.pid}:${randomUUID()}`,
|
|
258
|
-
leaseMs = DEFAULT_RUNTIME_LEASE_MS,
|
|
259
|
-
renewIntervalMs,
|
|
260
|
-
setIntervalFn = setInterval,
|
|
261
|
-
clearIntervalFn = clearInterval,
|
|
262
|
-
graphAuthority = undefined,
|
|
263
|
-
graphAuthorityMode = undefined,
|
|
264
|
-
} = {}) {
|
|
265
|
-
this.store = assertStore(store);
|
|
266
|
-
this.adapters = normalizeAdapters(adapters);
|
|
267
|
-
if (typeof authorize !== "function") {
|
|
268
|
-
throw runtimeError(
|
|
269
|
-
"SCHEDULER_RUNTIME_AUTHORIZER_REQUIRED",
|
|
270
|
-
"Scheduler runtime requires an explicit authorize() callback",
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
this.authorize = authorize;
|
|
274
|
-
this.ownerId = normalizeIdentifier(ownerId, "ownerId");
|
|
275
|
-
this.leaseMs = normalizeLeaseMs(leaseMs);
|
|
276
|
-
this.renewIntervalMs = normalizeRenewInterval(
|
|
277
|
-
renewIntervalMs,
|
|
278
|
-
this.leaseMs,
|
|
279
|
-
);
|
|
280
|
-
if (
|
|
281
|
-
typeof setIntervalFn !== "function" ||
|
|
282
|
-
typeof clearIntervalFn !== "function"
|
|
283
|
-
) {
|
|
284
|
-
throw runtimeError(
|
|
285
|
-
"SCHEDULER_RUNTIME_INVALID_TIMER",
|
|
286
|
-
"Scheduler runtime requires timer functions",
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
this.setIntervalFn = setIntervalFn;
|
|
290
|
-
this.clearIntervalFn = clearIntervalFn;
|
|
291
|
-
const resolvedGraphMode =
|
|
292
|
-
graphAuthorityMode || schedulerGraphAuthorityMode();
|
|
293
|
-
this.graphAuthority =
|
|
294
|
-
graphAuthority === undefined
|
|
295
|
-
? new SchedulerOccurrenceGraphAuthority({
|
|
296
|
-
mode: resolvedGraphMode,
|
|
297
|
-
})
|
|
298
|
-
: graphAuthority;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
registerAdapter(adapter) {
|
|
302
|
-
const normalized = normalizeAdapter(adapter);
|
|
303
|
-
if (this.adapters.has(normalized.kind)) {
|
|
304
|
-
throw runtimeError(
|
|
305
|
-
"SCHEDULER_RUNTIME_DUPLICATE_ADAPTER",
|
|
306
|
-
`Scheduler adapter is registered more than once: ${normalized.kind}`,
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
this.adapters.set(normalized.kind, normalized.adapter);
|
|
310
|
-
return this;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
runtimeControlFor(jobKind) {
|
|
314
|
-
const kind = normalizeIdentifier(jobKind, "jobKind", { maxLength: 128 });
|
|
315
|
-
const adapter = this.adapters.get(kind);
|
|
316
|
-
return adapter
|
|
317
|
-
? normalizeRuntimeControlCapability(adapter.runtimeControl)
|
|
318
|
-
: normalizeRuntimeControlCapability();
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
async _settleRejected(occurrence, error, retryable = false) {
|
|
322
|
-
const settled = this.store.settle({
|
|
323
|
-
occurrenceId: occurrence.id,
|
|
324
|
-
ownerId: this.ownerId,
|
|
325
|
-
fence: occurrence.fence,
|
|
326
|
-
outcome: "failed",
|
|
327
|
-
error: safeError(error, "scheduler_rejected"),
|
|
328
|
-
retryable,
|
|
329
|
-
});
|
|
330
|
-
return settledResult(settled);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
async _executeClaim(occurrence, { signal } = {}) {
|
|
334
|
-
const job = this.store.getJob(occurrence.jobId);
|
|
335
|
-
if (!job) {
|
|
336
|
-
return this._settleRejected(
|
|
337
|
-
occurrence,
|
|
338
|
-
runtimeError(
|
|
339
|
-
"SCHEDULER_RUNTIME_JOB_MISSING",
|
|
340
|
-
`Scheduler job disappeared before execution: ${occurrence.jobId}`,
|
|
341
|
-
),
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
if (job.revision !== occurrence.jobRevision) {
|
|
345
|
-
return this._settleRejected(
|
|
346
|
-
occurrence,
|
|
347
|
-
runtimeError(
|
|
348
|
-
"SCHEDULER_RUNTIME_STALE_REVISION",
|
|
349
|
-
`Occurrence references stale job revision: ${occurrence.id}`,
|
|
350
|
-
{
|
|
351
|
-
occurrenceRevision: occurrence.jobRevision,
|
|
352
|
-
currentRevision: job.revision,
|
|
353
|
-
},
|
|
354
|
-
),
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
const adapter = this.adapters.get(job.kind);
|
|
358
|
-
if (!adapter) {
|
|
359
|
-
return this._settleRejected(
|
|
360
|
-
occurrence,
|
|
361
|
-
runtimeError(
|
|
362
|
-
"SCHEDULER_RUNTIME_ADAPTER_MISSING",
|
|
363
|
-
`No scheduler adapter is registered for job kind: ${job.kind}`,
|
|
364
|
-
),
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
const runtimeControl = normalizeRuntimeControlCapability(
|
|
368
|
-
adapter.runtimeControl,
|
|
369
|
-
);
|
|
370
|
-
|
|
371
|
-
let decision;
|
|
372
|
-
let allowed = false;
|
|
373
|
-
let deniedReason = "not_allowed";
|
|
374
|
-
try {
|
|
375
|
-
decision = await this.authorize({ job, occurrence, signal });
|
|
376
|
-
allowed =
|
|
377
|
-
decision !== null &&
|
|
378
|
-
typeof decision === "object" &&
|
|
379
|
-
decision.allowed === true;
|
|
380
|
-
if (typeof decision?.reason === "string") {
|
|
381
|
-
deniedReason = decision.reason.slice(0, 256);
|
|
382
|
-
}
|
|
383
|
-
} catch (error) {
|
|
384
|
-
const authError = runtimeError(
|
|
385
|
-
"SCHEDULER_RUNTIME_AUTHORIZATION_UNAVAILABLE",
|
|
386
|
-
"Scheduler authorization could not be completed",
|
|
387
|
-
undefined,
|
|
388
|
-
error,
|
|
389
|
-
);
|
|
390
|
-
authError.retryable = true;
|
|
391
|
-
return this._settleRejected(occurrence, authError, true);
|
|
392
|
-
}
|
|
393
|
-
if (!allowed) {
|
|
394
|
-
return this._settleRejected(
|
|
395
|
-
occurrence,
|
|
396
|
-
runtimeError(
|
|
397
|
-
"SCHEDULER_RUNTIME_AUTHORIZATION_DENIED",
|
|
398
|
-
"Scheduler occurrence was denied by the authority resolver",
|
|
399
|
-
{ reason: deniedReason },
|
|
400
|
-
),
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Authorization may involve remote policy evaluation. Revalidate ownership
|
|
405
|
-
// immediately before any adapter side effect so an expired/reclaimed claim
|
|
406
|
-
// cannot execute under a stale fence.
|
|
407
|
-
occurrence = this.store.renew({
|
|
408
|
-
occurrenceId: occurrence.id,
|
|
409
|
-
ownerId: this.ownerId,
|
|
410
|
-
fence: occurrence.fence,
|
|
411
|
-
leaseMs: this.leaseMs,
|
|
9
|
+
export const {
|
|
10
|
+
DEFAULT_RUNTIME_LEASE_MS,
|
|
11
|
+
MIN_RUNTIME_LEASE_MS,
|
|
12
|
+
DEFAULT_RUN_LIMIT,
|
|
13
|
+
MAX_RUN_LIMIT,
|
|
14
|
+
} = schedulerRuntime;
|
|
15
|
+
|
|
16
|
+
export class SchedulerRuntime extends schedulerRuntime.SchedulerRuntime {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
const mode = options.graphAuthorityMode || schedulerGraphAuthorityMode();
|
|
19
|
+
const authority =
|
|
20
|
+
options.graphAuthority === undefined
|
|
21
|
+
? new SchedulerOccurrenceGraphAuthority({ mode })
|
|
22
|
+
: options.graphAuthority;
|
|
23
|
+
super({
|
|
24
|
+
...options,
|
|
25
|
+
graphAuthority: authority,
|
|
26
|
+
graphAuthorityMode: authority?.mode ?? mode,
|
|
412
27
|
});
|
|
413
|
-
|
|
414
|
-
const linked = createLinkedAbortController(signal);
|
|
415
|
-
if (linked.controller.signal.aborted) {
|
|
416
|
-
linked.dispose();
|
|
417
|
-
const aborted = runtimeError(
|
|
418
|
-
"SCHEDULER_RUNTIME_ABORTED",
|
|
419
|
-
"Scheduler occurrence was aborted before adapter execution",
|
|
420
|
-
);
|
|
421
|
-
aborted.retryable = true;
|
|
422
|
-
return this._settleRejected(occurrence, aborted, true);
|
|
423
|
-
}
|
|
424
|
-
const readBoundControl = (state) => {
|
|
425
|
-
if (typeof this.store.getOccurrenceControl !== "function") return null;
|
|
426
|
-
const control = this.store.getOccurrenceControl(occurrence.id);
|
|
427
|
-
if (control?.state !== state) return null;
|
|
428
|
-
if (
|
|
429
|
-
runtimeControl.pauseResume !== RUNTIME_PAUSE_RESUME.CHECKPOINT_V1 ||
|
|
430
|
-
canonicalJson(control.capability, "runtimeControl.persisted") !==
|
|
431
|
-
canonicalJson(runtimeControl, "runtimeControl.adapter")
|
|
432
|
-
) {
|
|
433
|
-
throw runtimeError(
|
|
434
|
-
"SCHEDULER_RUNTIME_CONTROL_CAPABILITY_MISMATCH",
|
|
435
|
-
`Scheduler runtime-control evidence no longer matches adapter capability: ${occurrence.id}`,
|
|
436
|
-
{
|
|
437
|
-
capabilityDigest: control.capabilityDigest,
|
|
438
|
-
adapterPauseResume: runtimeControl.pauseResume,
|
|
439
|
-
},
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
if (control.expectedFence !== occurrence.fence) {
|
|
443
|
-
throw runtimeError(
|
|
444
|
-
"SCHEDULER_RUNTIME_CONTROL_FENCE_MISMATCH",
|
|
445
|
-
`Scheduler runtime control is not bound to this claim: ${occurrence.id}`,
|
|
446
|
-
{
|
|
447
|
-
expectedFence: control.expectedFence,
|
|
448
|
-
actualFence: occurrence.fence,
|
|
449
|
-
},
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
return control;
|
|
453
|
-
};
|
|
454
|
-
const readPendingPause = () => readBoundControl("pause_requested");
|
|
455
|
-
const readResumingControl = () => {
|
|
456
|
-
const control = readBoundControl("resumed");
|
|
457
|
-
if (!control) return null;
|
|
458
|
-
const checkpoint = control.checkpoint;
|
|
459
|
-
if (
|
|
460
|
-
!checkpoint ||
|
|
461
|
-
checkpoint.schemaVersion !== RUNTIME_CONTROL_SCHEMA_VERSION ||
|
|
462
|
-
!Object.values(RUNTIME_CONTROL_SAFE_POINTS).includes(
|
|
463
|
-
checkpoint.safePoint,
|
|
464
|
-
) ||
|
|
465
|
-
!Object.hasOwn(checkpoint, "data") ||
|
|
466
|
-
!runtimeControl.safePoints.includes(checkpoint.safePoint)
|
|
467
|
-
) {
|
|
468
|
-
throw runtimeError(
|
|
469
|
-
"SCHEDULER_RUNTIME_RESUME_CHECKPOINT_INVALID",
|
|
470
|
-
`Scheduler resume checkpoint is invalid for adapter: ${occurrence.id}`,
|
|
471
|
-
);
|
|
472
|
-
}
|
|
473
|
-
return control;
|
|
474
|
-
};
|
|
475
|
-
const acknowledgePause = (control, safePoint, checkpoint) => {
|
|
476
|
-
if (typeof this.store.ackOccurrencePause !== "function") {
|
|
477
|
-
throw runtimeError(
|
|
478
|
-
"SCHEDULER_RUNTIME_CONTROL_STORE_UNSUPPORTED",
|
|
479
|
-
"Scheduler store cannot acknowledge durable runtime controls",
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
const acknowledged = this.store.ackOccurrencePause({
|
|
483
|
-
occurrenceId: occurrence.id,
|
|
484
|
-
ownerId: this.ownerId,
|
|
485
|
-
fence: occurrence.fence,
|
|
486
|
-
requestId: control.pauseRequestId,
|
|
487
|
-
expectedRevision: control.revision,
|
|
488
|
-
safePoint,
|
|
489
|
-
checkpoint,
|
|
490
|
-
});
|
|
491
|
-
return {
|
|
492
|
-
status: "paused",
|
|
493
|
-
occurrence: acknowledged.occurrence,
|
|
494
|
-
control: acknowledged.control,
|
|
495
|
-
result: null,
|
|
496
|
-
error: null,
|
|
497
|
-
};
|
|
498
|
-
};
|
|
499
|
-
let pendingPause;
|
|
500
|
-
let resumingControl;
|
|
501
|
-
try {
|
|
502
|
-
pendingPause = readPendingPause();
|
|
503
|
-
resumingControl = readResumingControl();
|
|
504
|
-
} catch (error) {
|
|
505
|
-
linked.dispose();
|
|
506
|
-
return this._settleRejected(occurrence, error, false);
|
|
507
|
-
}
|
|
508
|
-
if (
|
|
509
|
-
pendingPause &&
|
|
510
|
-
runtimeControl.safePoints.includes(
|
|
511
|
-
RUNTIME_CONTROL_SAFE_POINTS.BEFORE_EXECUTE,
|
|
512
|
-
)
|
|
513
|
-
) {
|
|
514
|
-
linked.dispose();
|
|
515
|
-
return acknowledgePause(
|
|
516
|
-
pendingPause,
|
|
517
|
-
RUNTIME_CONTROL_SAFE_POINTS.BEFORE_EXECUTE,
|
|
518
|
-
{ adapterStarted: false },
|
|
519
|
-
);
|
|
520
|
-
}
|
|
521
|
-
let leaseError = null;
|
|
522
|
-
let renewing = false;
|
|
523
|
-
const renew = () => {
|
|
524
|
-
if (renewing || leaseError || linked.controller.signal.aborted) return;
|
|
525
|
-
renewing = true;
|
|
526
|
-
try {
|
|
527
|
-
this.store.renew({
|
|
528
|
-
occurrenceId: occurrence.id,
|
|
529
|
-
ownerId: this.ownerId,
|
|
530
|
-
fence: occurrence.fence,
|
|
531
|
-
leaseMs: this.leaseMs,
|
|
532
|
-
});
|
|
533
|
-
} catch (error) {
|
|
534
|
-
leaseError = error;
|
|
535
|
-
linked.controller.abort(error);
|
|
536
|
-
} finally {
|
|
537
|
-
renewing = false;
|
|
538
|
-
}
|
|
539
|
-
};
|
|
540
|
-
let timer;
|
|
541
|
-
try {
|
|
542
|
-
timer = this.setIntervalFn(renew, this.renewIntervalMs);
|
|
543
|
-
} catch (error) {
|
|
544
|
-
linked.dispose();
|
|
545
|
-
return this._settleRejected(
|
|
546
|
-
occurrence,
|
|
547
|
-
runtimeError(
|
|
548
|
-
"SCHEDULER_RUNTIME_TIMER_FAILED",
|
|
549
|
-
"Scheduler lease-renewal timer could not be started",
|
|
550
|
-
undefined,
|
|
551
|
-
error,
|
|
552
|
-
),
|
|
553
|
-
true,
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
|
-
timer?.unref?.();
|
|
557
|
-
const context = {
|
|
558
|
-
job,
|
|
559
|
-
occurrence,
|
|
560
|
-
authority: occurrence.authority,
|
|
561
|
-
decision,
|
|
562
|
-
adjudication:
|
|
563
|
-
typeof this.store.getOccurrenceAdjudication === "function"
|
|
564
|
-
? this.store.getOccurrenceAdjudication(occurrence.id)
|
|
565
|
-
: null,
|
|
566
|
-
signal: linked.controller.signal,
|
|
567
|
-
renewLease: renew,
|
|
568
|
-
runtimeControl,
|
|
569
|
-
resumeCheckpoint: resumingControl?.checkpoint ?? null,
|
|
570
|
-
checkpoint: (data = null) => {
|
|
571
|
-
if (
|
|
572
|
-
!runtimeControl.safePoints.includes(
|
|
573
|
-
RUNTIME_CONTROL_SAFE_POINTS.ADAPTER_CHECKPOINT,
|
|
574
|
-
)
|
|
575
|
-
) {
|
|
576
|
-
return { pauseRequested: false };
|
|
577
|
-
}
|
|
578
|
-
const control = readPendingPause();
|
|
579
|
-
if (!control) return { pauseRequested: false };
|
|
580
|
-
throw new SchedulerPauseSignal(control, data);
|
|
581
|
-
},
|
|
582
|
-
};
|
|
583
|
-
const invokeAdapter = () =>
|
|
584
|
-
resumingControl?.checkpoint.safePoint ===
|
|
585
|
-
RUNTIME_CONTROL_SAFE_POINTS.ADAPTER_CHECKPOINT
|
|
586
|
-
? adapter.resume(context, resumingControl.checkpoint)
|
|
587
|
-
: adapter.execute(context);
|
|
588
|
-
let graphClaim = null;
|
|
589
|
-
let graphAuthorityMode = "legacy";
|
|
590
|
-
try {
|
|
591
|
-
let result;
|
|
592
|
-
graphClaim = this.graphAuthority?.begin(context) || null;
|
|
593
|
-
graphAuthorityMode =
|
|
594
|
-
graphClaim?.authorityMode || this.graphAuthority?.mode || "legacy";
|
|
595
|
-
if (graphClaim?.alreadySettled) {
|
|
596
|
-
result = graphClaim.result;
|
|
597
|
-
} else if (context.adjudication?.status === "pending") {
|
|
598
|
-
const allowedAttempts =
|
|
599
|
-
context.adjudication.decision === "confirmed_applied"
|
|
600
|
-
? [
|
|
601
|
-
context.adjudication.expectedAttempt + 1,
|
|
602
|
-
context.adjudication.expectedAttempt + 2,
|
|
603
|
-
]
|
|
604
|
-
: [context.adjudication.expectedAttempt + 1];
|
|
605
|
-
if (
|
|
606
|
-
!allowedAttempts.includes(occurrence.attempt) ||
|
|
607
|
-
context.adjudication.expectedFence >= occurrence.fence
|
|
608
|
-
) {
|
|
609
|
-
throw runtimeError(
|
|
610
|
-
"SCHEDULER_RUNTIME_ADJUDICATION_BINDING_MISMATCH",
|
|
611
|
-
`Scheduler adjudication is not bound to this claim: ${occurrence.id}`,
|
|
612
|
-
);
|
|
613
|
-
}
|
|
614
|
-
if (typeof adapter.adjudicate !== "function") {
|
|
615
|
-
throw runtimeError(
|
|
616
|
-
"SCHEDULER_RUNTIME_ADJUDICATION_UNSUPPORTED",
|
|
617
|
-
`Scheduler adapter cannot apply an outcome-unknown adjudication: ${job.kind}`,
|
|
618
|
-
);
|
|
619
|
-
}
|
|
620
|
-
const resolution = await adapter.adjudicate(context);
|
|
621
|
-
if (
|
|
622
|
-
context.adjudication.decision === "confirmed_applied" &&
|
|
623
|
-
resolution?.settled !== true
|
|
624
|
-
) {
|
|
625
|
-
throw runtimeError(
|
|
626
|
-
"SCHEDULER_RUNTIME_ADJUDICATION_INVALID",
|
|
627
|
-
"confirmed_applied adjudication must settle without replay",
|
|
628
|
-
);
|
|
629
|
-
}
|
|
630
|
-
if (
|
|
631
|
-
context.adjudication.decision === "confirmed_not_applied" &&
|
|
632
|
-
resolution?.continue !== true
|
|
633
|
-
) {
|
|
634
|
-
throw runtimeError(
|
|
635
|
-
"SCHEDULER_RUNTIME_ADJUDICATION_INVALID",
|
|
636
|
-
"confirmed_not_applied adjudication must explicitly authorize one execution",
|
|
637
|
-
);
|
|
638
|
-
}
|
|
639
|
-
result =
|
|
640
|
-
resolution?.settled === true
|
|
641
|
-
? (resolution.result ?? {
|
|
642
|
-
adjudicationRequestId: context.adjudication.requestId,
|
|
643
|
-
decision: context.adjudication.decision,
|
|
644
|
-
})
|
|
645
|
-
: await invokeAdapter();
|
|
646
|
-
} else {
|
|
647
|
-
result = await invokeAdapter();
|
|
648
|
-
}
|
|
649
|
-
if (leaseError) throw leaseError;
|
|
650
|
-
if (linked.controller.signal.aborted) {
|
|
651
|
-
const aborted = runtimeError(
|
|
652
|
-
"SCHEDULER_RUNTIME_ABORTED",
|
|
653
|
-
"Scheduler occurrence was aborted before settlement",
|
|
654
|
-
);
|
|
655
|
-
aborted.retryable = true;
|
|
656
|
-
throw aborted;
|
|
657
|
-
}
|
|
658
|
-
if (graphClaim && !graphClaim.alreadySettled) {
|
|
659
|
-
try {
|
|
660
|
-
const graphProjection = this.graphAuthority.settleSuccess(
|
|
661
|
-
context,
|
|
662
|
-
result,
|
|
663
|
-
);
|
|
664
|
-
if (graphAuthorityMode === "canonical") {
|
|
665
|
-
result =
|
|
666
|
-
result && typeof result === "object" && !Array.isArray(result)
|
|
667
|
-
? { ...result, graphAuthority: graphProjection }
|
|
668
|
-
: { value: result ?? null, graphAuthority: graphProjection };
|
|
669
|
-
}
|
|
670
|
-
} catch (graphError) {
|
|
671
|
-
if (graphAuthorityMode === "canonical") throw graphError;
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
const settled = this.store.settle({
|
|
675
|
-
occurrenceId: occurrence.id,
|
|
676
|
-
ownerId: this.ownerId,
|
|
677
|
-
fence: occurrence.fence,
|
|
678
|
-
outcome: "succeeded",
|
|
679
|
-
result: result ?? null,
|
|
680
|
-
...(context.adjudication?.status === "pending"
|
|
681
|
-
? { adjudicationRequestId: context.adjudication.requestId }
|
|
682
|
-
: {}),
|
|
683
|
-
});
|
|
684
|
-
return settledResult(settled);
|
|
685
|
-
} catch (error) {
|
|
686
|
-
if (leaseError) throw leaseError;
|
|
687
|
-
if (error instanceof SchedulerPauseSignal) {
|
|
688
|
-
if (graphClaim && !graphClaim.alreadySettled) {
|
|
689
|
-
const knownPause = new Error("scheduler paused at a safe point");
|
|
690
|
-
knownPause.outcomeKnown = true;
|
|
691
|
-
try {
|
|
692
|
-
this.graphAuthority.settleFailure(context, knownPause);
|
|
693
|
-
} catch (graphError) {
|
|
694
|
-
if (graphAuthorityMode === "canonical") throw graphError;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
return acknowledgePause(
|
|
698
|
-
error.control,
|
|
699
|
-
RUNTIME_CONTROL_SAFE_POINTS.ADAPTER_CHECKPOINT,
|
|
700
|
-
error.checkpoint,
|
|
701
|
-
);
|
|
702
|
-
}
|
|
703
|
-
let policy;
|
|
704
|
-
let settlementError = error;
|
|
705
|
-
if (graphClaim && !graphClaim.alreadySettled) {
|
|
706
|
-
try {
|
|
707
|
-
const graphProjection = this.graphAuthority.settleFailure(
|
|
708
|
-
context,
|
|
709
|
-
error,
|
|
710
|
-
);
|
|
711
|
-
if (
|
|
712
|
-
graphAuthorityMode === "canonical" &&
|
|
713
|
-
graphProjection?.status === "reconciliation_required"
|
|
714
|
-
) {
|
|
715
|
-
settlementError = runtimeError(
|
|
716
|
-
"CC_GRAPH_RECONCILIATION_REQUIRED",
|
|
717
|
-
"Scheduler adapter effect outcome is unknown and requires Graph reconciliation",
|
|
718
|
-
{ graphRunId: graphProjection.id },
|
|
719
|
-
error,
|
|
720
|
-
);
|
|
721
|
-
settlementError.retryable = false;
|
|
722
|
-
}
|
|
723
|
-
} catch (graphError) {
|
|
724
|
-
if (graphAuthorityMode === "canonical") {
|
|
725
|
-
settlementError = graphError;
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
try {
|
|
730
|
-
policy =
|
|
731
|
-
settlementError?.code === "CC_GRAPH_RECONCILIATION_REQUIRED"
|
|
732
|
-
? { retryable: false }
|
|
733
|
-
: executionPolicy(settlementError, adapter, context);
|
|
734
|
-
} catch (classificationError) {
|
|
735
|
-
settlementError = runtimeError(
|
|
736
|
-
"SCHEDULER_RUNTIME_ERROR_POLICY_FAILED",
|
|
737
|
-
"Scheduler adapter error policy failed",
|
|
738
|
-
undefined,
|
|
739
|
-
classificationError,
|
|
740
|
-
);
|
|
741
|
-
policy = { retryable: false };
|
|
742
|
-
}
|
|
743
|
-
const settled = this.store.settle({
|
|
744
|
-
occurrenceId: occurrence.id,
|
|
745
|
-
ownerId: this.ownerId,
|
|
746
|
-
fence: occurrence.fence,
|
|
747
|
-
outcome: "failed",
|
|
748
|
-
error: safeError(settlementError),
|
|
749
|
-
retryable: policy.retryable,
|
|
750
|
-
...(context.adjudication?.status === "pending"
|
|
751
|
-
? { adjudicationRequestId: context.adjudication.requestId }
|
|
752
|
-
: {}),
|
|
753
|
-
...(policy.retryAt === undefined ? {} : { retryAt: policy.retryAt }),
|
|
754
|
-
});
|
|
755
|
-
return settledResult(settled);
|
|
756
|
-
} finally {
|
|
757
|
-
this.clearIntervalFn(timer);
|
|
758
|
-
linked.dispose();
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
async runOccurrence(occurrenceId, options = {}) {
|
|
763
|
-
const id = normalizeIdentifier(occurrenceId, "occurrenceId");
|
|
764
|
-
const current = this.store.getOccurrence(id);
|
|
765
|
-
if (!current) {
|
|
766
|
-
throw runtimeError(
|
|
767
|
-
"SCHEDULER_NOT_FOUND",
|
|
768
|
-
`Scheduler occurrence does not exist: ${id}`,
|
|
769
|
-
);
|
|
770
|
-
}
|
|
771
|
-
if (TERMINAL_OCCURRENCE_STATUSES.has(current.status)) {
|
|
772
|
-
return settledResult(current, { alreadySettled: true });
|
|
773
|
-
}
|
|
774
|
-
if (options.signal?.aborted) {
|
|
775
|
-
return { status: "aborted", occurrence: current };
|
|
776
|
-
}
|
|
777
|
-
const claimed = this.store.claimOccurrence({
|
|
778
|
-
occurrenceId: id,
|
|
779
|
-
ownerId: this.ownerId,
|
|
780
|
-
leaseMs: this.leaseMs,
|
|
781
|
-
});
|
|
782
|
-
if (!claimed) {
|
|
783
|
-
const control =
|
|
784
|
-
typeof this.store.getOccurrenceControl === "function"
|
|
785
|
-
? this.store.getOccurrenceControl(id)
|
|
786
|
-
: null;
|
|
787
|
-
if (control?.state === "paused") {
|
|
788
|
-
return {
|
|
789
|
-
status: "paused",
|
|
790
|
-
occurrence: this.store.getOccurrence(id),
|
|
791
|
-
control,
|
|
792
|
-
};
|
|
793
|
-
}
|
|
794
|
-
return {
|
|
795
|
-
status: "busy",
|
|
796
|
-
occurrence: this.store.getOccurrence(id),
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
return this._executeClaim(claimed, options);
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
async runNext(options = {}) {
|
|
803
|
-
if (options.signal?.aborted) return { status: "aborted" };
|
|
804
|
-
const claimed = this.store.claimNext({
|
|
805
|
-
ownerId: this.ownerId,
|
|
806
|
-
leaseMs: this.leaseMs,
|
|
807
|
-
...(options.jobKind === undefined ? {} : { jobKind: options.jobKind }),
|
|
808
|
-
...(options.workspaceId === undefined
|
|
809
|
-
? {}
|
|
810
|
-
: { workspaceId: options.workspaceId }),
|
|
811
|
-
});
|
|
812
|
-
if (!claimed) return { status: "idle" };
|
|
813
|
-
return this._executeClaim(claimed, options);
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
async runUntilIdle({ limit, signal, jobKind, workspaceId } = {}) {
|
|
817
|
-
const bounded = normalizeRunLimit(limit);
|
|
818
|
-
const results = [];
|
|
819
|
-
while (results.length < bounded && !signal?.aborted) {
|
|
820
|
-
const result = await this.runNext({ signal, jobKind, workspaceId });
|
|
821
|
-
if (result.status === "idle" || result.status === "aborted") {
|
|
822
|
-
return { status: result.status, results };
|
|
823
|
-
}
|
|
824
|
-
results.push(result);
|
|
825
|
-
}
|
|
826
|
-
return {
|
|
827
|
-
status: signal?.aborted ? "aborted" : "limit_reached",
|
|
828
|
-
results,
|
|
829
|
-
};
|
|
830
28
|
}
|
|
831
29
|
}
|
|
832
30
|
|