chainlesschain 0.166.14 → 0.166.16
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 +1 -1
- package/src/assets/web-panel/assets/{AIOps-C8SyFhOo.js → AIOps-CTxa2Wbq.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Dup5gFK0.js → ActionButton-DHrQyYhy.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-8FyOWA7V.js → Analytics-DQiUqcNl.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DBzdU9dg.js → AppLayout-_Iz4r6wt.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-C_0Z8gNy.js → Artifacts-BNs63YHo.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-Cf2a-58m.js → Audit-BgHIqRLn.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-M7w-2zgB.js → BackgroundAgents-DUQ5axBB.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CCTHQXoL.js → Backup-CJ51E9Vw.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DjXpeFwJ.js → BaseInput-o-5toA_R.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-cAvchsJU.js → Chat-Cu7a-x1L.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DvEvxlZv.js → ChatBubbleRenderer-BUyYkAXr.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DKs6qvOn.js → Checkbox-DwdmZ71L.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DlkA7b9X.js → Codegen-BrH2eYiP.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CkfdKhyJ.js → Col-BVJQEP2j.js} +1 -1
- package/src/assets/web-panel/assets/{Community-iNXMHzj6.js → Community-FGO3vZPq.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DQxPEd09.js → Compact-DYGAFVnT.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CSKvMCjs.js → Compliance-CRvc8Bdt.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CkWqazpD.js → Cowork-D6Ah2m7A.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-k6W8IzhB.js → Cron-AXbU2ifR.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-C8MS1OuY.js → Crosschain-C5DXgEFd.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DJuCcgiQ.js → DID-Bxh9QV9v.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-LeThKzp3.js → Dashboard-B-ZHEta-.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BvxwgpE4.js → Dropdown-66Ik1jqa.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-n3e_a1M3.js → EmailListRenderer-CCWk1BIM.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-509W6W6v.js → FamilyGuardDashboard--9faIULK.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-xgZReQm0.js → Federation-CejW9CgX.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-jZOhKcQx.js → FormItemContext-acHgcXki.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Jo0ULzHv.js → GenericCardRenderer-D2ghd_K4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BsRcyWQP.js → Git-BOe1YJrV.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-JlpMYTAk.js → Governance-BjgzJsof.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CUEz872-.js → Inference-CXCD5rnP.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DgrvvEDU.js → KnowledgeGraph-CHA8QgJT.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Df-KY4U3.js → Logs-DORPMcL6.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-CPPHz01z.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-kPZDTOeI.js → Marketplace-BCFlo1Yx.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CRRzPqNX.js → McpTools-Dl_uZAKh.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-D6pNSkg9.js → Memory-DupHamwz.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-g-pvtwRC.js → MobileBridge-BRSMPJxW.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Bzayfrfe.js → MobileProjects-BHpuzsDl.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-B7S3W-XL.js → Mtc-Ch0jOQfZ.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-B8OMEWVb.js → MtcAudit-qzwQrDi7.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CowRp7GH.js → Multisig-B5wHzUcm.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BkQNyi4c.js → NLProgramming-Hy9uAiA0.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cm7gtkKz.js → Notes-DkuchMC7.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-CbPTVh9m.js → NotificationSettings-CYZhD7Pi.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Dswi26mJ.js → OrderTableRenderer-DKOoqajt.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BkjQ9yy7.js → Organization-D9AXn6j8.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DmRFXP7Y.js → Overflow-Bg15J6hX.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DQE1toAu.js → P2P--B54HoQn.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-Cz9Kk2Nb.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-xSjfOaiU.js → Permissions-DHx38eS1.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-B9ICLqVP.js → PersonalDataHub-Dw8i2hAs.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-CUNwyN9E.js → Pipeline-B2o6Ur2G.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-SOoCricX.js → Privacy-8g-h2fnu.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CSaFul0F.js → ProjectInit-DuVTcINx.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CueiB_oe.js → ProjectSettings-C8njvdZX.js} +2 -2
- package/src/assets/web-panel/assets/Projects-Ca9BAfu7.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CTqf_31h.js → Providers-wFqgod_W.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C8ZP31E9.js → QrScannerModal-9NCXrpmA.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CPgn4713.js → QuickAsk-WUTNvFkY.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-8_e0zw0i.js → Recommend-xT4nYmju.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-iT7lbGqw.js → RemoteSession-fak1PBGC.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-B4q9SUOz.js → Reputation-D1AkQvD-.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CA_nASyL.js → Row-DVfm6xGt.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Cwb0E3yv.js → RssFeed-BDunoLSE.js} +3 -3
- package/src/assets/web-panel/assets/{Search-D9iVsOxJ.js → Search-OPycRoU3.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DPLbYchG.js → Security-C8-Fm3Dt.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DGMVL_LF.js → Services-qM_sMpMl.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-B_6kym0D.js → Skeleton-D3HBJjVF.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Ds6r0dXB.js → Skills-jr67X-tP.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BLHAbBhb.js → Sla-CS3ggyCg.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CZuddd14.js → SpeechSettings-CTOCYxOi.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CdBq7oSl.js → SyncSettings-D3s3cLT5.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DfT60Nyl.js → Tasks-CdfoJ25m.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-RLfsKy2V.js → Templates-Drb4AI8X.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Cw8xCNLE.js → Tenant-DzwR3Qkz.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BOUkNu4f.js → Terminal-D-ESq7xp.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CgGZWaRm.js → TimelineRenderer-BK-AUuws.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CpwjVyir.js → Tokens-xGTouuNp.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DL21H-eb.js → Trigger-BvZj-v2H.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-B3ffFclW.js → Trust-BLC9CGmc.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CkBeb5aI.js → UkeySign-BSuCXpmE.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-U2iVaE3r.js → VideoEditing-DT3A-_Ql.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CQk2wzYd.js → Wallet-c1OXao85.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DYIuIYzT.js → WebAuthn-CuA-F7KJ.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-tg1c2mZQ.js → WorkflowEditor-MANZrf82.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CtL61spq.js → chat-D4Y4Ey0O.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DKpbeo8s.js → colors-DDH06hKO.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-gPZsrswt.js → compact-item-Cym756Xj.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CfHlwzVr.js → createContext-By4Nb1k-.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-KO3pAGeO.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-MV47g_6X.js → hasIn-Ch7OY258.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMMvlLp9.js → index-6-2eYBXr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsH-i_3d.js → index-6CpOV3Pn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CB1HnbNK.js → index-ArMrnx0v.js} +1 -1
- package/src/assets/web-panel/assets/{index-DU4rZpiK.js → index-B51otVoZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRv_uMLV.js → index-BBBUn5v7.js} +1 -1
- package/src/assets/web-panel/assets/{index-srBc9U_s.js → index-BFydNU6a.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnZ_zS1M.js → index-BIrRX-ra.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGtEBodr.js → index-BZB9q-Lp.js} +1 -1
- package/src/assets/web-panel/assets/index-Bh4Rgkg2.js +1 -0
- package/src/assets/web-panel/assets/{index-BjlPD7GO.js → index-Bo20BfdS.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_B9LiKs.js → index-CF3Lhyns.js} +1 -1
- package/src/assets/web-panel/assets/{index-Rb7CRMw9.js → index-CGsvEbbq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIeJmlAA.js → index-CJPks33Y.js} +1 -1
- package/src/assets/web-panel/assets/{index-xUlgG0Xe.js → index-CT-3FYwd.js} +1 -1
- package/src/assets/web-panel/assets/{index-6G0ETFTW.js → index-CUSUzaB8.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzfxTSPW.js → index-CV1UC4zo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmPJpLoD.js → index-CV8qXTvb.js} +1 -1
- package/src/assets/web-panel/assets/{index-fYcS7NS0.js → index-CZn6dmZe.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cjv0kKCU.js → index-CjNUTBwe.js} +1 -1
- package/src/assets/web-panel/assets/{index-Df9sWKpl.js → index-CpudmDhf.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9RF4ieu.js → index-CykROEJA.js} +1 -1
- package/src/assets/web-panel/assets/{index-Zvkt9xqi.js → index-D5sADPGY.js} +1 -1
- package/src/assets/web-panel/assets/{index-yxxXlqBA.js → index-D9le0-dc.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBw52sEl.js → index-DAkk1M7x.js} +1 -1
- package/src/assets/web-panel/assets/{index-ExAGPAnX.js → index-DNEJzc0r.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQp5M0s1.js → index-DNlxihs8.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ddcpj1El.js → index-DiewptTL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOyGUuBE.js → index-DjwgJ5Jd.js} +1 -1
- package/src/assets/web-panel/assets/index-Dox_coTY.js +1 -0
- package/src/assets/web-panel/assets/{index-CmM9jqwe.js → index-DtGValNi.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfLyHCWi.js → index-DvnywwUj.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN-wxSQ8.js → index-OU8DZ9BL.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1XB5-t5.js → index-XGeQMvWK.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4lF-f_z.js → index-ZY2Qs_Sn.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9gtY4nG.js → index-jx7kr6mB.js} +3 -3
- package/src/assets/web-panel/assets/{index-C6nC_DyY.js → index-mL3nOcH6.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dd19vRwy.js → index-oBsfUbyH.js} +1 -1
- package/src/assets/web-panel/assets/{index-bSFrAszw.js → index-q-s04OKn.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_Pl1GnW.js → index-tZ5BUdad.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BeOZoSZ4.js → initDefaultProps-DGcX9iPP.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BXE8VMKx.js → motion-2SeL1D8A.js} +1 -1
- package/src/assets/web-panel/assets/{move-I9sdvPGX.js → move-3cYbQCpS.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-d25zrJd0.js → mtc-parser-IDdxfw0z.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D71V_T4e.js → omit-BNswdKO6.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BNZKpIAR.js → pickAttrs-BwCnem2I.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-jOcgxTTz.js → placementArrow-B9PtZ5rq.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-pta_O8AU.js → responsiveObserve-CPB6iSzV.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Dlq6om7z.js → slide-DZgyblZa.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BnkO_yRv.js → statusUtils-D82IBdsx.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-p8NfWmcG.js → styleChecker-qSHtosM-.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-KcjZZ5U7.js → useFlexGapSupport-CmWO7h0I.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-gqonDMWB.js → useFs-yLrs_ub4.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-jIIfE4go.js → usePersonalDataHub-CJ1VW6rh.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Dyo7fBrM.js → vnode-CzY_moQ4.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-6l8BMg9W.js → zoom-DAa7rEY5.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +62 -11
- package/src/commands/learning.js +71 -1
- package/src/commands/team.js +100 -3
- package/src/data/changelog.json +29 -3
- package/src/harness/worktree-isolator.js +74 -9
- package/src/lib/agent-team/task-lease.js +12 -1
- package/src/lib/agent-team/team-graph-runtime-adapter.js +6 -0
- package/src/lib/agent-team/team-runner.js +4 -0
- package/src/lib/agent-team/team-worktree.js +4 -0
- package/src/lib/capability-manifest.js +212 -1
- package/src/lib/evolution/evolution-artifact-ports.js +3277 -0
- package/src/lib/evolution/evolution-eval-gate.js +6442 -0
- package/src/lib/evolution/evolution-evidence-projector.js +3786 -0
- package/src/lib/evolution/evolution-ledger-ports.js +2689 -0
- package/src/lib/evolution/evolution-ledger.js +4280 -0
- package/src/lib/evolution/skill-candidate-registry.js +2258 -0
- package/src/lib/evolution/skill-execution-manifest.js +942 -0
- package/src/lib/evolution/skill-mutation-authority.js +1677 -0
- package/src/lib/evolution/skill-promotion-controller.js +506 -0
- package/src/lib/evolution/skill-release-registry.js +3277 -0
- package/src/lib/evolution/skill-target-matrix-eval.js +3233 -0
- package/src/lib/evolution/skill-writer-inventory-manifest.js +998 -0
- package/src/lib/evolution/skill-writer-inventory-validator.js +816 -0
- package/src/lib/formal-quality-eval-runtime.js +192 -0
- package/src/lib/graph-kernel/cutover-contract.js +7 -0
- package/src/lib/graph-kernel/cutover-ledger.js +8 -7
- package/src/lib/graph-kernel/evidence-digest.js +47 -0
- package/src/lib/graph-kernel/graph-runtime-surfaces.json +8 -1
- package/src/lib/graph-kernel/production-cutover-evidence.js +342 -15
- package/src/lib/graph-kernel/production-source-evidence.js +1599 -0
- package/src/lib/graph-kernel/retirement-evidence.js +15 -5
- package/src/lib/graph-kernel/runtime-surface-manifest.js +67 -2
- package/src/lib/headless-manifest.js +3 -1
- package/src/lib/learning/skill-improver.js +311 -43
- package/src/lib/learning/skill-synthesizer.js +236 -16
- package/src/lib/process-execution-broker/index.js +32 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +5 -4
- package/src/lib/secure-fs.js +45 -2
- package/src/runtime/agent-core.js +17 -5
- package/src/runtime/headless-runner.js +16 -9
- package/src/assets/web-panel/assets/MarkdownRenderer-BEPDcSwz.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-BujyoDRG.js +0 -7
- package/src/assets/web-panel/assets/Projects-BOeXvU7y.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DdqnMhzi.js +0 -1
- package/src/assets/web-panel/assets/index-BcK8o4ke.js +0 -1
- package/src/assets/web-panel/assets/index-DvbAjyYI.js +0 -1
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
import { GRAPH_CUTOVER_REQUIRED_PLATFORMS } from "./cutover-
|
|
2
|
-
import { graphDigest } from "./compiler.js";
|
|
1
|
+
import { GRAPH_CUTOVER_REQUIRED_PLATFORMS } from "./cutover-contract.js";
|
|
3
2
|
import {
|
|
3
|
+
canonicalGraphEvidenceJson as canonicalGraphJson,
|
|
4
|
+
graphEvidenceDigest as graphDigest,
|
|
5
|
+
} from "./evidence-digest.js";
|
|
6
|
+
import {
|
|
7
|
+
GRAPH_PRODUCTION_SOURCE_ENVIRONMENT,
|
|
8
|
+
GRAPH_PRODUCTION_SOURCE_REF,
|
|
9
|
+
GRAPH_PRODUCTION_SOURCE_WORKFLOW,
|
|
10
|
+
normalizeGraphProductionSourceBundle,
|
|
11
|
+
} from "./production-source-evidence.js";
|
|
12
|
+
import {
|
|
13
|
+
assertGraphProductionRuntimeSurfaceManifest,
|
|
4
14
|
graphRuntimeEntryManifestDigest,
|
|
15
|
+
graphRuntimeSurfaceManifestDigest,
|
|
5
16
|
loadGraphRuntimeSurfaceManifest,
|
|
6
17
|
} from "./runtime-surface-manifest.js";
|
|
7
18
|
import {
|
|
@@ -16,6 +27,19 @@ export const GRAPH_ENTRY_WRITER_OBSERVATION_SCHEMA =
|
|
|
16
27
|
"chainlesschain.graph-entry-writer-observation/v1";
|
|
17
28
|
export const GRAPH_PRODUCTION_CUTOVER_RECEIPT_SCHEMA =
|
|
18
29
|
"chainlesschain.graph-production-cutover-receipt/v1";
|
|
30
|
+
export const GRAPH_PRODUCTION_EVIDENCE_WORKFLOW =
|
|
31
|
+
GRAPH_PRODUCTION_SOURCE_WORKFLOW;
|
|
32
|
+
export const GRAPH_PRODUCTION_EVIDENCE_ENVIRONMENT =
|
|
33
|
+
GRAPH_PRODUCTION_SOURCE_ENVIRONMENT;
|
|
34
|
+
export const GRAPH_PRODUCTION_EVIDENCE_REF = GRAPH_PRODUCTION_SOURCE_REF;
|
|
35
|
+
export const GRAPH_MINIMUM_SHADOW_OBSERVATION_MS = 30 * 60 * 1_000;
|
|
36
|
+
export const GRAPH_MINIMUM_CANARY_OBSERVATION_MS = 60 * 60 * 1_000;
|
|
37
|
+
export const GRAPH_MINIMUM_RETIREMENT_OBSERVATION_MS = 60 * 60 * 1_000;
|
|
38
|
+
export const GRAPH_MINIMUM_LEGACY_WRITER_OBSERVATION_MS = 60 * 60 * 1_000;
|
|
39
|
+
export const GRAPH_PRODUCTION_SOURCE_KINDS = Object.freeze([
|
|
40
|
+
"physical_self_hosted_runner",
|
|
41
|
+
"authenticated_production_endpoint",
|
|
42
|
+
]);
|
|
19
43
|
|
|
20
44
|
export const GRAPH_REQUIRED_CUTOVER_STAGES = Object.freeze([
|
|
21
45
|
"shadow",
|
|
@@ -153,7 +177,11 @@ function timestamp(value, field) {
|
|
|
153
177
|
return { value: normalized, milliseconds };
|
|
154
178
|
}
|
|
155
179
|
|
|
156
|
-
function windowEvidence(
|
|
180
|
+
function windowEvidence(
|
|
181
|
+
input,
|
|
182
|
+
field,
|
|
183
|
+
{ notBefore, minimumDurationMs = 1 } = {},
|
|
184
|
+
) {
|
|
157
185
|
const started = timestamp(input?.startedAt, `${field}.startedAt`);
|
|
158
186
|
const ended = timestamp(input?.endedAt, `${field}.endedAt`);
|
|
159
187
|
if (ended.milliseconds <= started.milliseconds) {
|
|
@@ -169,10 +197,18 @@ function windowEvidence(input, field, { notBefore } = {}) {
|
|
|
169
197
|
{ notBefore, startedAt: started.value },
|
|
170
198
|
);
|
|
171
199
|
}
|
|
200
|
+
const durationMs = ended.milliseconds - started.milliseconds;
|
|
201
|
+
if (durationMs < minimumDurationMs || input?.durationMs !== durationMs) {
|
|
202
|
+
throw evidenceError(
|
|
203
|
+
"CC_GRAPH_PRODUCTION_OBSERVATION_TOO_SHORT",
|
|
204
|
+
`${field}.durationMs must equal its timestamp window and be at least ${minimumDurationMs}`,
|
|
205
|
+
{ field, durationMs, minimumDurationMs },
|
|
206
|
+
);
|
|
207
|
+
}
|
|
172
208
|
return {
|
|
173
209
|
startedAt: started.value,
|
|
174
210
|
endedAt: ended.value,
|
|
175
|
-
durationMs
|
|
211
|
+
durationMs,
|
|
176
212
|
};
|
|
177
213
|
}
|
|
178
214
|
|
|
@@ -206,6 +242,109 @@ function exactMembers(actual, expected, code, message, details = {}) {
|
|
|
206
242
|
}
|
|
207
243
|
}
|
|
208
244
|
|
|
245
|
+
function normalizeObservationSources(input, expectedDigestsByPlatform, field) {
|
|
246
|
+
const sources = Array.isArray(input)
|
|
247
|
+
? input.map((entry, index) => {
|
|
248
|
+
const sourceKind = text(
|
|
249
|
+
entry?.sourceKind,
|
|
250
|
+
`${field}[${index}].sourceKind`,
|
|
251
|
+
);
|
|
252
|
+
const platform = String(entry?.platform || "").toLowerCase();
|
|
253
|
+
if (
|
|
254
|
+
!GRAPH_PRODUCTION_SOURCE_KINDS.includes(sourceKind) ||
|
|
255
|
+
!GRAPH_CUTOVER_REQUIRED_PLATFORMS.includes(platform)
|
|
256
|
+
) {
|
|
257
|
+
throw evidenceError(
|
|
258
|
+
"CC_GRAPH_PRODUCTION_SOURCE_INVALID",
|
|
259
|
+
`${field}[${index}] must identify a physical self-hosted runner or authenticated production endpoint on a required platform`,
|
|
260
|
+
{ field, sourceKind, platform },
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
const observationDigests = Array.isArray(entry?.observationDigests)
|
|
264
|
+
? entry.observationDigests.map((value, digestIndex) =>
|
|
265
|
+
digest(
|
|
266
|
+
value,
|
|
267
|
+
`${field}[${index}].observationDigests[${digestIndex}]`,
|
|
268
|
+
),
|
|
269
|
+
)
|
|
270
|
+
: [];
|
|
271
|
+
exactMembers(
|
|
272
|
+
observationDigests,
|
|
273
|
+
expectedDigestsByPlatform.get(platform) || [],
|
|
274
|
+
"CC_GRAPH_PRODUCTION_SOURCE_BINDING_INCOMPLETE",
|
|
275
|
+
"each production source must bind every required observation digest for its platform",
|
|
276
|
+
{ field, platform },
|
|
277
|
+
);
|
|
278
|
+
return {
|
|
279
|
+
platform,
|
|
280
|
+
sourceKind,
|
|
281
|
+
sourceId: text(entry?.sourceId, `${field}[${index}].sourceId`),
|
|
282
|
+
identityDigest: digest(
|
|
283
|
+
entry?.identityDigest,
|
|
284
|
+
`${field}[${index}].identityDigest`,
|
|
285
|
+
),
|
|
286
|
+
keyId: digest(entry?.keyId, `${field}[${index}].keyId`),
|
|
287
|
+
registryDigest: digest(
|
|
288
|
+
entry?.registryDigest,
|
|
289
|
+
`${field}[${index}].registryDigest`,
|
|
290
|
+
),
|
|
291
|
+
runnerRegistrationId: positive(
|
|
292
|
+
entry?.runnerRegistrationId,
|
|
293
|
+
`${field}[${index}].runnerRegistrationId`,
|
|
294
|
+
),
|
|
295
|
+
runnerName: text(entry?.runnerName, `${field}[${index}].runnerName`),
|
|
296
|
+
runnerLabels: Array.isArray(entry?.runnerLabels)
|
|
297
|
+
? [...entry.runnerLabels]
|
|
298
|
+
.map((label, labelIndex) =>
|
|
299
|
+
text(label, `${field}[${index}].runnerLabels[${labelIndex}]`),
|
|
300
|
+
)
|
|
301
|
+
.sort()
|
|
302
|
+
: [],
|
|
303
|
+
challenge: text(entry?.challenge, `${field}[${index}].challenge`),
|
|
304
|
+
nonce: text(entry?.nonce, `${field}[${index}].nonce`),
|
|
305
|
+
rawLogRoot: digest(
|
|
306
|
+
entry?.rawLogRoot,
|
|
307
|
+
`${field}[${index}].rawLogRoot`,
|
|
308
|
+
),
|
|
309
|
+
receiptDigest: digest(
|
|
310
|
+
entry?.receiptDigest,
|
|
311
|
+
`${field}[${index}].receiptDigest`,
|
|
312
|
+
),
|
|
313
|
+
authenticationDigest: digest(
|
|
314
|
+
entry?.authenticationDigest,
|
|
315
|
+
`${field}[${index}].authenticationDigest`,
|
|
316
|
+
),
|
|
317
|
+
observationDigests: [...observationDigests].sort(),
|
|
318
|
+
};
|
|
319
|
+
})
|
|
320
|
+
: [];
|
|
321
|
+
sources.sort((left, right) =>
|
|
322
|
+
compareCanonicalText(left.platform, right.platform),
|
|
323
|
+
);
|
|
324
|
+
exactMembers(
|
|
325
|
+
sources.map((entry) => entry.platform),
|
|
326
|
+
GRAPH_CUTOVER_REQUIRED_PLATFORMS,
|
|
327
|
+
"CC_GRAPH_PRODUCTION_SOURCE_COVERAGE_INCOMPLETE",
|
|
328
|
+
"production observations must cover Linux, macOS, and Windows sources",
|
|
329
|
+
{ field },
|
|
330
|
+
);
|
|
331
|
+
if (
|
|
332
|
+
new Set(sources.map((entry) => entry.identityDigest)).size !==
|
|
333
|
+
sources.length ||
|
|
334
|
+
new Set(sources.map((entry) => entry.sourceId)).size !== sources.length ||
|
|
335
|
+
new Set(sources.map((entry) => entry.runnerRegistrationId)).size !==
|
|
336
|
+
sources.length ||
|
|
337
|
+
new Set(sources.map((entry) => entry.keyId)).size !== sources.length
|
|
338
|
+
) {
|
|
339
|
+
throw evidenceError(
|
|
340
|
+
"CC_GRAPH_PRODUCTION_HOST_IDENTITY_REUSED",
|
|
341
|
+
"Linux, macOS, and Windows production observations must come from distinct source identities",
|
|
342
|
+
{ field },
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return sources;
|
|
346
|
+
}
|
|
347
|
+
|
|
209
348
|
function verifyDigest(input, normalized, domain, field = "evidenceDigest") {
|
|
210
349
|
const supplied = digest(input?.[field], field);
|
|
211
350
|
const unsigned = clone(normalized);
|
|
@@ -292,7 +431,9 @@ function normalizeShadow(input) {
|
|
|
292
431
|
"shadow evidence must cover every semantic projection dimension",
|
|
293
432
|
);
|
|
294
433
|
return {
|
|
295
|
-
...windowEvidence(input, "shadow"
|
|
434
|
+
...windowEvidence(input, "shadow", {
|
|
435
|
+
minimumDurationMs: GRAPH_MINIMUM_SHADOW_OBSERVATION_MS,
|
|
436
|
+
}),
|
|
296
437
|
runCount: positive(input?.runCount, "shadow.runCount"),
|
|
297
438
|
divergenceCount: zero(input?.divergenceCount, "shadow.divergenceCount"),
|
|
298
439
|
unknownEffectCount: zero(
|
|
@@ -347,7 +488,9 @@ function normalizeCanary(input, commitSha) {
|
|
|
347
488
|
"canary evidence must cover every required platform",
|
|
348
489
|
);
|
|
349
490
|
return {
|
|
350
|
-
...windowEvidence(input, "canary"
|
|
491
|
+
...windowEvidence(input, "canary", {
|
|
492
|
+
minimumDurationMs: GRAPH_MINIMUM_CANARY_OBSERVATION_MS,
|
|
493
|
+
}),
|
|
351
494
|
internalRunCount: positive(
|
|
352
495
|
input?.internalRunCount,
|
|
353
496
|
"canary.internalRunCount",
|
|
@@ -542,7 +685,10 @@ function normalizeMigratedWriterObservation(input, identity, entry, notBefore) {
|
|
|
542
685
|
);
|
|
543
686
|
const normalized = {
|
|
544
687
|
...observedIdentity,
|
|
545
|
-
...windowEvidence(input, "legacyReadOnly", {
|
|
688
|
+
...windowEvidence(input, "legacyReadOnly", {
|
|
689
|
+
notBefore,
|
|
690
|
+
minimumDurationMs: GRAPH_MINIMUM_LEGACY_WRITER_OBSERVATION_MS,
|
|
691
|
+
}),
|
|
546
692
|
observationSampleCount: positive(
|
|
547
693
|
input?.observationSampleCount,
|
|
548
694
|
"legacyReadOnly.observationSampleCount",
|
|
@@ -666,6 +812,7 @@ function normalizeEntry(input, expected, commitSha) {
|
|
|
666
812
|
commitSha,
|
|
667
813
|
contract,
|
|
668
814
|
requiredPlatforms: GRAPH_CUTOVER_REQUIRED_PLATFORMS,
|
|
815
|
+
minimumDurationMs: GRAPH_MINIMUM_RETIREMENT_OBSERVATION_MS,
|
|
669
816
|
},
|
|
670
817
|
);
|
|
671
818
|
normalized.legacyReadOnly = normalizeGraphLegacyWriterObservation(
|
|
@@ -677,6 +824,7 @@ function normalizeEntry(input, expected, commitSha) {
|
|
|
677
824
|
commitSha,
|
|
678
825
|
contract,
|
|
679
826
|
notBefore: finalLedger.canonicalActivatedAt,
|
|
827
|
+
minimumDurationMs: GRAPH_MINIMUM_LEGACY_WRITER_OBSERVATION_MS,
|
|
680
828
|
},
|
|
681
829
|
);
|
|
682
830
|
} else {
|
|
@@ -687,6 +835,42 @@ function normalizeEntry(input, expected, commitSha) {
|
|
|
687
835
|
finalLedger.canonicalActivatedAt,
|
|
688
836
|
);
|
|
689
837
|
}
|
|
838
|
+
const expectedLegacyErrorCode =
|
|
839
|
+
expected.manifest?.cutoverPolicy?.legacyMutationErrorCodes?.[
|
|
840
|
+
identity.surface
|
|
841
|
+
];
|
|
842
|
+
for (const probe of [
|
|
843
|
+
...normalized.legacyReadOnly.mutationProbes,
|
|
844
|
+
...(normalized.retirementEvidence?.mutationProbes || []),
|
|
845
|
+
]) {
|
|
846
|
+
if (probe.errorCode !== expectedLegacyErrorCode) {
|
|
847
|
+
throw evidenceError(
|
|
848
|
+
"CC_GRAPH_PRODUCTION_LEGACY_ERROR_CODE_MISMATCH",
|
|
849
|
+
`${probe.mutationFunction} did not return the manifest-pinned legacy writer error code`,
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
const commonObservationDigests = [
|
|
854
|
+
normalized.shadow.evidenceDigest,
|
|
855
|
+
normalized.canary.evidenceDigest,
|
|
856
|
+
normalized.rollback.evidenceDigest,
|
|
857
|
+
normalized.finalLedger.evidenceDigest,
|
|
858
|
+
normalized.legacyReadOnly.evidenceDigest,
|
|
859
|
+
...(normalized.retirementEvidence
|
|
860
|
+
? [normalized.retirementEvidence.evidenceDigest]
|
|
861
|
+
: []),
|
|
862
|
+
];
|
|
863
|
+
const expectedDigestsByPlatform = new Map(
|
|
864
|
+
normalized.canary.platformJourneys.map(({ platform }) => [
|
|
865
|
+
platform,
|
|
866
|
+
[...commonObservationDigests],
|
|
867
|
+
]),
|
|
868
|
+
);
|
|
869
|
+
normalized.observationSources = normalizeObservationSources(
|
|
870
|
+
input?.observationSources,
|
|
871
|
+
expectedDigestsByPlatform,
|
|
872
|
+
"observationSources",
|
|
873
|
+
);
|
|
690
874
|
normalized.evidenceDigest = verifyDigest(
|
|
691
875
|
input,
|
|
692
876
|
normalized,
|
|
@@ -730,6 +914,10 @@ function normalizeDisabledEntry(input, expected, commitSha) {
|
|
|
730
914
|
input?.durableAuthorityClaimCount,
|
|
731
915
|
"disabledEntry.durableAuthorityClaimCount",
|
|
732
916
|
),
|
|
917
|
+
disablementProbeDigest: digest(
|
|
918
|
+
input?.disablementProbeDigest,
|
|
919
|
+
"disabledEntry.disablementProbeDigest",
|
|
920
|
+
),
|
|
733
921
|
};
|
|
734
922
|
if (
|
|
735
923
|
normalized.surface !== expected.surface.originSurface ||
|
|
@@ -748,6 +936,16 @@ function normalizeDisabledEntry(input, expected, commitSha) {
|
|
|
748
936
|
{ surface: expected.surface.originSurface, entryId: expected.entry.id },
|
|
749
937
|
);
|
|
750
938
|
}
|
|
939
|
+
normalized.observationSources = normalizeObservationSources(
|
|
940
|
+
input?.observationSources,
|
|
941
|
+
new Map(
|
|
942
|
+
GRAPH_CUTOVER_REQUIRED_PLATFORMS.map((platform) => [
|
|
943
|
+
platform,
|
|
944
|
+
[normalized.disablementProbeDigest],
|
|
945
|
+
]),
|
|
946
|
+
),
|
|
947
|
+
"disabledEntry.observationSources",
|
|
948
|
+
);
|
|
751
949
|
normalized.evidenceDigest = verifyDigest(
|
|
752
950
|
input,
|
|
753
951
|
normalized,
|
|
@@ -789,6 +987,41 @@ export function graphProductionCutoverEvidenceDigest(value) {
|
|
|
789
987
|
return graphDigest(unsigned, "cc.graph.production-cutover-evidence/v1");
|
|
790
988
|
}
|
|
791
989
|
|
|
990
|
+
export function graphProductionExpectedIdentityBinding({
|
|
991
|
+
commitSha,
|
|
992
|
+
repository,
|
|
993
|
+
workflow = GRAPH_PRODUCTION_EVIDENCE_WORKFLOW,
|
|
994
|
+
ref = GRAPH_PRODUCTION_EVIDENCE_REF,
|
|
995
|
+
environment = GRAPH_PRODUCTION_EVIDENCE_ENVIRONMENT,
|
|
996
|
+
workflowRunId,
|
|
997
|
+
workflowRunAttempt,
|
|
998
|
+
manifestDigest,
|
|
999
|
+
sourceRegistryDigest,
|
|
1000
|
+
challenge,
|
|
1001
|
+
}) {
|
|
1002
|
+
return graphDigest(
|
|
1003
|
+
{
|
|
1004
|
+
commitSha: commit(commitSha),
|
|
1005
|
+
repository: text(repository, "provenance.repository"),
|
|
1006
|
+
workflow: text(workflow, "provenance.workflow"),
|
|
1007
|
+
ref: text(ref, "provenance.ref"),
|
|
1008
|
+
environment: text(environment, "provenance.environment"),
|
|
1009
|
+
workflowRunId: positive(workflowRunId, "provenance.workflowRunId"),
|
|
1010
|
+
workflowRunAttempt: positive(
|
|
1011
|
+
workflowRunAttempt,
|
|
1012
|
+
"provenance.workflowRunAttempt",
|
|
1013
|
+
),
|
|
1014
|
+
manifestDigest: digest(manifestDigest, "provenance.manifestDigest"),
|
|
1015
|
+
sourceRegistryDigest: digest(
|
|
1016
|
+
sourceRegistryDigest,
|
|
1017
|
+
"provenance.sourceRegistryDigest",
|
|
1018
|
+
),
|
|
1019
|
+
challenge: text(challenge, "provenance.challenge"),
|
|
1020
|
+
},
|
|
1021
|
+
"cc.graph.production-expected-identity/v1",
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
792
1025
|
export function normalizeGraphProductionCutoverEvidence(
|
|
793
1026
|
input,
|
|
794
1027
|
{
|
|
@@ -796,8 +1029,13 @@ export function normalizeGraphProductionCutoverEvidence(
|
|
|
796
1029
|
expectedCommitSha = undefined,
|
|
797
1030
|
expectedRepository = undefined,
|
|
798
1031
|
expectedEnvironment = undefined,
|
|
1032
|
+
expectedWorkflow = GRAPH_PRODUCTION_EVIDENCE_WORKFLOW,
|
|
799
1033
|
expectedWorkflowRunId = undefined,
|
|
800
1034
|
expectedWorkflowRunAttempt = undefined,
|
|
1035
|
+
expectedRegistryDigest = undefined,
|
|
1036
|
+
expectedChallenge = undefined,
|
|
1037
|
+
jobsInventory = undefined,
|
|
1038
|
+
clock = Date.now,
|
|
801
1039
|
} = {},
|
|
802
1040
|
) {
|
|
803
1041
|
if (input?.schema !== GRAPH_PRODUCTION_CUTOVER_EVIDENCE_SCHEMA) {
|
|
@@ -813,8 +1051,19 @@ export function normalizeGraphProductionCutoverEvidence(
|
|
|
813
1051
|
"production cutover evidence does not match the expected commit",
|
|
814
1052
|
);
|
|
815
1053
|
}
|
|
1054
|
+
const manifestContract =
|
|
1055
|
+
assertGraphProductionRuntimeSurfaceManifest(manifest);
|
|
1056
|
+
const manifestDigest = digest(input?.manifestDigest, "manifestDigest");
|
|
1057
|
+
if (manifestDigest !== manifestContract.manifestDigest) {
|
|
1058
|
+
throw evidenceError(
|
|
1059
|
+
"CC_GRAPH_PRODUCTION_MANIFEST_CONTRACT_MISMATCH",
|
|
1060
|
+
"production evidence does not bind the frozen five-surface manifest",
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
816
1063
|
const provenance = {
|
|
817
1064
|
repository: text(input?.provenance?.repository, "provenance.repository"),
|
|
1065
|
+
workflow: text(input?.provenance?.workflow, "provenance.workflow"),
|
|
1066
|
+
ref: text(input?.provenance?.ref, "provenance.ref"),
|
|
818
1067
|
environment: text(input?.provenance?.environment, "provenance.environment"),
|
|
819
1068
|
workflowRunId: positive(
|
|
820
1069
|
input?.provenance?.workflowRunId,
|
|
@@ -824,24 +1073,47 @@ export function normalizeGraphProductionCutoverEvidence(
|
|
|
824
1073
|
input?.provenance?.workflowRunAttempt,
|
|
825
1074
|
"provenance.workflowRunAttempt",
|
|
826
1075
|
),
|
|
827
|
-
|
|
828
|
-
input?.provenance?.
|
|
829
|
-
"provenance.
|
|
1076
|
+
manifestDigest: digest(
|
|
1077
|
+
input?.provenance?.manifestDigest,
|
|
1078
|
+
"provenance.manifestDigest",
|
|
1079
|
+
),
|
|
1080
|
+
sourceRegistryDigest: digest(
|
|
1081
|
+
input?.provenance?.sourceRegistryDigest,
|
|
1082
|
+
"provenance.sourceRegistryDigest",
|
|
1083
|
+
),
|
|
1084
|
+
challenge: text(input?.provenance?.challenge, "provenance.challenge"),
|
|
1085
|
+
expectedIdentityBinding: digest(
|
|
1086
|
+
input?.provenance?.expectedIdentityBinding,
|
|
1087
|
+
"provenance.expectedIdentityBinding",
|
|
830
1088
|
),
|
|
831
1089
|
};
|
|
1090
|
+
const expectedIdentityBinding = graphProductionExpectedIdentityBinding({
|
|
1091
|
+
commitSha,
|
|
1092
|
+
...provenance,
|
|
1093
|
+
});
|
|
832
1094
|
if (
|
|
833
1095
|
(expectedRepository && provenance.repository !== expectedRepository) ||
|
|
1096
|
+
provenance.workflow !== GRAPH_PRODUCTION_EVIDENCE_WORKFLOW ||
|
|
1097
|
+
provenance.ref !== GRAPH_PRODUCTION_EVIDENCE_REF ||
|
|
1098
|
+
provenance.environment !== GRAPH_PRODUCTION_EVIDENCE_ENVIRONMENT ||
|
|
1099
|
+
(expectedWorkflow && provenance.workflow !== expectedWorkflow) ||
|
|
834
1100
|
(expectedEnvironment && provenance.environment !== expectedEnvironment) ||
|
|
835
1101
|
(expectedWorkflowRunId !== undefined &&
|
|
836
1102
|
provenance.workflowRunId !== Number(expectedWorkflowRunId)) ||
|
|
837
1103
|
(expectedWorkflowRunAttempt !== undefined &&
|
|
838
|
-
provenance.workflowRunAttempt !== Number(expectedWorkflowRunAttempt))
|
|
1104
|
+
provenance.workflowRunAttempt !== Number(expectedWorkflowRunAttempt)) ||
|
|
1105
|
+
provenance.manifestDigest !== manifestDigest ||
|
|
1106
|
+
(expectedRegistryDigest &&
|
|
1107
|
+
provenance.sourceRegistryDigest !== expectedRegistryDigest) ||
|
|
1108
|
+
(expectedChallenge && provenance.challenge !== expectedChallenge) ||
|
|
1109
|
+
provenance.expectedIdentityBinding !== expectedIdentityBinding
|
|
839
1110
|
) {
|
|
840
1111
|
throw evidenceError(
|
|
841
1112
|
"CC_GRAPH_PRODUCTION_PROVENANCE_MISMATCH",
|
|
842
1113
|
"production evidence provenance does not match the protected producer",
|
|
843
1114
|
{
|
|
844
1115
|
expectedRepository,
|
|
1116
|
+
expectedWorkflow,
|
|
845
1117
|
expectedEnvironment,
|
|
846
1118
|
expectedWorkflowRunId:
|
|
847
1119
|
expectedWorkflowRunId === undefined
|
|
@@ -855,6 +1127,30 @@ export function normalizeGraphProductionCutoverEvidence(
|
|
|
855
1127
|
},
|
|
856
1128
|
);
|
|
857
1129
|
}
|
|
1130
|
+
if (!jobsInventory) {
|
|
1131
|
+
throw evidenceError(
|
|
1132
|
+
"CC_GRAPH_PRODUCTION_SOURCE_INVENTORY_REQUIRED",
|
|
1133
|
+
"production evidence verification requires the complete current-attempt Actions job inventory",
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
const sourceBundle = normalizeGraphProductionSourceBundle(
|
|
1137
|
+
{
|
|
1138
|
+
registry: input?.sourceRegistry,
|
|
1139
|
+
fragments: input?.sourceFragments,
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
manifest,
|
|
1143
|
+
expectedCommitSha: commitSha,
|
|
1144
|
+
expectedRepository: provenance.repository,
|
|
1145
|
+
expectedRegistryDigest:
|
|
1146
|
+
expectedRegistryDigest || provenance.sourceRegistryDigest,
|
|
1147
|
+
expectedWorkflowRunId: provenance.workflowRunId,
|
|
1148
|
+
expectedWorkflowRunAttempt: provenance.workflowRunAttempt,
|
|
1149
|
+
expectedChallenge: provenance.challenge,
|
|
1150
|
+
jobsInventory,
|
|
1151
|
+
clock,
|
|
1152
|
+
},
|
|
1153
|
+
);
|
|
858
1154
|
const allEntries = manifestEntries(manifest);
|
|
859
1155
|
const durable = allEntries.filter(
|
|
860
1156
|
({ entry }) => entry.cutoverStrategy !== "disabled",
|
|
@@ -913,21 +1209,38 @@ export function normalizeGraphProductionCutoverEvidence(
|
|
|
913
1209
|
`${right.surface}/${right.entryId}`,
|
|
914
1210
|
),
|
|
915
1211
|
);
|
|
1212
|
+
if (
|
|
1213
|
+
canonicalGraphJson(entries) !== canonicalGraphJson(sourceBundle.entries) ||
|
|
1214
|
+
canonicalGraphJson(disabledEntries) !==
|
|
1215
|
+
canonicalGraphJson(sourceBundle.disabledEntries)
|
|
1216
|
+
) {
|
|
1217
|
+
throw evidenceError(
|
|
1218
|
+
"CC_GRAPH_PRODUCTION_SOURCE_DERIVATION_MISMATCH",
|
|
1219
|
+
"aggregate entries do not exactly match values derived from signed raw source receipts",
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
916
1222
|
const observedAt = timestamp(input?.observedAt, "observedAt");
|
|
917
|
-
const
|
|
918
|
-
...
|
|
1223
|
+
const latestSignedCollection = Math.max(
|
|
1224
|
+
...sourceBundle.fragments.flatMap((fragment) =>
|
|
1225
|
+
fragment.receipts.map((receipt) =>
|
|
1226
|
+
Date.parse(receipt.payload.collectorEndedAt),
|
|
1227
|
+
),
|
|
1228
|
+
),
|
|
919
1229
|
);
|
|
920
|
-
if (observedAt.milliseconds
|
|
1230
|
+
if (observedAt.milliseconds !== latestSignedCollection) {
|
|
921
1231
|
throw evidenceError(
|
|
922
1232
|
"CC_GRAPH_PRODUCTION_OBSERVATION_INVALID",
|
|
923
|
-
"aggregate observedAt
|
|
1233
|
+
"aggregate observedAt must equal the latest signed collector completion",
|
|
924
1234
|
);
|
|
925
1235
|
}
|
|
926
1236
|
const normalized = {
|
|
927
1237
|
schema: GRAPH_PRODUCTION_CUTOVER_EVIDENCE_SCHEMA,
|
|
928
1238
|
commitSha,
|
|
1239
|
+
manifestDigest,
|
|
929
1240
|
observedAt: observedAt.value,
|
|
930
1241
|
provenance,
|
|
1242
|
+
sourceRegistry: sourceBundle.registry,
|
|
1243
|
+
sourceFragments: sourceBundle.fragments,
|
|
931
1244
|
entries,
|
|
932
1245
|
disabledEntries,
|
|
933
1246
|
};
|
|
@@ -941,6 +1254,10 @@ export function normalizeGraphProductionCutoverEvidence(
|
|
|
941
1254
|
|
|
942
1255
|
export function createGraphProductionCutoverReceipt(input, options = {}) {
|
|
943
1256
|
const evidence = normalizeGraphProductionCutoverEvidence(input, options);
|
|
1257
|
+
const observationSources = [
|
|
1258
|
+
...evidence.entries.flatMap((entry) => entry.observationSources),
|
|
1259
|
+
...evidence.disabledEntries.flatMap((entry) => entry.observationSources),
|
|
1260
|
+
];
|
|
944
1261
|
const surfaceNames = new Set([
|
|
945
1262
|
...evidence.entries.map((entry) => entry.surface),
|
|
946
1263
|
...evidence.disabledEntries.map((entry) => entry.surface),
|
|
@@ -966,6 +1283,16 @@ export function createGraphProductionCutoverReceipt(input, options = {}) {
|
|
|
966
1283
|
(total, entry) => total + entry.legacyReadOnly.mutationProbes.length,
|
|
967
1284
|
0,
|
|
968
1285
|
),
|
|
1286
|
+
observationSourceCount: observationSources.length,
|
|
1287
|
+
distinctObservationSourceCount: new Set(
|
|
1288
|
+
observationSources.map((source) => source.identityDigest),
|
|
1289
|
+
).size,
|
|
1290
|
+
minimumObservationWindowMs: {
|
|
1291
|
+
shadow: GRAPH_MINIMUM_SHADOW_OBSERVATION_MS,
|
|
1292
|
+
canary: GRAPH_MINIMUM_CANARY_OBSERVATION_MS,
|
|
1293
|
+
retirement: GRAPH_MINIMUM_RETIREMENT_OBSERVATION_MS,
|
|
1294
|
+
legacyWriter: GRAPH_MINIMUM_LEGACY_WRITER_OBSERVATION_MS,
|
|
1295
|
+
},
|
|
969
1296
|
provenance: clone(evidence.provenance),
|
|
970
1297
|
};
|
|
971
1298
|
receipt.receiptDigest = graphDigest(
|