chainlesschain 0.166.6 → 0.166.7
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 +3 -1
- package/src/assets/web-panel/assets/{AIOps-CVnFjTfG.js → AIOps-BlrmQxa2.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BxkwuuQC.js → ActionButton-zyRyLITg.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C2670q6z.js → Analytics-DwGz7OGN.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CU_rylW6.js → AppLayout-Dc-nj7Zd.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-DGJmYqnj.js → Artifacts-7Hu3O73p.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BZOQbINJ.js → Audit-Bnoe3-fR.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DghB4QwF.js → BackgroundAgents-BqYFrDKZ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-l0mwPbta.js → Backup-B3hwW1nz.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Bv3WSZOh.js → BaseInput-XFVxLA4w.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-s88nBdvt.js → Chat-CWRDNw7e.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Z8CBuB1a.js → ChatBubbleRenderer-Bf30VM8G.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B5icasEs.js → Checkbox-kFeeBgac.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CsUFqNud.js → Codegen-CCxp8xoI.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DlBtClaW.js → Col-BLKZalle.js} +1 -1
- package/src/assets/web-panel/assets/{Community-xRn1IdLB.js → Community-DD0eWCez.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-naIr8a_o.js → Compact-CHqHWdy0.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Dp9esfFE.js → Compliance-Bw54uPiK.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DQlMYJB-.js → Cowork-DZ13zKNJ.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-Cd0oNLzJ.js → Cron-Dlj5Jevg.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BtDIx3XX.js → Crosschain-Nvz0aR0j.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BOlpzEwg.js → DID-Ct89eUyY.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DV15Axk1.js → Dashboard-BHUH5IAe.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-COXrewN1.js → Dropdown-BhZG-PO7.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-EjIt0Cm7.js → EmailListRenderer-ae4RVwwJ.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DJlhwb-R.js → FamilyGuardDashboard-AOcxLfLr.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BMiFl82k.js → Federation-BK2PJQOF.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BUcDQyxn.js → FormItemContext-C2n3xO2_.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-C25uFxvK.js → GenericCardRenderer-DcyUVFZq.js} +1 -1
- package/src/assets/web-panel/assets/{Git-D20uaEUU.js → Git-tBae9Lt8.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CQxYJjCX.js → Governance-DmNR3AP4.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-m-sczpS5.js → Inference-CoseEigi.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CBsIlU0S.js → KnowledgeGraph-Bdjd1sxr.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-D0-5bqeu.js → Logs-CtlkKIcn.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BwH414Ms.js → MarkdownRenderer-CZsTBEQE.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CwDGFu2Q.js → Marketplace-BTYb7nEx.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-7FxJ3omT.js → McpTools-D0iUdW3P.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-DOVyb59U.js → Memory--gwI7w4Y.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DZXl-Hje.js → MobileBridge-JmFBi24T.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DlZ8tRXt.js → MobileProjects-BK01cQRx.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-D7Pjx1s_.js → Mtc-u7avzyoO.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BND7lX8p.js → MtcAudit-gT3z5fo_.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BknS7B-p.js → Multisig-BIqZTz5n.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-7C2-KPHt.js → NLProgramming-DdhVfXYq.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DNWdTndN.js → Notes-CBlyUmY3.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-DCm4KcJZ.js → NotificationSettings-DSyI26N3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DyVwwjJx.js → OrderTableRenderer-B7IEuNz4.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Dl2O_qJ9.js → Organization-ozhi4kGS.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BOFCvk9Q.js → Overflow-CBy57RVM.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DgdVowY1.js → P2P-CA-ZRv77.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DOHc9zm8.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-BHNEUUwa.js → Permissions-DiP632GP.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CaZbrOdz.js → PersonalDataHub-AnU8O-SS.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DJDnoXmE.js → Pipeline-DDibOUaP.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CBQr2eX8.js → Privacy-D421t36T.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Yghqa06z.js → ProjectInit-DR879ZPJ.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-HBAtJi8U.js → ProjectSettings-Ded8o6aY.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DiCGnMjz.js → Projects-BHPxiucB.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-uJTz77GI.js → Providers-Boivuu-E.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-k3M5ouTp.js → QrScannerModal-xKD_ntKp.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CMji45PH.js → QuickAsk-D3y_A6FV.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DyoZYPls.js → Recommend-BjKM-YC2.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-s1gR38IO.js → RemoteSession-CgqKMXG4.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D4hIs4vV.js → Reputation-Ci2GjH5p.js} +1 -1
- package/src/assets/web-panel/assets/{Row-mzE-ElTg.js → Row-B0-T2BSh.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-cg7J3hI6.js → RssFeed-Bet-ur-r.js} +3 -3
- package/src/assets/web-panel/assets/{Search-6M0TkGSZ.js → Search-DWtRAS2R.js} +1 -1
- package/src/assets/web-panel/assets/{Security-B1GQ67qh.js → Security-BDfu2Qn6.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D_RwU_5S.js → Services-CvJmvSMM.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-TZjk-dsW.js → Skeleton-CEbrKpdC.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CG6FcaCV.js → Skills-CjVeiETf.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BI190QDv.js → Sla-Dibypxum.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BWmxF2Wu.js → SpeechSettings-XflYXp7a.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CwPiGw6L.js → SyncSettings-ro1Ivx1E.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BIXgCeSk.js → Tasks-CHq1qFbo.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CQFgGCoK.js → Templates-CRnUZxtZ.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DAelEdkL.js → Tenant-jUX72JCA.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BbqWK6qh.js → Terminal-BBhAs7pt.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-cmG3zvY5.js → TimelineRenderer-CD5M3RGp.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-C8444NKU.js → Tokens-sah3v0gu.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-C1Rpnz0I.js → Trigger-BNT3Uz3s.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-u4koPiFD.js → Trust-BytMGPMo.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-oPWKn80Z.js → UkeySign-BkYVMRQs.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D0CUUY_5.js → VideoEditing-psvb5Q7Y.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-fu9pIAbt.js → Wallet-PFQTW0MH.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Bc5ciuOx.js → WebAuthn-DgO-OwRT.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BCin4_4N.js → WorkflowEditor-DL2l9VNl.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B2jbM-XN.js → chat-C84akEzN.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CUVoUQ_2.js → colors-DzTWuQKP.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DgOGpkRH.js → compact-item-CR9LJQFv.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DIxU6eKI.js → createContext-CTTov5Kn.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BOhvmlpc.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DoKRKMav.js → hasIn-DALj523o.js} +1 -1
- package/src/assets/web-panel/assets/{index-i5MB455u.js → index-3-XJoYgX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLdpHe6w.js → index-7ux_XohH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3F_p8NA.js → index-AXnERsyV.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2yo6ast.js → index-B2qpjU-D.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWbL1-N0.js → index-B6QOJbSn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtyAuGOm.js → index-BDyt57zL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpTFx8Xx.js → index-BHRXKiU1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF80xxPG.js → index-BKNIzw0U.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRMEO2Tl.js → index-BNaQt49r.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByjrulIZ.js → index-Be6Os5S8.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCLeNqIL.js → index-C5eeMl_2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJMHnbmu.js → index-CNmTDXmf.js} +1 -1
- package/src/assets/web-panel/assets/{index-2flsPFIX.js → index-CXTEpfGe.js} +1 -1
- package/src/assets/web-panel/assets/{index-BwYofQJg.js → index-CXaCRXN4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5ySiGYy.js → index-CZhhFQi9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeWSw-z5.js → index-Cef0n4k_.js} +1 -1
- package/src/assets/web-panel/assets/{index-C846lPGD.js → index-CjkPDSX4.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9TsO9T9.js → index-CmELknPe.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqlwIjJx.js → index-CnxjXIsK.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co4lDEk-.js → index-CqUgXYIQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cj-us-D_.js → index-CunGDV0g.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFUprhNd.js → index-D0MqUnKO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGTZdZOE.js → index-D9ScRFxz.js} +3 -3
- package/src/assets/web-panel/assets/{index-C88m9lsi.js → index-DBIPnoTj.js} +1 -1
- package/src/assets/web-panel/assets/index-DDyMJexx.js +1 -0
- package/src/assets/web-panel/assets/{index-BXb-Smmm.js → index-DH6OG-ci.js} +1 -1
- package/src/assets/web-panel/assets/{index-eTWPaeBI.js → index-DZER6Lj3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cskz--fd.js → index-D_Bg0LdK.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-ufbAJB.js → index-Dah8M4l2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHugFl3v.js → index-DjE_ew7U.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9mSYovv.js → index-DtW6Zr_i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ds8r3Fzb.js → index-DxdzSljS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPXdBnGi.js → index-QW0EXx14.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-f6l4Vm.js → index-W9axN_Ce.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpvyOt5Z.js → index-_8vetPbU.js} +1 -1
- package/src/assets/web-panel/assets/index-btiojFYn.js +1 -0
- package/src/assets/web-panel/assets/{index-eYxUASSG.js → index-eJcFleIV.js} +1 -1
- package/src/assets/web-panel/assets/{index-be8SonCh.js → index-hzzTITR9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtSPhEyC.js → index-s4CFyn-n.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B4chl7iR.js → initDefaultProps-JuW8mFj7.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DruN9h96.js → motion-Cwb0HBve.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cl0UtCgU.js → move-DHokzMgu.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-FX2ttw70.js → mtc-parser-DX31y6QS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BDCneY46.js → omit-BCIUYDA6.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DycsEg8b.js → pickAttrs-DMCj4EoZ.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bc-dBuMv.js → placementArrow-Dy5K-u1s.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve--Wwaf8lu.js → responsiveObserve-DkGeZu54.js} +1 -1
- package/src/assets/web-panel/assets/{slide-vDmHQqHH.js → slide-Dc5dyJdg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-9c52yv3G.js → statusUtils-DIUBjOaC.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BT4BiO6_.js → styleChecker-DmyEOxm5.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C7XxWPcP.js → useFlexGapSupport-FRhakk1e.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BHoMqh4i.js → useFs-clXyV1WQ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BOLxvsAG.js → usePersonalDataHub-UF6DG41z.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CA7poeeP.js → vnode-CoCt95G7.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B_sAn-co.js → zoom-yVWt-ENm.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/graph.js +215 -5
- package/src/commands/team-distributed.js +342 -2
- package/src/commands/team.js +169 -7
- package/src/data/changelog.json +13 -0
- package/src/generated/cc-agent-protocol.schema.json +6 -1
- package/src/lib/agent-team/task-lease.js +315 -0
- package/src/lib/agent-team/team-agent-stream.js +16 -0
- package/src/lib/agent-team/team-distributed-graph-bridge.js +257 -0
- package/src/lib/agent-team/team-distributed-graph-writer.js +523 -0
- package/src/lib/agent-team/team-distributed-queue.js +251 -0
- package/src/lib/agent-team/team-graph-runtime-adapter.js +1918 -0
- package/src/lib/agent-team/team-runner.js +225 -2
- package/src/lib/app-server/graph-runtime.js +754 -0
- package/src/lib/app-server/rollout-store.js +32 -0
- package/src/lib/app-server/server.js +140 -0
- package/src/lib/autonomous-agent.js +11 -0
- package/src/lib/cowork-graph-authority-adapter.js +455 -0
- package/src/lib/dynamic-workflow-facade.js +83 -16
- package/src/lib/graph-kernel/adapters.js +93 -20
- package/src/lib/graph-kernel/authority.js +324 -0
- package/src/lib/graph-kernel/compiler.js +1 -8
- package/src/lib/graph-kernel/cutover-authority-resolver.js +219 -0
- package/src/lib/graph-kernel/cutover-ledger.js +650 -0
- package/src/lib/graph-kernel/event-store.js +15 -1
- package/src/lib/graph-kernel/graph-runtime-surfaces.json +1427 -0
- package/src/lib/graph-kernel/index.js +4 -0
- package/src/lib/graph-kernel/migration-saga.js +309 -0
- package/src/lib/graph-kernel/runtime-surface-manifest.js +481 -0
- package/src/lib/graph-kernel/runtime.js +661 -24
- package/src/lib/graph-kernel/store-cutover-evidence.js +354 -0
- package/src/lib/graph-kernel/trace-reducer.js +6 -0
- package/src/lib/graph-kernel/trigger-adapter.js +60 -3
- package/src/lib/legacy-runtime-authority.js +160 -0
- package/src/lib/orchestrator.js +28 -0
- package/src/lib/scheduler-kernel/graph-authority-adapter.js +512 -0
- package/src/lib/scheduler-kernel/runtime.js +75 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-BiaZfQIM.js +0 -7
- package/src/assets/web-panel/assets/devWarning-DiSlgCC4.js +0 -1
- package/src/assets/web-panel/assets/index-9WIQEHvv.js +0 -1
- package/src/assets/web-panel/assets/index-B7mDobAl.js +0 -1
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
export const GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA =
|
|
4
|
+
"chainlesschain.graph-store-cutover-evidence/v1";
|
|
5
|
+
|
|
6
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
7
|
+
const COMMIT = /^[a-f0-9]{40,64}$/u;
|
|
8
|
+
const STORE = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$/u;
|
|
9
|
+
|
|
10
|
+
function normalizePlatform(value) {
|
|
11
|
+
const platform = String(value || "")
|
|
12
|
+
.trim()
|
|
13
|
+
.toLowerCase();
|
|
14
|
+
if (platform === "win32") return "windows";
|
|
15
|
+
if (platform === "darwin") return "macos";
|
|
16
|
+
return platform;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function evidenceError(code, message, details = {}) {
|
|
20
|
+
const error = new Error(message);
|
|
21
|
+
error.name = "GraphStoreCutoverEvidenceError";
|
|
22
|
+
error.code = code;
|
|
23
|
+
Object.assign(error, details);
|
|
24
|
+
return error;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function stableValue(value) {
|
|
28
|
+
if (Array.isArray(value)) return value.map(stableValue);
|
|
29
|
+
if (!value || typeof value !== "object") return value;
|
|
30
|
+
return Object.fromEntries(
|
|
31
|
+
Object.keys(value)
|
|
32
|
+
.filter((key) => value[key] !== undefined)
|
|
33
|
+
.sort()
|
|
34
|
+
.map((key) => [key, stableValue(value[key])]),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function graphStoreEvidenceDigest(value) {
|
|
39
|
+
return `sha256:${createHash("sha256")
|
|
40
|
+
.update(JSON.stringify(stableValue(value)), "utf8")
|
|
41
|
+
.digest("hex")}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function assertExactCommitSha(expectedCommit, actualCommit) {
|
|
45
|
+
const actual = String(actualCommit || "")
|
|
46
|
+
.trim()
|
|
47
|
+
.toLowerCase();
|
|
48
|
+
const expected = String(expectedCommit || "")
|
|
49
|
+
.trim()
|
|
50
|
+
.toLowerCase();
|
|
51
|
+
if (!COMMIT.test(actual) || (expected && !COMMIT.test(expected))) {
|
|
52
|
+
throw evidenceError(
|
|
53
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
54
|
+
"expected and actual commit SHAs must be exact hexadecimal identities",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
if (expected && expected !== actual) {
|
|
58
|
+
throw evidenceError(
|
|
59
|
+
"CC_GRAPH_STORE_EVIDENCE_SHA_MISMATCH",
|
|
60
|
+
`expected commit ${expected} does not match checked-out HEAD ${actual}`,
|
|
61
|
+
{ expectedCommit: expected, actualCommit: actual },
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return actual;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function exactDigest(value, field) {
|
|
68
|
+
const output = String(value || "");
|
|
69
|
+
if (!DIGEST.test(output)) {
|
|
70
|
+
throw evidenceError(
|
|
71
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
72
|
+
`${field} must be a sha256 digest`,
|
|
73
|
+
{ field },
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return output;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeStore(value) {
|
|
80
|
+
const surface = String(value?.surface || "").trim();
|
|
81
|
+
const entryId = String(value?.entryId || "").trim();
|
|
82
|
+
const store = String(value?.store || "").trim();
|
|
83
|
+
if (!STORE.test(surface) || !STORE.test(entryId) || !STORE.test(store)) {
|
|
84
|
+
throw evidenceError(
|
|
85
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
86
|
+
"store evidence has an invalid surface, entry, or store identifier",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (value?.recovered !== true || Number(value?.rpoLossCount) !== 0) {
|
|
90
|
+
throw evidenceError(
|
|
91
|
+
"CC_GRAPH_STORE_EVIDENCE_RPO_FAILED",
|
|
92
|
+
`store evidence does not prove RPO=0 recovery: ${store}`,
|
|
93
|
+
{ store },
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return Object.freeze({
|
|
97
|
+
surface,
|
|
98
|
+
entryId,
|
|
99
|
+
store,
|
|
100
|
+
cutpointDigest: exactDigest(value.cutpointDigest, "cutpointDigest"),
|
|
101
|
+
recoveryReceiptDigest: exactDigest(
|
|
102
|
+
value.recoveryReceiptDigest,
|
|
103
|
+
"recoveryReceiptDigest",
|
|
104
|
+
),
|
|
105
|
+
rollbackDrillDigest: exactDigest(
|
|
106
|
+
value.rollbackDrillDigest,
|
|
107
|
+
"rollbackDrillDigest",
|
|
108
|
+
),
|
|
109
|
+
rpoLossCount: 0,
|
|
110
|
+
recovered: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function createGraphStoreCutoverEvidence({
|
|
115
|
+
source,
|
|
116
|
+
commitSha,
|
|
117
|
+
platform,
|
|
118
|
+
stores,
|
|
119
|
+
sourceReceipts,
|
|
120
|
+
}) {
|
|
121
|
+
const record = normalizeGraphStoreCutoverEvidence(
|
|
122
|
+
{
|
|
123
|
+
schema: GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA,
|
|
124
|
+
status: "passed",
|
|
125
|
+
source,
|
|
126
|
+
commitSha,
|
|
127
|
+
platform,
|
|
128
|
+
stores,
|
|
129
|
+
sourceReceipts,
|
|
130
|
+
},
|
|
131
|
+
{ requireEvidenceDigest: false },
|
|
132
|
+
);
|
|
133
|
+
const unsigned = { ...record };
|
|
134
|
+
delete unsigned.evidenceDigest;
|
|
135
|
+
return Object.freeze({
|
|
136
|
+
...unsigned,
|
|
137
|
+
evidenceDigest: graphStoreEvidenceDigest(unsigned),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function normalizeGraphStoreCutoverEvidence(
|
|
142
|
+
value,
|
|
143
|
+
{ requireEvidenceDigest = true } = {},
|
|
144
|
+
) {
|
|
145
|
+
if (
|
|
146
|
+
!value ||
|
|
147
|
+
typeof value !== "object" ||
|
|
148
|
+
Array.isArray(value) ||
|
|
149
|
+
value.schema !== GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA ||
|
|
150
|
+
value.status !== "passed"
|
|
151
|
+
) {
|
|
152
|
+
throw evidenceError(
|
|
153
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
154
|
+
"store cutover evidence schema or status is invalid",
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const source = String(value.source || "").trim();
|
|
158
|
+
const commitSha = String(value.commitSha || "")
|
|
159
|
+
.trim()
|
|
160
|
+
.toLowerCase();
|
|
161
|
+
const platform = normalizePlatform(value.platform);
|
|
162
|
+
if (!STORE.test(source) || !COMMIT.test(commitSha) || !platform) {
|
|
163
|
+
throw evidenceError(
|
|
164
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
165
|
+
"store evidence source, commit SHA, or platform is invalid",
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
if (!Array.isArray(value.stores) || value.stores.length === 0) {
|
|
169
|
+
throw evidenceError(
|
|
170
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
171
|
+
"store evidence must contain at least one real store receipt",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const stores = value.stores
|
|
175
|
+
.map(normalizeStore)
|
|
176
|
+
.sort(
|
|
177
|
+
(left, right) =>
|
|
178
|
+
left.surface.localeCompare(right.surface) ||
|
|
179
|
+
left.entryId.localeCompare(right.entryId) ||
|
|
180
|
+
left.store.localeCompare(right.store),
|
|
181
|
+
);
|
|
182
|
+
if (
|
|
183
|
+
new Set(
|
|
184
|
+
stores.map(
|
|
185
|
+
(entry) => `${entry.surface}\0${entry.entryId}\0${entry.store}`,
|
|
186
|
+
),
|
|
187
|
+
).size !== stores.length
|
|
188
|
+
) {
|
|
189
|
+
throw evidenceError(
|
|
190
|
+
"CC_GRAPH_STORE_EVIDENCE_DUPLICATE",
|
|
191
|
+
"store evidence contains a duplicate store receipt",
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const sourceReceipts = Object.fromEntries(
|
|
195
|
+
Object.entries(value.sourceReceipts || {})
|
|
196
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
197
|
+
.map(([name, receipt]) => [name, exactDigest(receipt, name)]),
|
|
198
|
+
);
|
|
199
|
+
if (Object.keys(sourceReceipts).length === 0) {
|
|
200
|
+
throw evidenceError(
|
|
201
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
202
|
+
"store evidence must bind its source journey receipts",
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
const normalized = {
|
|
206
|
+
schema: GRAPH_STORE_CUTOVER_EVIDENCE_SCHEMA,
|
|
207
|
+
status: "passed",
|
|
208
|
+
source,
|
|
209
|
+
commitSha,
|
|
210
|
+
platform,
|
|
211
|
+
stores,
|
|
212
|
+
sourceReceipts,
|
|
213
|
+
};
|
|
214
|
+
if (requireEvidenceDigest) {
|
|
215
|
+
const evidenceDigest = exactDigest(value.evidenceDigest, "evidenceDigest");
|
|
216
|
+
if (evidenceDigest !== graphStoreEvidenceDigest(normalized)) {
|
|
217
|
+
throw evidenceError(
|
|
218
|
+
"CC_GRAPH_STORE_EVIDENCE_TAMPERED",
|
|
219
|
+
"store cutover evidence digest does not match its contents",
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
normalized.evidenceDigest = evidenceDigest;
|
|
223
|
+
}
|
|
224
|
+
return Object.freeze(normalized);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function graphStoreCutoverCoverage(manifest, evidenceRecords = []) {
|
|
228
|
+
const records = evidenceRecords.map((record) =>
|
|
229
|
+
normalizeGraphStoreCutoverEvidence(record),
|
|
230
|
+
);
|
|
231
|
+
const commits = new Set(records.map((record) => record.commitSha));
|
|
232
|
+
if (commits.size > 1) {
|
|
233
|
+
throw evidenceError(
|
|
234
|
+
"CC_GRAPH_STORE_EVIDENCE_SHA_MISMATCH",
|
|
235
|
+
"store evidence records must bind one exact commit SHA",
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
const availableStores = new Map();
|
|
239
|
+
for (const record of records) {
|
|
240
|
+
for (const store of record.stores) {
|
|
241
|
+
const key = `${store.surface}\0${store.entryId}\0${store.store}`;
|
|
242
|
+
const receipts = availableStores.get(key) || [];
|
|
243
|
+
receipts.push({
|
|
244
|
+
platform: record.platform,
|
|
245
|
+
evidenceDigest: record.evidenceDigest,
|
|
246
|
+
...store,
|
|
247
|
+
});
|
|
248
|
+
availableStores.set(key, receipts);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const requiredPlatforms = [
|
|
252
|
+
...(manifest.cutoverPolicy?.requiredPlatforms || []),
|
|
253
|
+
]
|
|
254
|
+
.map(normalizePlatform)
|
|
255
|
+
.sort();
|
|
256
|
+
if (requiredPlatforms.length === 0) {
|
|
257
|
+
throw evidenceError(
|
|
258
|
+
"CC_GRAPH_STORE_EVIDENCE_INVALID",
|
|
259
|
+
"runtime manifest must declare required cutover platforms",
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
const entries = manifest.surfaces.flatMap((surface) =>
|
|
263
|
+
surface.entries
|
|
264
|
+
.filter((entry) => entry.cutoverStrategy === "migrate")
|
|
265
|
+
.map((entry) => {
|
|
266
|
+
const stores = [...entry.storeDispositions.migrate].sort();
|
|
267
|
+
const keyFor = (store) =>
|
|
268
|
+
`${surface.originSurface}\0${entry.id}\0${store}`;
|
|
269
|
+
const coveredStores = stores.filter((store) =>
|
|
270
|
+
availableStores.has(keyFor(store)),
|
|
271
|
+
);
|
|
272
|
+
const missingStores = stores.filter(
|
|
273
|
+
(store) => !availableStores.has(keyFor(store)),
|
|
274
|
+
);
|
|
275
|
+
const platformCoverage = stores.map((store) => {
|
|
276
|
+
const coveredPlatforms = [
|
|
277
|
+
...new Set(
|
|
278
|
+
(availableStores.get(keyFor(store)) || []).map(
|
|
279
|
+
(receipt) => receipt.platform,
|
|
280
|
+
),
|
|
281
|
+
),
|
|
282
|
+
].sort();
|
|
283
|
+
const missingPlatforms = requiredPlatforms.filter(
|
|
284
|
+
(platform) => !coveredPlatforms.includes(platform),
|
|
285
|
+
);
|
|
286
|
+
return Object.freeze({
|
|
287
|
+
store,
|
|
288
|
+
coveredPlatforms: Object.freeze(coveredPlatforms),
|
|
289
|
+
missingPlatforms: Object.freeze(missingPlatforms),
|
|
290
|
+
complete: missingPlatforms.length === 0,
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
const incompletePlatformStores = platformCoverage.filter(
|
|
294
|
+
(store) => !store.complete,
|
|
295
|
+
);
|
|
296
|
+
return Object.freeze({
|
|
297
|
+
surface: surface.originSurface,
|
|
298
|
+
entryId: entry.id,
|
|
299
|
+
stores: Object.freeze(stores),
|
|
300
|
+
coveredStores: Object.freeze(coveredStores),
|
|
301
|
+
missingStores: Object.freeze(missingStores),
|
|
302
|
+
platformCoverage: Object.freeze(platformCoverage),
|
|
303
|
+
incompletePlatformStores: Object.freeze(incompletePlatformStores),
|
|
304
|
+
complete:
|
|
305
|
+
missingStores.length === 0 && incompletePlatformStores.length === 0,
|
|
306
|
+
});
|
|
307
|
+
}),
|
|
308
|
+
);
|
|
309
|
+
const storeSlotCount = entries.reduce(
|
|
310
|
+
(count, entry) => count + entry.stores.length,
|
|
311
|
+
0,
|
|
312
|
+
);
|
|
313
|
+
const coveredStoreSlotCount = entries.reduce(
|
|
314
|
+
(count, entry) => count + entry.coveredStores.length,
|
|
315
|
+
0,
|
|
316
|
+
);
|
|
317
|
+
const completeStoreSlotCount = entries.reduce(
|
|
318
|
+
(count, entry) =>
|
|
319
|
+
count + entry.platformCoverage.filter((store) => store.complete).length,
|
|
320
|
+
0,
|
|
321
|
+
);
|
|
322
|
+
const platformStoreSlotCount = storeSlotCount * requiredPlatforms.length;
|
|
323
|
+
const coveredPlatformStoreSlotCount = entries.reduce(
|
|
324
|
+
(count, entry) =>
|
|
325
|
+
count +
|
|
326
|
+
entry.platformCoverage.reduce(
|
|
327
|
+
(storeCount, store) =>
|
|
328
|
+
storeCount +
|
|
329
|
+
store.coveredPlatforms.filter((platform) =>
|
|
330
|
+
requiredPlatforms.includes(platform),
|
|
331
|
+
).length,
|
|
332
|
+
0,
|
|
333
|
+
),
|
|
334
|
+
0,
|
|
335
|
+
);
|
|
336
|
+
return Object.freeze({
|
|
337
|
+
schema: "chainlesschain.graph-store-cutover-coverage/v1",
|
|
338
|
+
commitSha: [...commits][0] || null,
|
|
339
|
+
requiredPlatforms: Object.freeze(requiredPlatforms),
|
|
340
|
+
evidenceRecordCount: records.length,
|
|
341
|
+
migratableEntryCount: entries.length,
|
|
342
|
+
completeEntryCount: entries.filter((entry) => entry.complete).length,
|
|
343
|
+
storeSlotCount,
|
|
344
|
+
coveredStoreSlotCount,
|
|
345
|
+
missingStoreSlotCount: storeSlotCount - coveredStoreSlotCount,
|
|
346
|
+
completeStoreSlotCount,
|
|
347
|
+
incompletePlatformStoreSlotCount: storeSlotCount - completeStoreSlotCount,
|
|
348
|
+
platformStoreSlotCount,
|
|
349
|
+
coveredPlatformStoreSlotCount,
|
|
350
|
+
missingPlatformStoreSlotCount:
|
|
351
|
+
platformStoreSlotCount - coveredPlatformStoreSlotCount,
|
|
352
|
+
entries: Object.freeze(entries),
|
|
353
|
+
});
|
|
354
|
+
}
|
|
@@ -280,6 +280,12 @@ export function reduceGraphTrace(
|
|
|
280
280
|
runId: state.id,
|
|
281
281
|
throughSeq: ordered.at(-1)?.seq || 0,
|
|
282
282
|
eventHeadHash: ordered.at(-1)?.hash || null,
|
|
283
|
+
originSurface: state.authority?.originSurface || null,
|
|
284
|
+
authoritySource: state.authority?.authoritySource || null,
|
|
285
|
+
authorityMode: state.authority?.authorityMode || null,
|
|
286
|
+
authorityGeneration: state.authority?.authorityGeneration || null,
|
|
287
|
+
writerId: state.authority?.writerId || null,
|
|
288
|
+
projectionVersion: state.authority?.projectionVersion || null,
|
|
283
289
|
definitionId: definition.id,
|
|
284
290
|
graphRevision: state.graphRevision,
|
|
285
291
|
revisionDigest: state.revisionDigest,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { MemoryRolloutStore } from "../app-server/rollout-store.js";
|
|
3
|
+
import { createGraphAuthorityBinding } from "./authority.js";
|
|
3
4
|
|
|
4
5
|
const JOURNAL_THREAD_ID = "scheduler-graph-dispatch";
|
|
5
6
|
|
|
@@ -61,6 +62,61 @@ export class SchedulerGraphTriggerAdapter {
|
|
|
61
62
|
this.journal = journal;
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
runtimeClaims() {
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
originSurface: "scheduler",
|
|
68
|
+
surface: "scheduler",
|
|
69
|
+
execution: "real",
|
|
70
|
+
persistence: "durable",
|
|
71
|
+
isolated: true,
|
|
72
|
+
terminalEvidence: true,
|
|
73
|
+
authorityModes: Object.freeze(["canonical"]),
|
|
74
|
+
featureGated: true,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_recover(runId) {
|
|
79
|
+
try {
|
|
80
|
+
return this.kernel.recoverRun(runId);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error?.code !== "CC_GRAPH_STALE_WRITER") throw error;
|
|
83
|
+
}
|
|
84
|
+
const events = this.kernel.eventStore.read(runId);
|
|
85
|
+
const latest = events.at(-1);
|
|
86
|
+
const previous = [...events]
|
|
87
|
+
.reverse()
|
|
88
|
+
.find((event) => event.payload?.state?.authority)?.payload
|
|
89
|
+
.state.authority;
|
|
90
|
+
const writer = this.kernel.writerIdentity;
|
|
91
|
+
if (
|
|
92
|
+
!latest ||
|
|
93
|
+
!previous ||
|
|
94
|
+
Number(writer.authorityGeneration) <= Number(previous.authorityGeneration)
|
|
95
|
+
) {
|
|
96
|
+
const error = new Error(
|
|
97
|
+
"scheduler recovery requires an explicitly higher Graph writer generation",
|
|
98
|
+
);
|
|
99
|
+
error.code = "CC_GRAPH_STALE_GENERATION";
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
return this.kernel.recoverRun(runId, {
|
|
103
|
+
authority: createGraphAuthorityBinding({
|
|
104
|
+
...previous,
|
|
105
|
+
logicalRunId: runId,
|
|
106
|
+
originSurface: "scheduler",
|
|
107
|
+
authorityMode: "canonical",
|
|
108
|
+
authoritySource: "graph_kernel",
|
|
109
|
+
authorityGeneration: writer.authorityGeneration,
|
|
110
|
+
writerId: writer.writerId,
|
|
111
|
+
writerLeaseId: writer.writerLeaseId,
|
|
112
|
+
writerLeaseExpiresAt: new Date(
|
|
113
|
+
this.kernel.now() + this.kernel.writerLeaseTtlMs,
|
|
114
|
+
).toISOString(),
|
|
115
|
+
eventHead: latest.hash,
|
|
116
|
+
}),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
64
120
|
dispatch(occurrence, compiledGraph, options = {}) {
|
|
65
121
|
const key = dispatchKey(occurrence);
|
|
66
122
|
const digest = keyDigest(key);
|
|
@@ -72,7 +128,7 @@ export class SchedulerGraphTriggerAdapter {
|
|
|
72
128
|
try {
|
|
73
129
|
run = this.kernel.getRun(existing.runId);
|
|
74
130
|
} catch {
|
|
75
|
-
run = this.
|
|
131
|
+
run = this._recover(existing.runId);
|
|
76
132
|
}
|
|
77
133
|
return Object.freeze({
|
|
78
134
|
occurrenceStatus: "succeeded",
|
|
@@ -86,7 +142,7 @@ export class SchedulerGraphTriggerAdapter {
|
|
|
86
142
|
.find((entry) => entry.phase === "pending");
|
|
87
143
|
if (pending) {
|
|
88
144
|
try {
|
|
89
|
-
const graphRun = this.
|
|
145
|
+
const graphRun = this._recover(pending.runId);
|
|
90
146
|
if (graphRun.revisionDigest !== compiledGraph.revisionDigest) {
|
|
91
147
|
const error = new Error(
|
|
92
148
|
"pending scheduler dispatch is bound to a different GraphRevision",
|
|
@@ -127,6 +183,7 @@ export class SchedulerGraphTriggerAdapter {
|
|
|
127
183
|
const graphRun = this.kernel.startRun(compiledGraph, {
|
|
128
184
|
...options,
|
|
129
185
|
runId,
|
|
186
|
+
originSurface: "scheduler",
|
|
130
187
|
occurrenceRef: {
|
|
131
188
|
jobRevision: occurrence.jobRevision,
|
|
132
189
|
occurrenceId: occurrence.occurrenceId || occurrence.idempotencyKey,
|
|
@@ -173,7 +230,7 @@ export class SchedulerGraphTriggerAdapter {
|
|
|
173
230
|
try {
|
|
174
231
|
graphRun = this.kernel.getRun(accepted.runId);
|
|
175
232
|
} catch {
|
|
176
|
-
graphRun = this.
|
|
233
|
+
graphRun = this._recover(accepted.runId);
|
|
177
234
|
}
|
|
178
235
|
return Object.freeze({
|
|
179
236
|
occurrenceStatus: "succeeded",
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { createRuntimeGraphCutoverAuthorityResolver } from "./graph-kernel/cutover-authority-resolver.js";
|
|
2
|
+
import {
|
|
3
|
+
graphRuntimeSurfaceEntry,
|
|
4
|
+
loadGraphRuntimeSurfaceManifest,
|
|
5
|
+
} from "./graph-kernel/runtime-surface-manifest.js";
|
|
6
|
+
|
|
7
|
+
const AUTHORITY_MODES = new Set(["legacy", "shadow", "canonical"]);
|
|
8
|
+
const ENTRYPOINTS = Object.freeze([
|
|
9
|
+
["CLIAutonomousAgent.", "cli-legacy-autonomous"],
|
|
10
|
+
["Orchestrator.", "cli-legacy-orchestrate"],
|
|
11
|
+
]);
|
|
12
|
+
const resolverCache = new Map();
|
|
13
|
+
const runtimeManifest = loadGraphRuntimeSurfaceManifest();
|
|
14
|
+
|
|
15
|
+
function authorityError(code, message, details = {}) {
|
|
16
|
+
const error = new Error(message);
|
|
17
|
+
error.name = "CLILegacyRuntimeAuthorityError";
|
|
18
|
+
error.code = code;
|
|
19
|
+
Object.assign(error, details);
|
|
20
|
+
return error;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function fallbackMode(env) {
|
|
24
|
+
const mode = String(env.CHAINLESSCHAIN_GRAPH_COWORK || "legacy")
|
|
25
|
+
.trim()
|
|
26
|
+
.toLowerCase();
|
|
27
|
+
if (!AUTHORITY_MODES.has(mode)) {
|
|
28
|
+
throw authorityError(
|
|
29
|
+
"CC_GRAPH_AUTHORITY_MODE_INVALID",
|
|
30
|
+
"CHAINLESSCHAIN_GRAPH_COWORK must be legacy, shadow, or canonical",
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return mode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function entryIdFor(entrypoint) {
|
|
37
|
+
const value = String(entrypoint || "");
|
|
38
|
+
return ENTRYPOINTS.find(([prefix]) => value.startsWith(prefix))?.[1];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function retirementContractFor(entryId) {
|
|
42
|
+
if (!entryId) return null;
|
|
43
|
+
const entry = graphRuntimeSurfaceEntry(
|
|
44
|
+
runtimeManifest,
|
|
45
|
+
"cowork",
|
|
46
|
+
entryId,
|
|
47
|
+
).entry;
|
|
48
|
+
const replacementTargets = (entry.replacementEntryIds || []).map(
|
|
49
|
+
(replacementEntryId) => {
|
|
50
|
+
for (const surface of runtimeManifest.surfaces || []) {
|
|
51
|
+
const target = (surface.entries || []).find(
|
|
52
|
+
(candidate) => candidate.id === replacementEntryId,
|
|
53
|
+
);
|
|
54
|
+
if (!target) continue;
|
|
55
|
+
return Object.freeze({
|
|
56
|
+
entryId: target.id,
|
|
57
|
+
originSurface: surface.originSurface,
|
|
58
|
+
rolloutKey: target.rolloutKey,
|
|
59
|
+
entrypoints: Object.freeze([...(target.entrypoints || [])]),
|
|
60
|
+
recoveryEntrypoints: Object.freeze([
|
|
61
|
+
...(target.recoveryEntrypoints || []),
|
|
62
|
+
]),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
return Object.freeze({
|
|
69
|
+
replacementEntrypoint: entry.replacementEntrypoint || null,
|
|
70
|
+
replacementEntryIds: Object.freeze([...(entry.replacementEntryIds || [])]),
|
|
71
|
+
historicalReadFunctions: Object.freeze([
|
|
72
|
+
...(entry.historicalReadFunctions || []),
|
|
73
|
+
]),
|
|
74
|
+
replacementTargets: Object.freeze(replacementTargets.filter(Boolean)),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function cliLegacyRuntimeAuthorityMode(env = process.env, options = {}) {
|
|
79
|
+
const configured = fallbackMode(env);
|
|
80
|
+
const entryId = options.entryId;
|
|
81
|
+
if (!entryId) return configured;
|
|
82
|
+
let resolver = options.resolver;
|
|
83
|
+
if (!resolver) {
|
|
84
|
+
const key = `${entryId}\0${configured}\0${
|
|
85
|
+
env.CHAINLESSCHAIN_GRAPH_CUTOVER_STATE_DIR || ""
|
|
86
|
+
}`;
|
|
87
|
+
resolver = resolverCache.get(key);
|
|
88
|
+
if (!resolver) {
|
|
89
|
+
resolver = createRuntimeGraphCutoverAuthorityResolver({
|
|
90
|
+
env,
|
|
91
|
+
surface: "cowork",
|
|
92
|
+
entryId,
|
|
93
|
+
fallbackMode: configured,
|
|
94
|
+
});
|
|
95
|
+
resolverCache.set(key, resolver);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const resolved =
|
|
99
|
+
typeof resolver === "function"
|
|
100
|
+
? resolver({ runKey: options.runKey, optIn: options.optIn === true })
|
|
101
|
+
: resolver.resolve({
|
|
102
|
+
runKey: options.runKey,
|
|
103
|
+
optIn: options.optIn === true,
|
|
104
|
+
fallbackMode: configured,
|
|
105
|
+
});
|
|
106
|
+
const mode = typeof resolved === "string" ? resolved : resolved?.mode;
|
|
107
|
+
if (!AUTHORITY_MODES.has(mode)) {
|
|
108
|
+
throw authorityError(
|
|
109
|
+
"CC_GRAPH_AUTHORITY_MODE_INVALID",
|
|
110
|
+
"CLI legacy runtime authority resolver returned an invalid mode",
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return mode;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function assertCLILegacyMutationAllowed(
|
|
117
|
+
entrypoint,
|
|
118
|
+
env = process.env,
|
|
119
|
+
options = {},
|
|
120
|
+
) {
|
|
121
|
+
const entryId = options.entryId || entryIdFor(entrypoint);
|
|
122
|
+
const mode =
|
|
123
|
+
options.authorityMode ||
|
|
124
|
+
cliLegacyRuntimeAuthorityMode(env, { ...options, entryId });
|
|
125
|
+
if (
|
|
126
|
+
mode !== "canonical" &&
|
|
127
|
+
String(env.CHAINLESSCHAIN_CLI_LEGACY_READ_ONLY || "") !== "1"
|
|
128
|
+
) {
|
|
129
|
+
return Object.freeze({
|
|
130
|
+
authorityMode: mode,
|
|
131
|
+
authoritySource:
|
|
132
|
+
mode === "shadow" ? "graph_kernel_shadow" : "legacy_runtime",
|
|
133
|
+
legacyReadOnly: false,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const retirementContract = retirementContractFor(entryId);
|
|
137
|
+
const replacementEntrypoint = retirementContract?.replacementEntrypoint;
|
|
138
|
+
throw authorityError(
|
|
139
|
+
"CC_CLI_LEGACY_RUNTIME_READ_ONLY",
|
|
140
|
+
`CLI legacy runtime is read-only; '${entrypoint}' must use ${replacementEntrypoint || "the canonical Graph Kernel entrypoint"}`,
|
|
141
|
+
{
|
|
142
|
+
entrypoint: String(entrypoint),
|
|
143
|
+
entryId,
|
|
144
|
+
replacementEntrypoint,
|
|
145
|
+
replacementEntryIds: retirementContract?.replacementEntryIds || [],
|
|
146
|
+
historicalReadFunctions:
|
|
147
|
+
retirementContract?.historicalReadFunctions || [],
|
|
148
|
+
replacementTargets: retirementContract?.replacementTargets || [],
|
|
149
|
+
authorityMode: "canonical",
|
|
150
|
+
authoritySource: "graph_kernel",
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function cliLegacyRuntimeReadOnly(env = process.env, options = {}) {
|
|
156
|
+
return (
|
|
157
|
+
cliLegacyRuntimeAuthorityMode(env, options) === "canonical" ||
|
|
158
|
+
String(env.CHAINLESSCHAIN_CLI_LEGACY_READ_ONLY || "") === "1"
|
|
159
|
+
);
|
|
160
|
+
}
|