chainlesschain 0.166.74 → 0.166.76
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-BlIvP3k1.js → AIOps-CNaejClV.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DYF7atSV.js → ActionButton-CF_CVKT_.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-LZYaYek6.js → Analytics-a3Z6J7gv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BJxrjNbj.js → AppLayout-BFtWEnct.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-gEDhxhmE.js → Artifacts-BQ8oeMvX.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B0MR950Q.js → Audit-NOo9bmgk.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-3e6Os_Kl.js → BackgroundAgents-QRc7F3Tp.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DB_X8KUg.js → Backup-UlVgLn2P.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DTNcvNeG.js → BaseInput-BER9LJAr.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-SnqdA62j.js → Chat-Z8z2Fdfz.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BaiWNH_V.js → ChatBubbleRenderer-DdmuBrdQ.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Dj0O4dyP.js → Checkbox-CXPgyB8L.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BeelW3dx.js → Codegen-D1vOsLJ7.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BmstiyBM.js → Col-ucLnUJC7.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CrbmFk3f.js → Community-COsV9n9t.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DCg5ZPIw.js → Compact-D0EkBEYh.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-B3sajhq7.js → Compliance-C8w9SUjt.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DWcdvrDK.js → Cowork-CmVaKEJS.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-Bjwp_NDf.js → Cron-B_FiMMV2.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BXTLC9o8.js → Crosschain-ByO3YL8N.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Di62M46b.js → DID-DwpsLM9r.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BQED8Rkt.js → Dashboard-B_8IUvM_.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DEf9VYaj.js → Dropdown-Bo6WQkuX.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DhFpPMAM.js → EmailListRenderer-C9LiQesx.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BOqmzkpS.js → EvolutionSettings-Pc1IpRfk.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BxBnJ4fe.js → FamilyGuardDashboard-Dst6VUnO.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BN9Q8nsZ.js → Federation-Ci7CoLkJ.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CGeqFEd-.js → FormItemContext-bdDyUhUM.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DElmWQTc.js → GenericCardRenderer-CrRwOUVi.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BHBSgKck.js → Git-Dis8h-Z-.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Breo3NTU.js → Governance-DX7OH5w2.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CCABy4E0.js → Inference-Cavv_Q_Z.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-B6_ryn-X.js → KnowledgeGraph-Cck8tnZn.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CkmJjJok.js → Logs-BQt3aGMu.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BIUeeiVA.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-iip65jxv.js → Marketplace-CdmAKNSN.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DDwp_QLb.js → McpTools-BUlJdyPY.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-2ZmNDRkC.js → Memory-DQRTQDr-.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-C6HilwZl.js → MobileBridge-C0dnxgsl.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BeMtYRhx.js → MobileProjects-DQ5Gy7fa.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Bp-FEcoo.js → Mtc-Xl7u2isS.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-DNdkTCe5.js → MtcAudit-C3KX0574.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-PnKg2_Eo.js → Multisig-CHEhfkn8.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DDp4lZeG.js → NLProgramming-Ce38mH-8.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DEjFktcO.js → Notes-C7nuTd7c.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-FR8fJDAn.js → NotificationSettings-BcoEcyq8.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Cyc-XI0L.js → OrderTableRenderer-D-t5hKkx.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DNW2E_JU.js → Organization-C_BGi4xi.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BHfd6wk6.js → Overflow-BodhraDq.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-COIkaXH4.js → P2P-BTa3sAIy.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-BjZslP9T.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-BfVRGMy8.js → Permissions-u3UDzGef.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BWYjO6Aa.js → PersonalDataHub-Cb7ybv65.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-C0e0fPBW.js → Pipeline-CS24k-P7.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CnId4Jv-.js → Privacy-Ddj6Kqs7.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CYf1grXg.js → ProjectInit-Bg5uQIgg.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-HsXgJdiH.js → ProjectSettings-AmPR8T12.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Bi0r9QcC.js → Projects-DGSbAyTK.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B-Tu_-_4.js → Providers-Dc1C3lbB.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CPDqYT2F.js → QrScannerModal-Cv3HXpce.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Df6qcjXy.js → QuickAsk-3dpbXARb.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-dP6sfGSY.js → Recommend-5aGRVnJK.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-VAt9-tM3.js → RemoteSession-CTS2jx0p.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DtRVRiLI.js → Reputation-BxaKI0hY.js} +1 -1
- package/src/assets/web-panel/assets/{Row-B6Ukqvli.js → Row-C23uQdwd.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DfVRQMrZ.js → RssFeed-ssX9YOhm.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CyncAiqQ.js → Search-C24GogII.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DEO7nrkb.js → Security-DdAcGKkk.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CkusQEhN.js → Services-D0dCiEuq.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CbGtO3kc.js → Skeleton-DEY44o0v.js} +1 -1
- package/src/assets/web-panel/assets/Skills-CYt0Mu2W.js +1 -0
- package/src/assets/web-panel/assets/{Sla-CIu9Ahak.js → Sla-B_bbo2vB.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-a2BBjtTL.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-BAOLFlRq.js → SyncSettings-CpIXql0Z.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-BYQKU-GL.js +1 -0
- package/src/assets/web-panel/assets/{Templates-Dkr_vRdJ.js → Templates-C_44nVPq.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-kM7lHUFR.js → Tenant-CyZ2ey2P.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-9zfc41aU.js → Terminal-DwGNHWnp.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Cg_7j6cj.js → TimelineRenderer-BTAHNkqU.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Cs1aikaM.js → Tokens-DCJWkUwc.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DKYPJ9gl.js → Trigger-BCjDO9-E.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BFy1Sm8B.js → Trust-_YS8WbRb.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B31L9NBH.js → UkeySign-m6R8xGq7.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-OMmUYdIC.js → VideoEditing-xOfk29c4.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-y3aE7oru.js → Wallet-B1Gw0awc.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C0ICKvpu.js → WebAuthn-CHK5ft18.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Cq5UYbr5.js → WorkflowEditor-DEp1ukQQ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B1ijaKFv.js → chat-B2sFizun.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CHkI8PDg.js → colors-DJ17YV1E.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-1BYvgWEs.js → compact-item-CBhJJgEC.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BGti56u4.js → createContext-BZkpvNJy.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DZhu13vj.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Cr87Fph1.js → hasIn-C0ZKo6Ei.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkcWhgLB.js → index-4oULtRqE.js} +1 -1
- package/src/assets/web-panel/assets/{index-Duv0TfJa.js → index-5K2z_tgO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6g4jxdE.js → index-8ueG48gl.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dnp-4yPc.js → index-BEnd5fiz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dam-LB_J.js → index-BGIvhCPl.js} +1 -1
- package/src/assets/web-panel/assets/{index-fhpMyq0u.js → index-BMxOoITz.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_lEztok.js → index-BNp6HKFh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjBkVrq9.js → index-BOfPp5OV.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzevrmLK.js → index-Bc3vVG2X.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bni5GodE.js → index-BoDUYyuo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BA0FMuDX.js → index-BpyrhOeh.js} +1 -1
- package/src/assets/web-panel/assets/index-C6iFyQYz.js +1 -0
- package/src/assets/web-panel/assets/{index-B1yur8MU.js → index-C7gv9dvb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CS0MIE2C.js → index-C9gYiACH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHJtAEx8.js → index-CCOr6Q27.js} +1 -1
- package/src/assets/web-panel/assets/{index-6Ta8Pg47.js → index-CW5o1Gar.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOjTRSHE.js → index-CZW84cEf.js} +3 -3
- package/src/assets/web-panel/assets/{index-CvcpesEZ.js → index-CZlkPrxb.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkFXPrdx.js → index-CdxJm-HB.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bdkrut2A.js → index-Chct9tL8.js} +1 -1
- package/src/assets/web-panel/assets/{index-rO6VKJv5.js → index-Cn5UzvgR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYpqBWlt.js → index-Ctguam0K.js} +1 -1
- package/src/assets/web-panel/assets/index-CztThH9f.js +1 -0
- package/src/assets/web-panel/assets/{index-tY479EoQ.js → index-DHtpMr1G.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmmSJBNi.js → index-DJkoJzTU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjgtiMdY.js → index-DLMr5KMd.js} +1 -1
- package/src/assets/web-panel/assets/{index-1WxCzqYq.js → index-DLo8Ls9u.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4BSM3BK.js → index-DM0rWF6z.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJjnXDAD.js → index-DOBXNMdh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDTNnQDz.js → index-Dfgxe-fw.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcoI3ENn.js → index-DjdSFO0d.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cvu95WPI.js → index-DrU5xVpF.js} +1 -1
- package/src/assets/web-panel/assets/{index-rVnXNFST.js → index-DumLgj1t.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCkvhzaY.js → index-Dxe0YlZe.js} +1 -1
- package/src/assets/web-panel/assets/{index-CevUJTXd.js → index-DyiCbHeL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKb16YKp.js → index-IHgzfc1u.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQWMHlY7.js → index-KzNhWykP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbkGda_k.js → index-LPPe0val.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8Jb_cGt.js → index-vFMwiAN4.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DAGtnwoX.js → initDefaultProps-Cqfoq0TJ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-02FXBi5C.js → motion-CIiVJHNu.js} +1 -1
- package/src/assets/web-panel/assets/{move-BLf7rhzJ.js → move-CFl1o_A8.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Ct6i1vqQ.js → mtc-parser-DYoCxcZ1.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DKvTU8IT.js → omit-C1P2q5TY.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DqDsKoMe.js → pickAttrs-BtTRpJtC.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-kae6Cnwx.js → placementArrow-Cst2PcNM.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DzFM_TQf.js → responsiveObserve-CF5kalV2.js} +1 -1
- package/src/assets/web-panel/assets/{slide-qDjNFPuM.js → slide-CtHGqpXN.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BihSr7G3.js → statusUtils-N__biHXf.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BzoT0TfJ.js → styleChecker-DR8V_H-i.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CjXXcU1j.js → useFlexGapSupport-D274dqun.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DrWcbDJ1.js → useFs-BwHLYU5b.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DO1oBNTE.js → usePersonalDataHub-BiA-hVqt.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BR6crWko.js → vnode-Bugl94dy.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DmKLfw6W.js → zoom-DEFl8GCu.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +26 -0
- package/src/lib/evolution/evolution-eval-child-evidence-ledger-adapter.js +2 -0
- package/src/lib/evolution/evolution-eval-cohort-enrollment.js +770 -0
- package/src/lib/evolution/evolution-eval-contracts.js +86 -0
- package/src/lib/evolution/evolution-eval-gate.js +136 -85
- package/src/lib/evolution/evolution-eval-launch-admission.js +505 -0
- package/src/lib/evolution/skill-target-matrix-eval.js +84 -3
- package/src/lib/with-file-lock.js +81 -16
- package/src/assets/web-panel/assets/MarkdownRenderer-DQEQBaRu.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-DuRP0UeX.js +0 -7
- package/src/assets/web-panel/assets/Skills-diOh0gAr.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-_Nzyi4K9.js +0 -1
- package/src/assets/web-panel/assets/Tasks-BpmvL1Eq.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Isft1nEX.js +0 -1
- package/src/assets/web-panel/assets/index-B_T9NUk7.js +0 -1
- package/src/assets/web-panel/assets/index-DBqUxaat.js +0 -1
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
/** Signed admission of one registered attempt; never evidence of Actor execution. */
|
|
2
|
+
import { createHash, createPublicKey, KeyObject, verify } from "node:crypto";
|
|
3
|
+
import { isProxy } from "node:util/types";
|
|
4
|
+
import { captureEvolutionEvalCohortSlotBinding } from "./evolution-eval-cohort-enrollment.js";
|
|
5
|
+
import {
|
|
6
|
+
EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA,
|
|
7
|
+
EvolutionArtifactPorts,
|
|
8
|
+
isEvolutionLedgerArtifactResolver,
|
|
9
|
+
} from "./evolution-artifact-ports.js";
|
|
10
|
+
import {
|
|
11
|
+
EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA,
|
|
12
|
+
EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA,
|
|
13
|
+
EvolutionLedger,
|
|
14
|
+
} from "./evolution-ledger.js";
|
|
15
|
+
|
|
16
|
+
export const EVOLUTION_EVAL_LAUNCH_ADMISSION_SCHEMA =
|
|
17
|
+
"chainlesschain.evolution-eval-launch-admission/v1";
|
|
18
|
+
export const EVOLUTION_EVAL_ENROLLED_LAUNCH_ADMISSION_SCHEMA =
|
|
19
|
+
"chainlesschain.evolution-eval-launch-admission/v2";
|
|
20
|
+
export const EVOLUTION_EVAL_LAUNCH_ADMISSION_PURPOSE =
|
|
21
|
+
"chainlesschain.evolution-eval.attempt-admission/v1";
|
|
22
|
+
export const EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE =
|
|
23
|
+
"evolution.eval-attempt.admitted";
|
|
24
|
+
export const EVOLUTION_EVAL_LAUNCH_ADMISSION_FAILED_CODE =
|
|
25
|
+
"CC_EVOLUTION_EVAL_LAUNCH_ADMISSION_FAILED";
|
|
26
|
+
|
|
27
|
+
const AUTHORITIES = new WeakMap();
|
|
28
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
29
|
+
const ARTIFACT_TYPE = "evolution-eval-child-evidence";
|
|
30
|
+
const INPUT_KEYS = [
|
|
31
|
+
"runId",
|
|
32
|
+
"runNonce",
|
|
33
|
+
"requestDigest",
|
|
34
|
+
"policyDigest",
|
|
35
|
+
"evaluationAuthorityRoot",
|
|
36
|
+
"tenantId",
|
|
37
|
+
"admittedAt",
|
|
38
|
+
"deadlineAt",
|
|
39
|
+
];
|
|
40
|
+
const DESCRIPTOR_KEYS = [
|
|
41
|
+
"tenantId",
|
|
42
|
+
"artifactTenantId",
|
|
43
|
+
"streamId",
|
|
44
|
+
"audience",
|
|
45
|
+
"purpose",
|
|
46
|
+
"planDigest",
|
|
47
|
+
"manifestDigest",
|
|
48
|
+
"cohortId",
|
|
49
|
+
"slotId",
|
|
50
|
+
"authorityId",
|
|
51
|
+
"keyId",
|
|
52
|
+
"trustPolicyDigest",
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
function fail(message) {
|
|
56
|
+
const error = new Error(message);
|
|
57
|
+
error.code = EVOLUTION_EVAL_LAUNCH_ADMISSION_FAILED_CODE;
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function canonical(value) {
|
|
62
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
63
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
64
|
+
return `{${Object.keys(value)
|
|
65
|
+
.sort()
|
|
66
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
67
|
+
.join(",")}}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hash(domain, value) {
|
|
71
|
+
return `sha256:${createHash("sha256")
|
|
72
|
+
.update(`${domain}\0${canonical(value)}`)
|
|
73
|
+
.digest("hex")}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function frozen(value) {
|
|
77
|
+
if (value && typeof value === "object") {
|
|
78
|
+
for (const item of Object.values(value)) frozen(item);
|
|
79
|
+
Object.freeze(value);
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function record(value, keys, label) {
|
|
85
|
+
if (
|
|
86
|
+
!value ||
|
|
87
|
+
typeof value !== "object" ||
|
|
88
|
+
isProxy(value) ||
|
|
89
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(value)) ||
|
|
90
|
+
Reflect.ownKeys(value).length !== keys.length ||
|
|
91
|
+
keys.some(
|
|
92
|
+
(key) =>
|
|
93
|
+
!Object.hasOwn(value, key) ||
|
|
94
|
+
!Object.hasOwn(Object.getOwnPropertyDescriptor(value, key), "value"),
|
|
95
|
+
)
|
|
96
|
+
) {
|
|
97
|
+
fail(`${label} must contain exactly its own data fields`);
|
|
98
|
+
}
|
|
99
|
+
return Object.fromEntries(keys.map((key) => [key, value[key]]));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function text(value, label) {
|
|
103
|
+
if (
|
|
104
|
+
typeof value !== "string" ||
|
|
105
|
+
value.length < 1 ||
|
|
106
|
+
value.length > 256 ||
|
|
107
|
+
value.trim() !== value ||
|
|
108
|
+
[...value].some((character) => character.codePointAt(0) < 32)
|
|
109
|
+
)
|
|
110
|
+
fail(`${label} is invalid`);
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function digest(value, label) {
|
|
115
|
+
if (!DIGEST.test(value ?? "")) fail(`${label} must be a sha256 digest`);
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function timestamp(value, label) {
|
|
120
|
+
const parsed = Date.parse(value);
|
|
121
|
+
if (
|
|
122
|
+
typeof value !== "string" ||
|
|
123
|
+
!Number.isFinite(parsed) ||
|
|
124
|
+
new Date(parsed).toISOString() !== value
|
|
125
|
+
)
|
|
126
|
+
fail(`${label} is invalid`);
|
|
127
|
+
return parsed;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function descriptor(input) {
|
|
131
|
+
const output = record(input, DESCRIPTOR_KEYS, "admission descriptor");
|
|
132
|
+
for (const key of DESCRIPTOR_KEYS) text(output[key], key);
|
|
133
|
+
for (const key of ["planDigest", "manifestDigest", "trustPolicyDigest"])
|
|
134
|
+
digest(output[key], key);
|
|
135
|
+
if (output.purpose !== "evolution-ledger")
|
|
136
|
+
fail("admission requires ledger retention purpose");
|
|
137
|
+
return frozen(output);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function request(input, state, live = false) {
|
|
141
|
+
const output = record(input, INPUT_KEYS, "admission request");
|
|
142
|
+
for (const key of ["runId", "runNonce", "tenantId"]) text(output[key], key);
|
|
143
|
+
for (const key of [
|
|
144
|
+
"requestDigest",
|
|
145
|
+
"policyDigest",
|
|
146
|
+
"evaluationAuthorityRoot",
|
|
147
|
+
])
|
|
148
|
+
digest(output[key], key);
|
|
149
|
+
const start = timestamp(output.admittedAt, "admittedAt");
|
|
150
|
+
const end = timestamp(output.deadlineAt, "deadlineAt");
|
|
151
|
+
if (output.tenantId !== state.descriptor.tenantId || start >= end)
|
|
152
|
+
fail("admission tenant or interval differs from its authority");
|
|
153
|
+
if (live) {
|
|
154
|
+
const now = state.now();
|
|
155
|
+
if (!Number.isFinite(now) || now < start || now >= end)
|
|
156
|
+
fail("admission is outside its execution validity window");
|
|
157
|
+
}
|
|
158
|
+
return frozen(output);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function message(core) {
|
|
162
|
+
return Buffer.from(
|
|
163
|
+
`${EVOLUTION_EVAL_LAUNCH_ADMISSION_PURPOSE}\0${canonical(core)}`,
|
|
164
|
+
"utf8",
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function verifyEvidence(value, state) {
|
|
169
|
+
const evidence = record(
|
|
170
|
+
value,
|
|
171
|
+
[
|
|
172
|
+
"schema",
|
|
173
|
+
"descriptorDigest",
|
|
174
|
+
...INPUT_KEYS,
|
|
175
|
+
...(state.enrollment ? ["enrollmentDigest", "descriptor"] : []),
|
|
176
|
+
"attestation",
|
|
177
|
+
],
|
|
178
|
+
"admission evidence",
|
|
179
|
+
);
|
|
180
|
+
const input = request(
|
|
181
|
+
Object.fromEntries(INPUT_KEYS.map((key) => [key, evidence[key]])),
|
|
182
|
+
state,
|
|
183
|
+
);
|
|
184
|
+
if (
|
|
185
|
+
evidence.schema !==
|
|
186
|
+
(state.enrollment
|
|
187
|
+
? EVOLUTION_EVAL_ENROLLED_LAUNCH_ADMISSION_SCHEMA
|
|
188
|
+
: EVOLUTION_EVAL_LAUNCH_ADMISSION_SCHEMA) ||
|
|
189
|
+
evidence.descriptorDigest !== state.descriptorDigest
|
|
190
|
+
)
|
|
191
|
+
fail("admission scope is substituted");
|
|
192
|
+
const signature = record(
|
|
193
|
+
evidence.attestation,
|
|
194
|
+
["algorithm", "issuer", "keyId", "trustPolicyDigest", "value"],
|
|
195
|
+
"admission attestation",
|
|
196
|
+
);
|
|
197
|
+
if (
|
|
198
|
+
signature.algorithm !== "ed25519" ||
|
|
199
|
+
signature.issuer !== state.descriptor.authorityId ||
|
|
200
|
+
signature.keyId !== state.descriptor.keyId ||
|
|
201
|
+
signature.trustPolicyDigest !== state.descriptor.trustPolicyDigest ||
|
|
202
|
+
typeof signature.value !== "string" ||
|
|
203
|
+
!/^[A-Za-z0-9_-]{86}$/u.test(signature.value)
|
|
204
|
+
)
|
|
205
|
+
fail("admission signature trust differs from the fixed anchor");
|
|
206
|
+
const core = {
|
|
207
|
+
schema: evidence.schema,
|
|
208
|
+
descriptorDigest: evidence.descriptorDigest,
|
|
209
|
+
...input,
|
|
210
|
+
};
|
|
211
|
+
if (state.enrollment) {
|
|
212
|
+
if (
|
|
213
|
+
evidence.enrollmentDigest !== state.enrollment.enrollmentDigest ||
|
|
214
|
+
canonical(evidence.descriptor) !== canonical(state.descriptor)
|
|
215
|
+
)
|
|
216
|
+
fail("admission enrollment scope is substituted");
|
|
217
|
+
for (const key of [
|
|
218
|
+
"requestDigest",
|
|
219
|
+
"policyDigest",
|
|
220
|
+
"evaluationAuthorityRoot",
|
|
221
|
+
])
|
|
222
|
+
if (input[key] !== state.enrollment.expectedRequest[key])
|
|
223
|
+
fail("admission request differs from the enrolled slot");
|
|
224
|
+
core.enrollmentDigest = evidence.enrollmentDigest;
|
|
225
|
+
core.descriptor = state.descriptor;
|
|
226
|
+
}
|
|
227
|
+
const bytes = Buffer.from(signature.value, "base64url");
|
|
228
|
+
if (
|
|
229
|
+
bytes.length !== 64 ||
|
|
230
|
+
bytes.toString("base64url") !== signature.value ||
|
|
231
|
+
!verify(null, message(core), state.publicKey, bytes)
|
|
232
|
+
)
|
|
233
|
+
fail("admission Ed25519 signature rejected");
|
|
234
|
+
return frozen({ ...core, attestation: signature });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function eventId(state) {
|
|
238
|
+
// Authority/key rotation cannot free a previously occupied cohort slot.
|
|
239
|
+
return `${EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE}.${hash(
|
|
240
|
+
"eval-admission-slot/v1",
|
|
241
|
+
{
|
|
242
|
+
tenantId: state.descriptor.tenantId,
|
|
243
|
+
streamId: state.descriptor.streamId,
|
|
244
|
+
cohortId: state.descriptor.cohortId,
|
|
245
|
+
slotId: state.descriptor.slotId,
|
|
246
|
+
},
|
|
247
|
+
).slice(7)}`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function events(state) {
|
|
251
|
+
return EvolutionLedger.prototype.read
|
|
252
|
+
.call(state.ledger)
|
|
253
|
+
.filter(
|
|
254
|
+
(event) =>
|
|
255
|
+
event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
|
|
256
|
+
event.eventId === eventId(state),
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function resolveEvent(state, event) {
|
|
261
|
+
if (
|
|
262
|
+
event.type !== EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE ||
|
|
263
|
+
event.tenantId !== state.descriptor.tenantId ||
|
|
264
|
+
event.artifactTenantId !== state.descriptor.artifactTenantId ||
|
|
265
|
+
event.correlationId !== state.descriptor.streamId ||
|
|
266
|
+
event.decision !== "accepted" ||
|
|
267
|
+
event.skillName !== "evolution-eval" ||
|
|
268
|
+
!Array.isArray(event.sourceRefs) ||
|
|
269
|
+
canonical(event.sourceRefs) !==
|
|
270
|
+
canonical(state.enrollment ? [state.enrollment.enrollmentRef] : [])
|
|
271
|
+
)
|
|
272
|
+
fail("admission ledger event is substituted");
|
|
273
|
+
const identity = EvolutionLedger.prototype.verify.call(state.ledger);
|
|
274
|
+
const resolution = state.resolveArtifact({
|
|
275
|
+
epoch: identity.epoch,
|
|
276
|
+
ledgerId: identity.ledgerId,
|
|
277
|
+
ref: event.subjectRef,
|
|
278
|
+
tenantId: state.descriptor.artifactTenantId,
|
|
279
|
+
});
|
|
280
|
+
if (
|
|
281
|
+
resolution?.schema !== EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA ||
|
|
282
|
+
resolution.authenticated !== true ||
|
|
283
|
+
resolution.found !== true ||
|
|
284
|
+
resolution.ref !== event.subjectRef.ref ||
|
|
285
|
+
resolution.digest !== event.subjectRef.digest ||
|
|
286
|
+
!Buffer.isBuffer(resolution.bytes)
|
|
287
|
+
)
|
|
288
|
+
fail("admission artifact resolution rejected");
|
|
289
|
+
let stored;
|
|
290
|
+
try {
|
|
291
|
+
stored = JSON.parse(resolution.bytes.toString("utf8"));
|
|
292
|
+
} catch {
|
|
293
|
+
fail("admission artifact is not JSON");
|
|
294
|
+
}
|
|
295
|
+
if (
|
|
296
|
+
stored.schema !== EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA ||
|
|
297
|
+
stored.tenantId !== state.descriptor.artifactTenantId ||
|
|
298
|
+
stored.audience !== state.descriptor.audience ||
|
|
299
|
+
stored.purpose !== state.descriptor.purpose ||
|
|
300
|
+
stored.retention !== "ledger" ||
|
|
301
|
+
stored.type !== ARTIFACT_TYPE
|
|
302
|
+
)
|
|
303
|
+
fail("admission durable artifact scope differs");
|
|
304
|
+
const evidence = verifyEvidence(stored.value, state);
|
|
305
|
+
if (event.timestamp !== evidence.admittedAt)
|
|
306
|
+
fail("admission event timestamp differs");
|
|
307
|
+
return frozen({
|
|
308
|
+
schema: "chainlesschain.evolution-eval-launch-admission-resolution/v1",
|
|
309
|
+
eventId: event.eventId,
|
|
310
|
+
eventSequence: event.sequence,
|
|
311
|
+
admissionDigest: hash(evidence.schema, evidence),
|
|
312
|
+
evidence,
|
|
313
|
+
authenticated: true,
|
|
314
|
+
durable: true,
|
|
315
|
+
cohortCompletenessAuthenticated: false,
|
|
316
|
+
promotionAuthority: false,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Trusted composition only. This does not certify the supplied manifest's creation time. */
|
|
321
|
+
export function createEvolutionEvalLaunchAdmissionAuthority({
|
|
322
|
+
descriptor: input,
|
|
323
|
+
publicKey,
|
|
324
|
+
signer,
|
|
325
|
+
artifactPorts,
|
|
326
|
+
ledger,
|
|
327
|
+
ledgerArtifactResolver,
|
|
328
|
+
now = Date.now,
|
|
329
|
+
cohortSlotBinding,
|
|
330
|
+
} = {}) {
|
|
331
|
+
const scope = descriptor(input);
|
|
332
|
+
if (
|
|
333
|
+
!(artifactPorts instanceof EvolutionArtifactPorts) ||
|
|
334
|
+
isProxy(artifactPorts) ||
|
|
335
|
+
!(ledger instanceof EvolutionLedger) ||
|
|
336
|
+
isProxy(ledger) ||
|
|
337
|
+
!isEvolutionLedgerArtifactResolver(ledgerArtifactResolver)
|
|
338
|
+
)
|
|
339
|
+
fail(
|
|
340
|
+
"admission requires real artifact ports, Ledger and a branded resolver",
|
|
341
|
+
);
|
|
342
|
+
if (typeof now !== "function" || isProxy(now) || !signer || isProxy(signer))
|
|
343
|
+
fail("admission signer and clock are required");
|
|
344
|
+
const sign = Object.getOwnPropertyDescriptor(signer, "sign")?.value;
|
|
345
|
+
if (typeof sign !== "function" || isProxy(sign))
|
|
346
|
+
fail("admission signer must be an own callable");
|
|
347
|
+
const key =
|
|
348
|
+
publicKey instanceof KeyObject && publicKey.type === "public"
|
|
349
|
+
? publicKey
|
|
350
|
+
: createPublicKey(publicKey);
|
|
351
|
+
if (key.asymmetricKeyType !== "ed25519")
|
|
352
|
+
fail("admission trust anchor must be Ed25519");
|
|
353
|
+
const state = {
|
|
354
|
+
descriptor: scope,
|
|
355
|
+
descriptorDigest: hash("eval-admission-descriptor/v1", scope),
|
|
356
|
+
publicKey: key,
|
|
357
|
+
sign: sign.bind(signer),
|
|
358
|
+
artifactPorts,
|
|
359
|
+
ledger,
|
|
360
|
+
resolveArtifact: ledgerArtifactResolver,
|
|
361
|
+
now,
|
|
362
|
+
enrollment:
|
|
363
|
+
cohortSlotBinding === undefined
|
|
364
|
+
? null
|
|
365
|
+
: captureEvolutionEvalCohortSlotBinding(cohortSlotBinding, {
|
|
366
|
+
descriptor: scope,
|
|
367
|
+
ledger,
|
|
368
|
+
artifactPorts,
|
|
369
|
+
ledgerArtifactResolver,
|
|
370
|
+
publicKey: key,
|
|
371
|
+
}),
|
|
372
|
+
};
|
|
373
|
+
const authority = Object.freeze({ descriptor: scope });
|
|
374
|
+
AUTHORITIES.set(authority, state);
|
|
375
|
+
return authority;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
export function isEvolutionEvalLaunchAdmissionAuthority(value) {
|
|
379
|
+
return AUTHORITIES.has(value);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/** Captured identity for strict production composition; copies cannot forge enrollment. */
|
|
383
|
+
export function captureEvolutionEvalLaunchAdmissionBinding(authority) {
|
|
384
|
+
const state = authorityState(authority);
|
|
385
|
+
return frozen({
|
|
386
|
+
mode: state.enrollment ? "enrolled-cohort" : "legacy-single-slot",
|
|
387
|
+
descriptor: state.descriptor,
|
|
388
|
+
expectedRequest: state.enrollment?.expectedRequest ?? null,
|
|
389
|
+
enrollmentDigest: state.enrollment?.enrollmentDigest ?? null,
|
|
390
|
+
cohortCompletenessAuthenticated: false,
|
|
391
|
+
promotionAuthority: false,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function authorityState(authority) {
|
|
396
|
+
const state = AUTHORITIES.get(authority);
|
|
397
|
+
if (!state) fail("a trusted launch admission authority is required");
|
|
398
|
+
return state;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** One admission per slot, including identical requests. Recovery only reads; it never launches again. */
|
|
402
|
+
export async function admitEvolutionEvalLaunch(authority, input) {
|
|
403
|
+
const state = authorityState(authority);
|
|
404
|
+
const captured = request(input, state, true);
|
|
405
|
+
// Capture head BEFORE the occupancy read: a concurrent append cannot escape CAS.
|
|
406
|
+
const head = EvolutionLedger.prototype.verify.call(state.ledger);
|
|
407
|
+
if (state.enrollment) state.enrollment.assertOpen(captured);
|
|
408
|
+
if (events(state).length !== 0) fail("admission slot is already occupied");
|
|
409
|
+
const core = {
|
|
410
|
+
schema: state.enrollment
|
|
411
|
+
? EVOLUTION_EVAL_ENROLLED_LAUNCH_ADMISSION_SCHEMA
|
|
412
|
+
: EVOLUTION_EVAL_LAUNCH_ADMISSION_SCHEMA,
|
|
413
|
+
descriptorDigest: state.descriptorDigest,
|
|
414
|
+
...captured,
|
|
415
|
+
...(state.enrollment
|
|
416
|
+
? {
|
|
417
|
+
enrollmentDigest: state.enrollment.enrollmentDigest,
|
|
418
|
+
descriptor: state.descriptor,
|
|
419
|
+
}
|
|
420
|
+
: {}),
|
|
421
|
+
};
|
|
422
|
+
const signature = state.sign(
|
|
423
|
+
Object.freeze({ message: message(core).toString("utf8") }),
|
|
424
|
+
);
|
|
425
|
+
const evidence = verifyEvidence(
|
|
426
|
+
{
|
|
427
|
+
...core,
|
|
428
|
+
attestation: {
|
|
429
|
+
algorithm: "ed25519",
|
|
430
|
+
issuer: state.descriptor.authorityId,
|
|
431
|
+
keyId: state.descriptor.keyId,
|
|
432
|
+
trustPolicyDigest: state.descriptor.trustPolicyDigest,
|
|
433
|
+
value: signature,
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
state,
|
|
437
|
+
);
|
|
438
|
+
request(captured, state, true);
|
|
439
|
+
const published = EvolutionArtifactPorts.prototype.putCanonical.call(
|
|
440
|
+
state.artifactPorts,
|
|
441
|
+
ARTIFACT_TYPE,
|
|
442
|
+
evidence,
|
|
443
|
+
{
|
|
444
|
+
audience: state.descriptor.audience,
|
|
445
|
+
purpose: state.descriptor.purpose,
|
|
446
|
+
retention: "ledger",
|
|
447
|
+
},
|
|
448
|
+
);
|
|
449
|
+
if (
|
|
450
|
+
published?.receipt?.persisted !== true ||
|
|
451
|
+
published.receipt.readbackVerified !== true ||
|
|
452
|
+
published.receipt.integrityVerified !== true ||
|
|
453
|
+
published.receipt.retention !== "ledger"
|
|
454
|
+
)
|
|
455
|
+
fail("admission artifact persistence failed");
|
|
456
|
+
request(captured, state, true);
|
|
457
|
+
if (state.enrollment) state.enrollment.assertOpen(captured);
|
|
458
|
+
const receipt = EvolutionLedger.prototype.appendDomainEvent.call(
|
|
459
|
+
state.ledger,
|
|
460
|
+
{
|
|
461
|
+
type: EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE,
|
|
462
|
+
eventId: eventId(state),
|
|
463
|
+
tenantId: state.descriptor.tenantId,
|
|
464
|
+
artifactTenantId: state.descriptor.artifactTenantId,
|
|
465
|
+
correlationId: state.descriptor.streamId,
|
|
466
|
+
decision: "accepted",
|
|
467
|
+
skillName: "evolution-eval",
|
|
468
|
+
reason: "signed attempt admission; Actor execution is unproven",
|
|
469
|
+
sourceRefs: state.enrollment ? [state.enrollment.enrollmentRef] : [],
|
|
470
|
+
subjectRef: published.ref,
|
|
471
|
+
timestamp: captured.admittedAt,
|
|
472
|
+
},
|
|
473
|
+
{ expectedHeadDigest: head.headDigest, expectedSequence: head.sequence },
|
|
474
|
+
);
|
|
475
|
+
if (receipt?.authenticated !== true || receipt.durable !== true)
|
|
476
|
+
fail("admission ledger append failed");
|
|
477
|
+
const matches = events(state);
|
|
478
|
+
if (matches.length !== 1) fail("admission slot is absent or ambiguous");
|
|
479
|
+
const result = resolveEvent(state, matches[0]);
|
|
480
|
+
if (canonical(result.evidence) !== canonical(evidence))
|
|
481
|
+
fail("admission readback differs from signed bytes");
|
|
482
|
+
request(captured, state, true);
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/** Durable audit/recovery may outlive the execution deadline; it grants no execution permit. */
|
|
487
|
+
export async function resolveEvolutionEvalLaunch(authority, input) {
|
|
488
|
+
const state = authorityState(authority);
|
|
489
|
+
const expected = record(
|
|
490
|
+
input,
|
|
491
|
+
["runId", "runNonce", "requestDigest"],
|
|
492
|
+
"admission lookup",
|
|
493
|
+
);
|
|
494
|
+
text(expected.runId, "runId");
|
|
495
|
+
text(expected.runNonce, "runNonce");
|
|
496
|
+
digest(expected.requestDigest, "requestDigest");
|
|
497
|
+
const matches = events(state);
|
|
498
|
+
if (matches.length !== 1) fail("admission slot is absent or ambiguous");
|
|
499
|
+
const result = resolveEvent(state, matches[0]);
|
|
500
|
+
if (
|
|
501
|
+
Object.keys(expected).some((key) => result.evidence[key] !== expected[key])
|
|
502
|
+
)
|
|
503
|
+
fail("admission lookup differs from the recorded attempt");
|
|
504
|
+
return result;
|
|
505
|
+
}
|
|
@@ -5,6 +5,8 @@ import { types as utilTypes } from "node:util";
|
|
|
5
5
|
import {
|
|
6
6
|
EVOLUTION_EVAL_AUTHORITY_DESCRIPTOR_SCHEMA,
|
|
7
7
|
isEvolutionEvalGate,
|
|
8
|
+
captureEvolutionEvalGateLaunchAdmissionBinding,
|
|
9
|
+
computeEvolutionEvalLaunchRequestDigest,
|
|
8
10
|
isEvolutionEvalReceiptVerifier,
|
|
9
11
|
computeEvolutionEvalContextDigest,
|
|
10
12
|
runEvolutionEvalGate,
|
|
@@ -184,6 +186,10 @@ const AGGREGATOR_OPTION_KEYS = new Set([
|
|
|
184
186
|
"maximumMatrixWallClockMs",
|
|
185
187
|
"childReceiptStore",
|
|
186
188
|
]);
|
|
189
|
+
const ENROLLED_AGGREGATOR_OPTION_KEYS = new Set([
|
|
190
|
+
...AGGREGATOR_OPTION_KEYS,
|
|
191
|
+
"launchAdmissionMode",
|
|
192
|
+
]);
|
|
187
193
|
const CELL_RUNTIME_KEYS = new Set([
|
|
188
194
|
"gate",
|
|
189
195
|
"receiptVerifier",
|
|
@@ -1680,7 +1686,10 @@ function captureComposition(options) {
|
|
|
1680
1686
|
});
|
|
1681
1687
|
}
|
|
1682
1688
|
|
|
1683
|
-
function captureCellRuntimes(
|
|
1689
|
+
function captureCellRuntimes(
|
|
1690
|
+
value,
|
|
1691
|
+
{ requireEnrolledLaunchAdmission = false, tenantId } = {},
|
|
1692
|
+
) {
|
|
1684
1693
|
rejectProxy(value, "cellRuntimes");
|
|
1685
1694
|
if (
|
|
1686
1695
|
!(value instanceof Map) ||
|
|
@@ -1713,6 +1722,18 @@ function captureCellRuntimes(value) {
|
|
|
1713
1722
|
`${label}.gate must be a branded EvolutionEvalGate`,
|
|
1714
1723
|
);
|
|
1715
1724
|
}
|
|
1725
|
+
const launchAdmissionBinding =
|
|
1726
|
+
captureEvolutionEvalGateLaunchAdmissionBinding(gate);
|
|
1727
|
+
if (
|
|
1728
|
+
requireEnrolledLaunchAdmission &&
|
|
1729
|
+
(launchAdmissionBinding?.mode !== "enrolled-cohort" ||
|
|
1730
|
+
launchAdmissionBinding.descriptor.tenantId !== tenantId)
|
|
1731
|
+
) {
|
|
1732
|
+
throw matrixError(
|
|
1733
|
+
SKILL_TARGET_MATRIX_EVAL_INVALID_CODE,
|
|
1734
|
+
`${label}.gate requires an enrolled cohort launch authority`,
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1716
1737
|
if (!isEvolutionEvalReceiptVerifier(receiptVerifier)) {
|
|
1717
1738
|
throw matrixError(
|
|
1718
1739
|
SKILL_TARGET_MATRIX_EVAL_INVALID_CODE,
|
|
@@ -1731,6 +1752,7 @@ function captureCellRuntimes(value) {
|
|
|
1731
1752
|
);
|
|
1732
1753
|
const config = Object.freeze({
|
|
1733
1754
|
gate,
|
|
1755
|
+
launchAdmissionBinding,
|
|
1734
1756
|
receiptVerifier,
|
|
1735
1757
|
suiteRef: normalizeId(rawConfig.suiteRef, `${label}.suiteRef`),
|
|
1736
1758
|
suiteDigest: normalizeDigest(
|
|
@@ -2876,11 +2898,28 @@ export class SkillTargetMatrixEvalAggregator {
|
|
|
2876
2898
|
#used = false;
|
|
2877
2899
|
|
|
2878
2900
|
constructor(options) {
|
|
2901
|
+
rejectProxy(options, "matrix aggregator options");
|
|
2902
|
+
const requireEnrolledLaunchAdmission = Boolean(
|
|
2903
|
+
options &&
|
|
2904
|
+
typeof options === "object" &&
|
|
2905
|
+
Object.hasOwn(options, "launchAdmissionMode"),
|
|
2906
|
+
);
|
|
2879
2907
|
assertExactRecord(
|
|
2880
2908
|
options,
|
|
2881
|
-
|
|
2909
|
+
requireEnrolledLaunchAdmission
|
|
2910
|
+
? ENROLLED_AGGREGATOR_OPTION_KEYS
|
|
2911
|
+
: AGGREGATOR_OPTION_KEYS,
|
|
2882
2912
|
"matrix aggregator options",
|
|
2883
2913
|
);
|
|
2914
|
+
if (
|
|
2915
|
+
requireEnrolledLaunchAdmission &&
|
|
2916
|
+
options.launchAdmissionMode !== "enrolled-cohort"
|
|
2917
|
+
) {
|
|
2918
|
+
throw matrixError(
|
|
2919
|
+
SKILL_TARGET_MATRIX_EVAL_INVALID_CODE,
|
|
2920
|
+
"matrix launch admission mode must be enrolled-cohort",
|
|
2921
|
+
);
|
|
2922
|
+
}
|
|
2884
2923
|
const tenantId = normalizeId(
|
|
2885
2924
|
options.tenantId,
|
|
2886
2925
|
"matrix aggregator tenantId",
|
|
@@ -2903,7 +2942,32 @@ export class SkillTargetMatrixEvalAggregator {
|
|
|
2903
2942
|
"matrix composition artifacts must belong to the captured tenant",
|
|
2904
2943
|
);
|
|
2905
2944
|
}
|
|
2906
|
-
const cells = captureCellRuntimes(options.cellRuntimes
|
|
2945
|
+
const cells = captureCellRuntimes(options.cellRuntimes, {
|
|
2946
|
+
requireEnrolledLaunchAdmission,
|
|
2947
|
+
tenantId,
|
|
2948
|
+
});
|
|
2949
|
+
if (requireEnrolledLaunchAdmission) {
|
|
2950
|
+
const enrollments = new Set();
|
|
2951
|
+
const slots = new Set();
|
|
2952
|
+
for (const runtime of cells.runtimes.values()) {
|
|
2953
|
+
const binding = runtime.launchAdmissionBinding;
|
|
2954
|
+
enrollments.add(binding.enrollmentDigest);
|
|
2955
|
+
const slot = `${binding.descriptor.cohortId}\0${binding.descriptor.slotId}`;
|
|
2956
|
+
if (slots.has(slot)) {
|
|
2957
|
+
throw matrixError(
|
|
2958
|
+
SKILL_TARGET_MATRIX_EVAL_INVALID_CODE,
|
|
2959
|
+
"matrix cells cannot reuse one enrolled admission slot",
|
|
2960
|
+
);
|
|
2961
|
+
}
|
|
2962
|
+
slots.add(slot);
|
|
2963
|
+
}
|
|
2964
|
+
if (enrollments.size !== 1) {
|
|
2965
|
+
throw matrixError(
|
|
2966
|
+
SKILL_TARGET_MATRIX_EVAL_INVALID_CODE,
|
|
2967
|
+
"matrix cells must share one enrolled cohort",
|
|
2968
|
+
);
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2907
2971
|
const matrixCellIds = targetMatrix.cells.map((cell) => cell.cellId);
|
|
2908
2972
|
const runtimeCellIds = [...cells.runtimes.keys()].sort();
|
|
2909
2973
|
if (!sameCanonical(matrixCellIds, runtimeCellIds)) {
|
|
@@ -2948,6 +3012,7 @@ export class SkillTargetMatrixEvalAggregator {
|
|
|
2948
3012
|
runtimeManifest,
|
|
2949
3013
|
targetMatrix,
|
|
2950
3014
|
cellRuntimes: cells.runtimes,
|
|
3015
|
+
requireEnrolledLaunchAdmission,
|
|
2951
3016
|
composition,
|
|
2952
3017
|
matrixAuthorityRoot,
|
|
2953
3018
|
maximumMatrixWallClockMs,
|
|
@@ -3033,6 +3098,22 @@ export class SkillTargetMatrixEvalAggregator {
|
|
|
3033
3098
|
runtimeId: planCell.runtimeId,
|
|
3034
3099
|
}),
|
|
3035
3100
|
});
|
|
3101
|
+
if (state.requireEnrolledLaunchAdmission) {
|
|
3102
|
+
const binding = runtime.launchAdmissionBinding;
|
|
3103
|
+
if (
|
|
3104
|
+
binding.descriptor.planDigest !== plan.planDigest ||
|
|
3105
|
+
binding.expectedRequest.requestDigest !==
|
|
3106
|
+
computeEvolutionEvalLaunchRequestDigest(gateRequest) ||
|
|
3107
|
+
binding.expectedRequest.policyDigest !== planCell.policyDigest ||
|
|
3108
|
+
binding.expectedRequest.evaluationAuthorityRoot !==
|
|
3109
|
+
planCell.evaluationAuthorityRoot
|
|
3110
|
+
) {
|
|
3111
|
+
throw matrixError(
|
|
3112
|
+
SKILL_TARGET_MATRIX_EVAL_INVALID_CODE,
|
|
3113
|
+
`matrix cell ${planCell.cellId} differs from its enrolled launch request`,
|
|
3114
|
+
);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3036
3117
|
// The preregistered invocation identity is the signed plan cell plus the
|
|
3037
3118
|
// durable reservation. Gate-generated runId/runNonce are only exact
|
|
3038
3119
|
// child-verifier parameters read from this captured Promise result; they
|