chainlesschain 0.166.72 → 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/README.md +15 -2
- package/package.json +2 -1
- package/scripts/pm-exploration-effect.mjs +188 -0
- package/src/assets/web-panel/assets/{AIOps-Vk4bgcvz.js → AIOps-CNaejClV.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-dm1pfXdM.js → ActionButton-CF_CVKT_.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C9WdXlkB.js → Analytics-a3Z6J7gv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-0f-jWk68.js → AppLayout-BFtWEnct.js} +5 -5
- package/src/assets/web-panel/assets/Artifacts-BQ8oeMvX.js +1 -0
- package/src/assets/web-panel/assets/{Audit-CymWJrNf.js → Audit-NOo9bmgk.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-9bWGX_cn.js → BackgroundAgents-QRc7F3Tp.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DFBHB3_Y.js → Backup-UlVgLn2P.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D9Lm9d3n.js → BaseInput-BER9LJAr.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-maC7odiU.js → Chat-Z8z2Fdfz.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Crsqn0B1.js → ChatBubbleRenderer-DdmuBrdQ.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BrZgAIL0.js → Checkbox-CXPgyB8L.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-ChqWBE8R.js → Codegen-D1vOsLJ7.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C5TaXHn9.js → Col-ucLnUJC7.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D8m4Egsw.js → Community-COsV9n9t.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CMJmi_Bw.js → Compact-D0EkBEYh.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CW7Bwy8s.js → Compliance-C8w9SUjt.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DLhPTsU6.js → Cowork-CmVaKEJS.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DBrXtf_1.js → Cron-B_FiMMV2.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CzLbJF3j.js → Crosschain-ByO3YL8N.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DreItINq.js → DID-DwpsLM9r.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B_gO9CjY.js → Dashboard-B_8IUvM_.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DXpPiTH_.js → Dropdown-Bo6WQkuX.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Cb1YonC_.js → EmailListRenderer-C9LiQesx.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-GQb6tV_E.js → EvolutionSettings-Pc1IpRfk.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DUtpqpsn.js → FamilyGuardDashboard-Dst6VUnO.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CfZsj0gb.js → Federation-Ci7CoLkJ.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cdr40ozm.js → FormItemContext-bdDyUhUM.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BRaf18hh.js → GenericCardRenderer-CrRwOUVi.js} +1 -1
- package/src/assets/web-panel/assets/{Git-7SqGn3Zi.js → Git-Dis8h-Z-.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D1mfL8Fz.js → Governance-DX7OH5w2.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BXVyCWMd.js → Inference-Cavv_Q_Z.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C-wAA2Ub.js → KnowledgeGraph-Cck8tnZn.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DWxiJiFe.js → Logs-BQt3aGMu.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BIUeeiVA.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CmOVgbTO.js → Marketplace-CdmAKNSN.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Cx4WyryN.js → McpTools-BUlJdyPY.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Di6wy0Ky.js → Memory-DQRTQDr-.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DrR7I1A7.js → MobileBridge-C0dnxgsl.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-SnNFgay-.js → MobileProjects-DQ5Gy7fa.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DPZpfO4G.js → Mtc-Xl7u2isS.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-CTT74J6Y.js → MtcAudit-C3KX0574.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DoLT96hm.js → Multisig-CHEhfkn8.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BY-9TS7_.js → NLProgramming-Ce38mH-8.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-1_rKLQkS.js → Notes-C7nuTd7c.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-D8N1NZ6Y.js → NotificationSettings-BcoEcyq8.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Ch-HjmbS.js → OrderTableRenderer-D-t5hKkx.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DKQtaPAc.js → Organization-C_BGi4xi.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-B3n9XpS2.js → Overflow-BodhraDq.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Fn8LWurl.js → P2P-BTa3sAIy.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CsumgiUO.js → PdhVaultBrowser-BjZslP9T.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-CTCN6Rk6.js → Permissions-u3UDzGef.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BwpvzXm7.js → PersonalDataHub-Cb7ybv65.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-C1_hrCCQ.js → Pipeline-CS24k-P7.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-C-BmNft5.js → Privacy-Ddj6Kqs7.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B9HYk17G.js → ProjectInit-Bg5uQIgg.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BFgA-an1.js → ProjectSettings-AmPR8T12.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Yofw9TrC.js → Projects-DGSbAyTK.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B83JppEP.js → Providers-Dc1C3lbB.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-D5ZRpUGC.js → QrScannerModal-Cv3HXpce.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-B-mz9iY-.js → QuickAsk-3dpbXARb.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DtjVu00v.js → Recommend-5aGRVnJK.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Dk8IBiG3.js → RemoteSession-CTS2jx0p.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-DpTIK7Oe.js → Reputation-BxaKI0hY.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DVYQoXil.js → Row-C23uQdwd.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-ikMaTwEE.js → RssFeed-ssX9YOhm.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CHVHCNdo.js → Search-C24GogII.js} +1 -1
- package/src/assets/web-panel/assets/{Security-MxjX-UDp.js → Security-DdAcGKkk.js} +2 -2
- package/src/assets/web-panel/assets/{Services-CmwTYlHk.js → Services-D0dCiEuq.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BQzBoW5V.js → Skeleton-DEY44o0v.js} +1 -1
- package/src/assets/web-panel/assets/Skills-CYt0Mu2W.js +1 -0
- package/src/assets/web-panel/assets/{Sla-DOQbR10a.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-BPyc0P-r.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-BRpihbvV.js → Templates-C_44nVPq.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-B1qu8vDX.js → Tenant-CyZ2ey2P.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CEe3YAvM.js → Terminal-DwGNHWnp.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Biz2ENj5.js → TimelineRenderer-BTAHNkqU.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bh-mJyas.js → Tokens-DCJWkUwc.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DaFKe1bY.js → Trigger-BCjDO9-E.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DsJ7u_-G.js → Trust-_YS8WbRb.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-9I90JZxO.js → UkeySign-m6R8xGq7.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C96s3pW9.js → VideoEditing-xOfk29c4.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DTMqIySe.js → Wallet-B1Gw0awc.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C3rh3szY.js → WebAuthn-CHK5ft18.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-C3as7vBp.js → WorkflowEditor-DEp1ukQQ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-zsGetwuT.js → chat-B2sFizun.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Dt9qbWYV.js → colors-DJ17YV1E.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BJWYHVIL.js → compact-item-CBhJJgEC.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-pKrpnY7l.js → createContext-BZkpvNJy.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DZhu13vj.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-sbUKl7Xu.js → hasIn-C0ZKo6Ei.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfQmb4PB.js → index-4oULtRqE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DD_IBhgm.js → index-5K2z_tgO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWPF2Hth.js → index-8ueG48gl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRsSdHdW.js → index-BEnd5fiz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiZ6Lupa.js → index-BGIvhCPl.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQtTUsCI.js → index-BMxOoITz.js} +1 -1
- package/src/assets/web-panel/assets/{index-qE4san4o.js → index-BNp6HKFh.js} +1 -1
- package/src/assets/web-panel/assets/{index-omZRNwB7.js → index-BOfPp5OV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnrxgbPB.js → index-Bc3vVG2X.js} +1 -1
- package/src/assets/web-panel/assets/{index-CR5WxgE-.js → index-BoDUYyuo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRpfrG-e.js → index-BpyrhOeh.js} +1 -1
- package/src/assets/web-panel/assets/index-C6iFyQYz.js +1 -0
- package/src/assets/web-panel/assets/{index-Dmp7IdrF.js → index-C7gv9dvb.js} +1 -1
- package/src/assets/web-panel/assets/{index-5GohpTfK.js → index-C9gYiACH.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7tOZZAs.js → index-CCOr6Q27.js} +1 -1
- package/src/assets/web-panel/assets/{index--wWXhZQU.js → index-CW5o1Gar.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFMPJahZ.js → index-CZW84cEf.js} +3 -3
- package/src/assets/web-panel/assets/{index-DRAzhNw6.js → index-CZlkPrxb.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bf8dv266.js → index-CdxJm-HB.js} +1 -1
- package/src/assets/web-panel/assets/{index-sakhsZMa.js → index-Chct9tL8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFQTgkPD.js → index-Cn5UzvgR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BR1gZBlK.js → index-Ctguam0K.js} +1 -1
- package/src/assets/web-panel/assets/index-CztThH9f.js +1 -0
- package/src/assets/web-panel/assets/{index-T8ASbPWt.js → index-DHtpMr1G.js} +1 -1
- package/src/assets/web-panel/assets/{index-fQ-JtwM7.js → index-DJkoJzTU.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di-YcQHn.js → index-DLMr5KMd.js} +1 -1
- package/src/assets/web-panel/assets/{index-oUag3zZf.js → index-DLo8Ls9u.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSXJ2PbY.js → index-DM0rWF6z.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_z7zLle.js → index-DOBXNMdh.js} +1 -1
- package/src/assets/web-panel/assets/{index-0CK6iR4G.js → index-Dfgxe-fw.js} +1 -1
- package/src/assets/web-panel/assets/{index-B53DhH1R.js → index-DjdSFO0d.js} +1 -1
- package/src/assets/web-panel/assets/{index-vTPOhhfW.js → index-DrU5xVpF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJZq5jWm.js → index-DumLgj1t.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZmBSuN8.js → index-Dxe0YlZe.js} +1 -1
- package/src/assets/web-panel/assets/{index-DoMii5CD.js → index-DyiCbHeL.js} +1 -1
- package/src/assets/web-panel/assets/{index-n8vVPeJ6.js → index-IHgzfc1u.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIxu3nOh.js → index-KzNhWykP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWBlZsqf.js → index-LPPe0val.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9DoXtNz.js → index-vFMwiAN4.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BVpFM2mv.js → initDefaultProps-Cqfoq0TJ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-Mrl9_kZM.js → motion-CIiVJHNu.js} +1 -1
- package/src/assets/web-panel/assets/{move-CvRC7fRw.js → move-CFl1o_A8.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C7PSeivU.js → mtc-parser-DYoCxcZ1.js} +1 -1
- package/src/assets/web-panel/assets/{omit-RI1cO_Ok.js → omit-C1P2q5TY.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-akwD3e22.js → pickAttrs-BtTRpJtC.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-C4f-tfqj.js → placementArrow-Cst2PcNM.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-hyHNGoSW.js → responsiveObserve-CF5kalV2.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B6vlTDr6.js → slide-CtHGqpXN.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-D8poWZW8.js → statusUtils-N__biHXf.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bz1ZKvoD.js → styleChecker-DR8V_H-i.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C-vv_T11.js → useFlexGapSupport-D274dqun.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BubqlAej.js → useFs-BwHLYU5b.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CTNJrVC8.js → usePersonalDataHub-BiA-hVqt.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DbT41Wli.js → vnode-Bugl94dy.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-R0Rxz73D.js → zoom-DEFl8GCu.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +52 -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 +423 -115
- package/src/lib/evolution/evolution-eval-launch-admission.js +505 -0
- package/src/lib/evolution/pm-exploration-benchmark.js +2014 -49
- package/src/lib/evolution/skill-target-matrix-eval.js +84 -3
- package/src/lib/evolution/skill-writer-inventory-manifest.js +4 -1
- package/src/lib/task-progress-tracker.js +47 -4
- package/src/lib/with-file-lock.js +81 -16
- package/src/runtime/agent-core.js +18 -7
- package/src/assets/web-panel/assets/Artifacts-C7HWVeFu.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BJl3Hibe.js +0 -1
- package/src/assets/web-panel/assets/Skills-B-mPG69i.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-wPQkSA9J.js +0 -1
- package/src/assets/web-panel/assets/Tasks-DbBA-eHJ.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CAmY8PZd.js +0 -1
- package/src/assets/web-panel/assets/index-Dfsrnshy.js +0 -1
- package/src/assets/web-panel/assets/index-tlLfPT5e.js +0 -1
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
/** Signed, durable preregistration and closure of a cohort's admission inventory.
|
|
2
|
+
* An admission proves permission, never Actor execution or global launch coverage.
|
|
3
|
+
*/
|
|
4
|
+
import { createHash, createPublicKey, KeyObject, verify } from "node:crypto";
|
|
5
|
+
import { isProxy } from "node:util/types";
|
|
6
|
+
import {
|
|
7
|
+
EvolutionArtifactPorts,
|
|
8
|
+
EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA,
|
|
9
|
+
isEvolutionLedgerArtifactResolver,
|
|
10
|
+
} from "./evolution-artifact-ports.js";
|
|
11
|
+
import {
|
|
12
|
+
EvolutionLedger,
|
|
13
|
+
EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA,
|
|
14
|
+
EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA,
|
|
15
|
+
} from "./evolution-ledger.js";
|
|
16
|
+
import {
|
|
17
|
+
verifyPmExplorationEffectPlan,
|
|
18
|
+
verifyPmExplorationEffectSlotManifest,
|
|
19
|
+
} from "./pm-exploration-benchmark.js";
|
|
20
|
+
import {
|
|
21
|
+
createEvolutionEvalLaunchAdmissionAuthority,
|
|
22
|
+
resolveEvolutionEvalLaunch,
|
|
23
|
+
EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE,
|
|
24
|
+
} from "./evolution-eval-launch-admission.js";
|
|
25
|
+
|
|
26
|
+
export const EVOLUTION_EVAL_COHORT_ENROLLMENT_SCHEMA =
|
|
27
|
+
"chainlesschain.evolution-eval-cohort-enrollment/v1";
|
|
28
|
+
export const EVOLUTION_EVAL_COHORT_SEAL_SCHEMA =
|
|
29
|
+
"chainlesschain.evolution-eval-cohort-seal/v1";
|
|
30
|
+
export const EVOLUTION_EVAL_COHORT_ENROLLMENT_EVENT_TYPE =
|
|
31
|
+
"evolution.eval-cohort.enrolled";
|
|
32
|
+
export const EVOLUTION_EVAL_COHORT_SEAL_EVENT_TYPE =
|
|
33
|
+
"evolution.eval-cohort.sealed";
|
|
34
|
+
export const EVOLUTION_EVAL_COHORT_FAILED_CODE =
|
|
35
|
+
"CC_EVOLUTION_EVAL_COHORT_FAILED";
|
|
36
|
+
|
|
37
|
+
const AUTHORITIES = new WeakMap();
|
|
38
|
+
const SLOT_BINDINGS = new WeakMap();
|
|
39
|
+
const DESCRIPTOR_KEYS = [
|
|
40
|
+
"tenantId",
|
|
41
|
+
"artifactTenantId",
|
|
42
|
+
"streamId",
|
|
43
|
+
"audience",
|
|
44
|
+
"purpose",
|
|
45
|
+
"authorityId",
|
|
46
|
+
"keyId",
|
|
47
|
+
"trustPolicyDigest",
|
|
48
|
+
];
|
|
49
|
+
const SLOT_KEYS = [
|
|
50
|
+
"slotId",
|
|
51
|
+
"evaluationPlanDigest",
|
|
52
|
+
"requestDigest",
|
|
53
|
+
"policyDigest",
|
|
54
|
+
"evaluationAuthorityRoot",
|
|
55
|
+
];
|
|
56
|
+
const ARTIFACT_TYPE = "evolution-eval-child-evidence";
|
|
57
|
+
const LIMITS = {
|
|
58
|
+
cohortCompletenessAuthenticated: false,
|
|
59
|
+
promotionAuthority: false,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function fail(message) {
|
|
63
|
+
const error = new Error(message);
|
|
64
|
+
error.code = EVOLUTION_EVAL_COHORT_FAILED_CODE;
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
function canonical(value) {
|
|
68
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
69
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
70
|
+
return `{${Object.keys(value)
|
|
71
|
+
.sort()
|
|
72
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
73
|
+
.join(",")}}`;
|
|
74
|
+
}
|
|
75
|
+
function hash(domain, value) {
|
|
76
|
+
return `sha256:${createHash("sha256")
|
|
77
|
+
.update(`${domain}\0${canonical(value)}`)
|
|
78
|
+
.digest("hex")}`;
|
|
79
|
+
}
|
|
80
|
+
function frozen(value) {
|
|
81
|
+
if (value && typeof value === "object") {
|
|
82
|
+
for (const child of Object.values(value)) frozen(child);
|
|
83
|
+
Object.freeze(value);
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
function snapshot(value, depth = 0) {
|
|
88
|
+
if (depth > 50) fail("cohort evidence nesting exceeds limit");
|
|
89
|
+
if (value === null || ["string", "boolean"].includes(typeof value))
|
|
90
|
+
return value;
|
|
91
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
92
|
+
if (!value || typeof value !== "object" || isProxy(value))
|
|
93
|
+
fail("cohort evidence must contain JSON data");
|
|
94
|
+
if (Array.isArray(value)) {
|
|
95
|
+
if (
|
|
96
|
+
Object.getPrototypeOf(value) !== Array.prototype ||
|
|
97
|
+
Reflect.ownKeys(value).length !== value.length + 1
|
|
98
|
+
)
|
|
99
|
+
fail("cohort evidence array must be dense own data");
|
|
100
|
+
return Array.from({ length: value.length }, (_, index) => {
|
|
101
|
+
const property = Object.getOwnPropertyDescriptor(value, String(index));
|
|
102
|
+
if (!property || !("value" in property))
|
|
103
|
+
fail("cohort evidence array must be own data");
|
|
104
|
+
return snapshot(property.value, depth + 1);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (![Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
108
|
+
fail("cohort evidence must be plain data");
|
|
109
|
+
return Object.fromEntries(
|
|
110
|
+
Reflect.ownKeys(value).map((key) => {
|
|
111
|
+
const property = Object.getOwnPropertyDescriptor(value, key);
|
|
112
|
+
if (
|
|
113
|
+
typeof key !== "string" ||
|
|
114
|
+
!property.enumerable ||
|
|
115
|
+
!("value" in property)
|
|
116
|
+
)
|
|
117
|
+
fail("cohort evidence fields must be own data");
|
|
118
|
+
return [key, snapshot(property.value, depth + 1)];
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
function record(value, keys, label) {
|
|
123
|
+
if (
|
|
124
|
+
!value ||
|
|
125
|
+
Array.isArray(value) ||
|
|
126
|
+
typeof value !== "object" ||
|
|
127
|
+
isProxy(value) ||
|
|
128
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(value)) ||
|
|
129
|
+
Reflect.ownKeys(value).length !== keys.length ||
|
|
130
|
+
keys.some((key) => {
|
|
131
|
+
const property = Object.getOwnPropertyDescriptor(value, key);
|
|
132
|
+
return !property || !("value" in property);
|
|
133
|
+
})
|
|
134
|
+
)
|
|
135
|
+
fail(`${label} must contain exactly its own data fields`);
|
|
136
|
+
return Object.fromEntries(keys.map((key) => [key, value[key]]));
|
|
137
|
+
}
|
|
138
|
+
function text(value, label) {
|
|
139
|
+
if (
|
|
140
|
+
typeof value !== "string" ||
|
|
141
|
+
!value.length ||
|
|
142
|
+
value.length > 256 ||
|
|
143
|
+
value.trim() !== value ||
|
|
144
|
+
[...value].some((character) => character.codePointAt(0) < 32)
|
|
145
|
+
)
|
|
146
|
+
fail(`${label} is invalid`);
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
function digest(value, label) {
|
|
150
|
+
if (typeof value !== "string" || !/^sha256:[a-f0-9]{64}$/u.test(value))
|
|
151
|
+
fail(`${label} must be a sha256 digest`);
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function stateOf(authority) {
|
|
155
|
+
const state = AUTHORITIES.get(authority);
|
|
156
|
+
if (!state) fail("a branded cohort enrollment authority is required");
|
|
157
|
+
return state;
|
|
158
|
+
}
|
|
159
|
+
function scopeId(input) {
|
|
160
|
+
return text(
|
|
161
|
+
record(input, ["cohortId"], "cohort lookup").cohortId,
|
|
162
|
+
"cohortId",
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
function allEvents(state) {
|
|
166
|
+
return EvolutionLedger.prototype.read.call(state.ledger);
|
|
167
|
+
}
|
|
168
|
+
function head(state) {
|
|
169
|
+
return EvolutionLedger.prototype.verify.call(state.ledger);
|
|
170
|
+
}
|
|
171
|
+
function eventId(state, cohortId, type) {
|
|
172
|
+
return `${type}.${hash("eval-cohort-identity/v1", { tenantId: state.descriptor.tenantId, streamId: state.descriptor.streamId, cohortId }).slice(7)}`;
|
|
173
|
+
}
|
|
174
|
+
function matching(state, cohortId, type) {
|
|
175
|
+
return allEvents(state).filter(
|
|
176
|
+
(event) =>
|
|
177
|
+
event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
|
|
178
|
+
event.eventId === eventId(state, cohortId, type),
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
function admissions(state) {
|
|
182
|
+
return allEvents(state).filter(
|
|
183
|
+
(event) =>
|
|
184
|
+
event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
|
|
185
|
+
event.type === EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE &&
|
|
186
|
+
event.tenantId === state.descriptor.tenantId &&
|
|
187
|
+
event.correlationId === state.descriptor.streamId,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
function readArtifact(state, event) {
|
|
191
|
+
const identity = head(state);
|
|
192
|
+
const result = state.resolveArtifact({
|
|
193
|
+
epoch: identity.epoch,
|
|
194
|
+
ledgerId: identity.ledgerId,
|
|
195
|
+
ref: event.subjectRef,
|
|
196
|
+
tenantId: state.descriptor.artifactTenantId,
|
|
197
|
+
});
|
|
198
|
+
if (
|
|
199
|
+
result?.schema !== EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA ||
|
|
200
|
+
result.authenticated !== true ||
|
|
201
|
+
result.found !== true ||
|
|
202
|
+
result.ref !== event.subjectRef.ref ||
|
|
203
|
+
result.digest !== event.subjectRef.digest ||
|
|
204
|
+
!Buffer.isBuffer(result.bytes)
|
|
205
|
+
)
|
|
206
|
+
fail("cohort artifact resolution rejected");
|
|
207
|
+
let stored;
|
|
208
|
+
try {
|
|
209
|
+
stored = JSON.parse(result.bytes.toString("utf8"));
|
|
210
|
+
} catch {
|
|
211
|
+
fail("cohort artifact is not JSON");
|
|
212
|
+
}
|
|
213
|
+
if (
|
|
214
|
+
stored.schema !== EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA ||
|
|
215
|
+
stored.tenantId !== state.descriptor.artifactTenantId ||
|
|
216
|
+
stored.audience !== state.descriptor.audience ||
|
|
217
|
+
stored.purpose !== state.descriptor.purpose ||
|
|
218
|
+
stored.retention !== "ledger" ||
|
|
219
|
+
stored.type !== ARTIFACT_TYPE
|
|
220
|
+
)
|
|
221
|
+
fail("cohort durable artifact scope differs");
|
|
222
|
+
return stored.value;
|
|
223
|
+
}
|
|
224
|
+
function signatureMessage(core) {
|
|
225
|
+
return Buffer.from(`${core.schema}\0${canonical(core)}`, "utf8");
|
|
226
|
+
}
|
|
227
|
+
function verifySigned(state, value, schema, fields) {
|
|
228
|
+
const evidence = record(
|
|
229
|
+
value,
|
|
230
|
+
["schema", "descriptor", ...fields, "attestation"],
|
|
231
|
+
"cohort signed evidence",
|
|
232
|
+
);
|
|
233
|
+
if (
|
|
234
|
+
evidence.schema !== schema ||
|
|
235
|
+
canonical(evidence.descriptor) !== canonical(state.descriptor)
|
|
236
|
+
)
|
|
237
|
+
fail("cohort evidence scope is substituted");
|
|
238
|
+
const attestation = record(
|
|
239
|
+
evidence.attestation,
|
|
240
|
+
["algorithm", "issuer", "keyId", "trustPolicyDigest", "value"],
|
|
241
|
+
"cohort attestation",
|
|
242
|
+
);
|
|
243
|
+
if (
|
|
244
|
+
attestation.algorithm !== "ed25519" ||
|
|
245
|
+
attestation.issuer !== state.descriptor.authorityId ||
|
|
246
|
+
attestation.keyId !== state.descriptor.keyId ||
|
|
247
|
+
attestation.trustPolicyDigest !== state.descriptor.trustPolicyDigest ||
|
|
248
|
+
typeof attestation.value !== "string" ||
|
|
249
|
+
!/^[A-Za-z0-9_-]{86}$/u.test(attestation.value)
|
|
250
|
+
)
|
|
251
|
+
fail("cohort signature trust differs from fixed anchor");
|
|
252
|
+
const core = { ...evidence };
|
|
253
|
+
delete core.attestation;
|
|
254
|
+
const bytes = Buffer.from(attestation.value, "base64url");
|
|
255
|
+
if (
|
|
256
|
+
bytes.length !== 64 ||
|
|
257
|
+
bytes.toString("base64url") !== attestation.value ||
|
|
258
|
+
!verify(null, signatureMessage(core), state.publicKey, bytes)
|
|
259
|
+
)
|
|
260
|
+
fail("cohort Ed25519 signature rejected");
|
|
261
|
+
if (
|
|
262
|
+
typeof evidence.issuedAt !== "string" ||
|
|
263
|
+
!Number.isFinite(Date.parse(evidence.issuedAt)) ||
|
|
264
|
+
new Date(evidence.issuedAt).toISOString() !== evidence.issuedAt
|
|
265
|
+
)
|
|
266
|
+
fail("cohort issuedAt is invalid");
|
|
267
|
+
return frozen(snapshot(evidence));
|
|
268
|
+
}
|
|
269
|
+
function sign(state, core) {
|
|
270
|
+
return {
|
|
271
|
+
...core,
|
|
272
|
+
attestation: {
|
|
273
|
+
algorithm: "ed25519",
|
|
274
|
+
issuer: state.descriptor.authorityId,
|
|
275
|
+
keyId: state.descriptor.keyId,
|
|
276
|
+
trustPolicyDigest: state.descriptor.trustPolicyDigest,
|
|
277
|
+
value: state.sign(
|
|
278
|
+
Object.freeze({ message: signatureMessage(core).toString("utf8") }),
|
|
279
|
+
),
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function issuedAt(state) {
|
|
284
|
+
const now = state.now();
|
|
285
|
+
if (!Number.isFinite(now)) fail("cohort clock is invalid");
|
|
286
|
+
return new Date(now).toISOString();
|
|
287
|
+
}
|
|
288
|
+
function validateRegistration(input) {
|
|
289
|
+
const source = record(
|
|
290
|
+
snapshot(input),
|
|
291
|
+
["plan", "manifest", "slots"],
|
|
292
|
+
"cohort registration",
|
|
293
|
+
);
|
|
294
|
+
const plan = verifyPmExplorationEffectPlan(source.plan);
|
|
295
|
+
const manifest = verifyPmExplorationEffectSlotManifest({
|
|
296
|
+
plan,
|
|
297
|
+
manifest: source.manifest,
|
|
298
|
+
});
|
|
299
|
+
if (
|
|
300
|
+
!Array.isArray(source.slots) ||
|
|
301
|
+
source.slots.length !== manifest.slotIds.length
|
|
302
|
+
)
|
|
303
|
+
fail("cohort slots must cover the complete manifest");
|
|
304
|
+
const slots = source.slots.map((slot, index) => {
|
|
305
|
+
const output = record(slot, SLOT_KEYS, "cohort slot");
|
|
306
|
+
if (output.slotId !== manifest.slotIds[index])
|
|
307
|
+
fail("cohort slots differ from manifest membership/order");
|
|
308
|
+
for (const field of SLOT_KEYS.filter((key) => key !== "slotId"))
|
|
309
|
+
digest(output[field], field);
|
|
310
|
+
return output;
|
|
311
|
+
});
|
|
312
|
+
return frozen({ plan, manifest, slots });
|
|
313
|
+
}
|
|
314
|
+
const ENROLL_FIELDS = ["cohortId", "plan", "manifest", "slots", "issuedAt"];
|
|
315
|
+
const SEAL_FIELDS = [
|
|
316
|
+
"cohortId",
|
|
317
|
+
"enrollmentDigest",
|
|
318
|
+
"inventory",
|
|
319
|
+
"preSealHead",
|
|
320
|
+
"issuedAt",
|
|
321
|
+
];
|
|
322
|
+
function checkEvent(state, event, cohortId, type, evidence, sourceRefs) {
|
|
323
|
+
if (
|
|
324
|
+
event.eventId !== eventId(state, cohortId, type) ||
|
|
325
|
+
event.type !== type ||
|
|
326
|
+
event.tenantId !== state.descriptor.tenantId ||
|
|
327
|
+
event.artifactTenantId !== state.descriptor.artifactTenantId ||
|
|
328
|
+
event.correlationId !== state.descriptor.streamId ||
|
|
329
|
+
event.decision !== "accepted" ||
|
|
330
|
+
event.skillName !== "evolution-eval" ||
|
|
331
|
+
event.timestamp !== evidence.issuedAt ||
|
|
332
|
+
canonical(event.sourceRefs) !== canonical(sourceRefs)
|
|
333
|
+
)
|
|
334
|
+
fail("cohort Ledger event differs from signed evidence");
|
|
335
|
+
}
|
|
336
|
+
function resolveEnrollment(state, cohortId) {
|
|
337
|
+
const found = matching(
|
|
338
|
+
state,
|
|
339
|
+
cohortId,
|
|
340
|
+
EVOLUTION_EVAL_COHORT_ENROLLMENT_EVENT_TYPE,
|
|
341
|
+
);
|
|
342
|
+
if (found.length !== 1) fail("cohort enrollment is absent or ambiguous");
|
|
343
|
+
const event = found[0];
|
|
344
|
+
const evidence = verifySigned(
|
|
345
|
+
state,
|
|
346
|
+
readArtifact(state, event),
|
|
347
|
+
EVOLUTION_EVAL_COHORT_ENROLLMENT_SCHEMA,
|
|
348
|
+
ENROLL_FIELDS,
|
|
349
|
+
);
|
|
350
|
+
const registration = validateRegistration({
|
|
351
|
+
plan: evidence.plan,
|
|
352
|
+
manifest: evidence.manifest,
|
|
353
|
+
slots: evidence.slots,
|
|
354
|
+
});
|
|
355
|
+
if (
|
|
356
|
+
evidence.cohortId !== cohortId ||
|
|
357
|
+
registration.manifest.cohortId !== cohortId
|
|
358
|
+
)
|
|
359
|
+
fail("cohort enrollment identity differs");
|
|
360
|
+
checkEvent(
|
|
361
|
+
state,
|
|
362
|
+
event,
|
|
363
|
+
cohortId,
|
|
364
|
+
EVOLUTION_EVAL_COHORT_ENROLLMENT_EVENT_TYPE,
|
|
365
|
+
evidence,
|
|
366
|
+
[],
|
|
367
|
+
);
|
|
368
|
+
return frozen({
|
|
369
|
+
schema: "chainlesschain.evolution-eval-cohort-enrollment-resolution/v1",
|
|
370
|
+
enrollmentDigest: hash(evidence.schema, evidence),
|
|
371
|
+
evidence,
|
|
372
|
+
enrollmentRef: event.subjectRef,
|
|
373
|
+
enrollmentSequence: event.sequence,
|
|
374
|
+
authenticated: true,
|
|
375
|
+
durable: true,
|
|
376
|
+
...LIMITS,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
function publish(state, cohortId, type, evidence, sourceRefs, expectedHead) {
|
|
380
|
+
const published = EvolutionArtifactPorts.prototype.putCanonical.call(
|
|
381
|
+
state.artifactPorts,
|
|
382
|
+
ARTIFACT_TYPE,
|
|
383
|
+
evidence,
|
|
384
|
+
{
|
|
385
|
+
audience: state.descriptor.audience,
|
|
386
|
+
purpose: state.descriptor.purpose,
|
|
387
|
+
retention: "ledger",
|
|
388
|
+
},
|
|
389
|
+
);
|
|
390
|
+
if (
|
|
391
|
+
published?.receipt?.persisted !== true ||
|
|
392
|
+
published.receipt.readbackVerified !== true ||
|
|
393
|
+
published.receipt.integrityVerified !== true ||
|
|
394
|
+
published.receipt.retention !== "ledger"
|
|
395
|
+
)
|
|
396
|
+
fail("cohort artifact persistence failed");
|
|
397
|
+
const receipt = EvolutionLedger.prototype.appendDomainEvent.call(
|
|
398
|
+
state.ledger,
|
|
399
|
+
{
|
|
400
|
+
type,
|
|
401
|
+
eventId: eventId(state, cohortId, type),
|
|
402
|
+
tenantId: state.descriptor.tenantId,
|
|
403
|
+
artifactTenantId: state.descriptor.artifactTenantId,
|
|
404
|
+
correlationId: state.descriptor.streamId,
|
|
405
|
+
decision: "accepted",
|
|
406
|
+
skillName: "evolution-eval",
|
|
407
|
+
reason:
|
|
408
|
+
"signed cohort admission inventory; execution coverage remains unproven",
|
|
409
|
+
sourceRefs,
|
|
410
|
+
subjectRef: published.ref,
|
|
411
|
+
timestamp: evidence.issuedAt,
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
expectedHeadDigest: expectedHead.headDigest,
|
|
415
|
+
expectedSequence: expectedHead.sequence,
|
|
416
|
+
},
|
|
417
|
+
);
|
|
418
|
+
if (receipt?.authenticated !== true || receipt.durable !== true)
|
|
419
|
+
fail("cohort Ledger persistence failed");
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export function createEvolutionEvalCohortEnrollmentAuthority({
|
|
423
|
+
descriptor,
|
|
424
|
+
publicKey,
|
|
425
|
+
signer,
|
|
426
|
+
artifactPorts,
|
|
427
|
+
ledger,
|
|
428
|
+
ledgerArtifactResolver,
|
|
429
|
+
now = Date.now,
|
|
430
|
+
} = {}) {
|
|
431
|
+
const scope = record(
|
|
432
|
+
descriptor,
|
|
433
|
+
DESCRIPTOR_KEYS,
|
|
434
|
+
"cohort authority descriptor",
|
|
435
|
+
);
|
|
436
|
+
for (const key of DESCRIPTOR_KEYS) text(scope[key], key);
|
|
437
|
+
digest(scope.trustPolicyDigest, "trustPolicyDigest");
|
|
438
|
+
if (scope.purpose !== "evolution-ledger")
|
|
439
|
+
fail("cohort requires Ledger retention purpose");
|
|
440
|
+
if (
|
|
441
|
+
!(artifactPorts instanceof EvolutionArtifactPorts) ||
|
|
442
|
+
isProxy(artifactPorts) ||
|
|
443
|
+
!(ledger instanceof EvolutionLedger) ||
|
|
444
|
+
isProxy(ledger) ||
|
|
445
|
+
!isEvolutionLedgerArtifactResolver(ledgerArtifactResolver)
|
|
446
|
+
)
|
|
447
|
+
fail("cohort requires real artifact ports, Ledger and branded resolver");
|
|
448
|
+
if (!signer || isProxy(signer) || typeof now !== "function" || isProxy(now))
|
|
449
|
+
fail("cohort signer and clock are required");
|
|
450
|
+
const signing = Object.getOwnPropertyDescriptor(signer, "sign")?.value;
|
|
451
|
+
if (typeof signing !== "function" || isProxy(signing))
|
|
452
|
+
fail("cohort signer must be an own callable");
|
|
453
|
+
const key =
|
|
454
|
+
publicKey instanceof KeyObject && publicKey.type === "public"
|
|
455
|
+
? publicKey
|
|
456
|
+
: createPublicKey(publicKey);
|
|
457
|
+
if (key.asymmetricKeyType !== "ed25519")
|
|
458
|
+
fail("cohort anchor must be Ed25519");
|
|
459
|
+
const authority = Object.freeze({ descriptor: frozen(scope) });
|
|
460
|
+
AUTHORITIES.set(authority, {
|
|
461
|
+
descriptor: authority.descriptor,
|
|
462
|
+
publicKey: key,
|
|
463
|
+
sign: signing.bind(signer),
|
|
464
|
+
artifactPorts,
|
|
465
|
+
ledger,
|
|
466
|
+
resolveArtifact: ledgerArtifactResolver,
|
|
467
|
+
now,
|
|
468
|
+
});
|
|
469
|
+
return authority;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export function enrollEvolutionEvalCohort(authority, input) {
|
|
473
|
+
const state = stateOf(authority);
|
|
474
|
+
const registration = validateRegistration(input);
|
|
475
|
+
const cohortId = registration.manifest.cohortId;
|
|
476
|
+
const expectedHead = head(state);
|
|
477
|
+
if (
|
|
478
|
+
matching(state, cohortId, EVOLUTION_EVAL_COHORT_ENROLLMENT_EVENT_TYPE)
|
|
479
|
+
.length ||
|
|
480
|
+
matching(state, cohortId, EVOLUTION_EVAL_COHORT_SEAL_EVENT_TYPE).length
|
|
481
|
+
)
|
|
482
|
+
fail("cohort is already enrolled or sealed");
|
|
483
|
+
// All cohorts sharing a stream must be enrolled before its first admission.
|
|
484
|
+
// Legacy admissions cannot establish a trustworthy cohort identity.
|
|
485
|
+
if (admissions(state).length)
|
|
486
|
+
fail("stream admission already exists before enrollment");
|
|
487
|
+
const evidence = verifySigned(
|
|
488
|
+
state,
|
|
489
|
+
sign(state, {
|
|
490
|
+
schema: EVOLUTION_EVAL_COHORT_ENROLLMENT_SCHEMA,
|
|
491
|
+
descriptor: state.descriptor,
|
|
492
|
+
cohortId,
|
|
493
|
+
...registration,
|
|
494
|
+
issuedAt: issuedAt(state),
|
|
495
|
+
}),
|
|
496
|
+
EVOLUTION_EVAL_COHORT_ENROLLMENT_SCHEMA,
|
|
497
|
+
ENROLL_FIELDS,
|
|
498
|
+
);
|
|
499
|
+
publish(
|
|
500
|
+
state,
|
|
501
|
+
cohortId,
|
|
502
|
+
EVOLUTION_EVAL_COHORT_ENROLLMENT_EVENT_TYPE,
|
|
503
|
+
evidence,
|
|
504
|
+
[],
|
|
505
|
+
expectedHead,
|
|
506
|
+
);
|
|
507
|
+
const result = resolveEnrollment(state, cohortId);
|
|
508
|
+
if (canonical(result.evidence) !== canonical(evidence))
|
|
509
|
+
fail("cohort enrollment readback differs");
|
|
510
|
+
return result;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export function resolveEvolutionEvalCohortEnrollment(authority, input) {
|
|
514
|
+
return resolveEnrollment(stateOf(authority), scopeId(input));
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function slotDescriptor(state, enrollment, slot) {
|
|
518
|
+
return frozen({
|
|
519
|
+
...state.descriptor,
|
|
520
|
+
planDigest: slot.evaluationPlanDigest,
|
|
521
|
+
manifestDigest: enrollment.evidence.manifest.manifestDigest,
|
|
522
|
+
cohortId: enrollment.evidence.cohortId,
|
|
523
|
+
slotId: slot.slotId,
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
function deriveSlot(state, enrollment, slot) {
|
|
527
|
+
const descriptor = slotDescriptor(state, enrollment, slot);
|
|
528
|
+
const expectedRequest = frozen({
|
|
529
|
+
requestDigest: slot.requestDigest,
|
|
530
|
+
policyDigest: slot.policyDigest,
|
|
531
|
+
evaluationAuthorityRoot: slot.evaluationAuthorityRoot,
|
|
532
|
+
});
|
|
533
|
+
const binding = Object.freeze({});
|
|
534
|
+
SLOT_BINDINGS.set(binding, {
|
|
535
|
+
state,
|
|
536
|
+
descriptor,
|
|
537
|
+
enrollmentDigest: enrollment.enrollmentDigest,
|
|
538
|
+
enrollmentRef: enrollment.enrollmentRef,
|
|
539
|
+
expectedRequest,
|
|
540
|
+
assertOpen(input) {
|
|
541
|
+
const current = resolveEnrollment(state, descriptor.cohortId);
|
|
542
|
+
if (current.enrollmentDigest !== enrollment.enrollmentDigest)
|
|
543
|
+
fail("cohort enrollment changed");
|
|
544
|
+
if (
|
|
545
|
+
matching(
|
|
546
|
+
state,
|
|
547
|
+
descriptor.cohortId,
|
|
548
|
+
EVOLUTION_EVAL_COHORT_SEAL_EVENT_TYPE,
|
|
549
|
+
).length
|
|
550
|
+
)
|
|
551
|
+
fail("cohort is sealed");
|
|
552
|
+
for (const key of Object.keys(expectedRequest))
|
|
553
|
+
if (input[key] !== expectedRequest[key])
|
|
554
|
+
fail("admission request differs from enrolled slot");
|
|
555
|
+
},
|
|
556
|
+
});
|
|
557
|
+
return createEvolutionEvalLaunchAdmissionAuthority({
|
|
558
|
+
descriptor,
|
|
559
|
+
publicKey: state.publicKey,
|
|
560
|
+
signer: { sign: state.sign },
|
|
561
|
+
artifactPorts: state.artifactPorts,
|
|
562
|
+
ledger: state.ledger,
|
|
563
|
+
ledgerArtifactResolver: state.resolveArtifact,
|
|
564
|
+
now: state.now,
|
|
565
|
+
cohortSlotBinding: binding,
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** Internal branded capability capture: data copies and different storage/key ports are rejected. */
|
|
570
|
+
export function captureEvolutionEvalCohortSlotBinding(binding, expected) {
|
|
571
|
+
const captured = SLOT_BINDINGS.get(binding);
|
|
572
|
+
if (
|
|
573
|
+
!captured ||
|
|
574
|
+
canonical(captured.descriptor) !== canonical(expected.descriptor) ||
|
|
575
|
+
captured.state.ledger !== expected.ledger ||
|
|
576
|
+
captured.state.artifactPorts !== expected.artifactPorts ||
|
|
577
|
+
captured.state.resolveArtifact !== expected.ledgerArtifactResolver ||
|
|
578
|
+
!captured.state.publicKey.equals(expected.publicKey)
|
|
579
|
+
)
|
|
580
|
+
fail("a matching branded cohort slot binding is required");
|
|
581
|
+
return Object.freeze({
|
|
582
|
+
enrollmentDigest: captured.enrollmentDigest,
|
|
583
|
+
enrollmentRef: captured.enrollmentRef,
|
|
584
|
+
expectedRequest: captured.expectedRequest,
|
|
585
|
+
assertOpen: captured.assertOpen,
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
export function createEvolutionEvalCohortSlotAdmissionAuthority(
|
|
590
|
+
authority,
|
|
591
|
+
input,
|
|
592
|
+
) {
|
|
593
|
+
const state = stateOf(authority);
|
|
594
|
+
const lookup = record(input, ["cohortId", "slotId"], "cohort slot lookup");
|
|
595
|
+
text(lookup.cohortId, "cohortId");
|
|
596
|
+
text(lookup.slotId, "slotId");
|
|
597
|
+
const enrollment = resolveEnrollment(state, lookup.cohortId);
|
|
598
|
+
const slot = enrollment.evidence.slots.find(
|
|
599
|
+
(item) => item.slotId === lookup.slotId,
|
|
600
|
+
);
|
|
601
|
+
if (!slot) fail("slot is not in the enrolled manifest");
|
|
602
|
+
return deriveSlot(state, enrollment, slot);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async function inventory(state, enrollment, sealSequence = Infinity) {
|
|
606
|
+
const result = [];
|
|
607
|
+
const used = new Set();
|
|
608
|
+
for (const event of admissions(state)) {
|
|
609
|
+
const value = readArtifact(state, event);
|
|
610
|
+
// Reject ambiguous legacy entries instead of accepting a caller-selected subset.
|
|
611
|
+
if (!value.descriptor)
|
|
612
|
+
fail("legacy admission prevents complete cohort inventory");
|
|
613
|
+
const ownCohort =
|
|
614
|
+
value.descriptor.cohortId === enrollment.evidence.cohortId;
|
|
615
|
+
const registered = ownCohort
|
|
616
|
+
? enrollment
|
|
617
|
+
: resolveEnrollment(
|
|
618
|
+
state,
|
|
619
|
+
text(value.descriptor.cohortId, "admission cohortId"),
|
|
620
|
+
);
|
|
621
|
+
if (
|
|
622
|
+
event.sequence <= registered.enrollmentSequence ||
|
|
623
|
+
(ownCohort && event.sequence >= sealSequence)
|
|
624
|
+
)
|
|
625
|
+
fail("admission lies outside cohort enrollment/seal boundary");
|
|
626
|
+
const slot = registered.evidence.slots.find(
|
|
627
|
+
(item) => item.slotId === value.descriptor.slotId,
|
|
628
|
+
);
|
|
629
|
+
if (!slot || (ownCohort && used.has(slot.slotId)))
|
|
630
|
+
fail("unknown or duplicate cohort admission slot");
|
|
631
|
+
const resolution = await resolveEvolutionEvalLaunch(
|
|
632
|
+
deriveSlot(state, registered, slot),
|
|
633
|
+
{
|
|
634
|
+
runId: value.runId,
|
|
635
|
+
runNonce: value.runNonce,
|
|
636
|
+
requestDigest: value.requestDigest,
|
|
637
|
+
},
|
|
638
|
+
);
|
|
639
|
+
if (
|
|
640
|
+
resolution.eventId !== event.eventId ||
|
|
641
|
+
resolution.eventSequence !== event.sequence ||
|
|
642
|
+
canonical(resolution.evidence) !== canonical(value)
|
|
643
|
+
)
|
|
644
|
+
fail("cohort admission event substitution");
|
|
645
|
+
if (!ownCohort) continue;
|
|
646
|
+
used.add(slot.slotId);
|
|
647
|
+
result.push({
|
|
648
|
+
slotId: slot.slotId,
|
|
649
|
+
eventId: event.eventId,
|
|
650
|
+
sequence: event.sequence,
|
|
651
|
+
admissionDigest: resolution.admissionDigest,
|
|
652
|
+
runId: value.runId,
|
|
653
|
+
runNonce: value.runNonce,
|
|
654
|
+
requestDigest: value.requestDigest,
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
return frozen({
|
|
658
|
+
admissions: result,
|
|
659
|
+
unadmittedSlotIds: enrollment.evidence.slots
|
|
660
|
+
.filter((slot) => !used.has(slot.slotId))
|
|
661
|
+
.map((slot) => slot.slotId),
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/** Seal competes with every admission at the same Ledger CAS head. No silent retry. */
|
|
666
|
+
export async function sealEvolutionEvalCohort(authority, input) {
|
|
667
|
+
const state = stateOf(authority);
|
|
668
|
+
const cohortId = scopeId(input);
|
|
669
|
+
const expectedHead = head(state);
|
|
670
|
+
const enrollment = resolveEnrollment(state, cohortId);
|
|
671
|
+
if (matching(state, cohortId, EVOLUTION_EVAL_COHORT_SEAL_EVENT_TYPE).length)
|
|
672
|
+
fail("cohort is already sealed");
|
|
673
|
+
const contents = await inventory(state, enrollment);
|
|
674
|
+
const evidence = verifySigned(
|
|
675
|
+
state,
|
|
676
|
+
sign(state, {
|
|
677
|
+
schema: EVOLUTION_EVAL_COHORT_SEAL_SCHEMA,
|
|
678
|
+
descriptor: state.descriptor,
|
|
679
|
+
cohortId,
|
|
680
|
+
enrollmentDigest: enrollment.enrollmentDigest,
|
|
681
|
+
inventory: contents,
|
|
682
|
+
preSealHead: {
|
|
683
|
+
headDigest: expectedHead.headDigest,
|
|
684
|
+
sequence: expectedHead.sequence,
|
|
685
|
+
},
|
|
686
|
+
issuedAt: issuedAt(state),
|
|
687
|
+
}),
|
|
688
|
+
EVOLUTION_EVAL_COHORT_SEAL_SCHEMA,
|
|
689
|
+
SEAL_FIELDS,
|
|
690
|
+
);
|
|
691
|
+
publish(
|
|
692
|
+
state,
|
|
693
|
+
cohortId,
|
|
694
|
+
EVOLUTION_EVAL_COHORT_SEAL_EVENT_TYPE,
|
|
695
|
+
evidence,
|
|
696
|
+
[enrollment.enrollmentRef],
|
|
697
|
+
expectedHead,
|
|
698
|
+
);
|
|
699
|
+
return resolveEvolutionEvalCohortReconciliation(authority, { cohortId });
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/** Enumerates actual retained Ledger events; input cannot supply an admission subset. */
|
|
703
|
+
export async function resolveEvolutionEvalCohortReconciliation(
|
|
704
|
+
authority,
|
|
705
|
+
input,
|
|
706
|
+
) {
|
|
707
|
+
const state = stateOf(authority);
|
|
708
|
+
const cohortId = scopeId(input);
|
|
709
|
+
const expectedHead = head(state);
|
|
710
|
+
const enrollment = resolveEnrollment(state, cohortId);
|
|
711
|
+
const matches = matching(
|
|
712
|
+
state,
|
|
713
|
+
cohortId,
|
|
714
|
+
EVOLUTION_EVAL_COHORT_SEAL_EVENT_TYPE,
|
|
715
|
+
);
|
|
716
|
+
if (matches.length !== 1) fail("cohort seal is absent or ambiguous");
|
|
717
|
+
const event = matches[0];
|
|
718
|
+
const evidence = verifySigned(
|
|
719
|
+
state,
|
|
720
|
+
readArtifact(state, event),
|
|
721
|
+
EVOLUTION_EVAL_COHORT_SEAL_SCHEMA,
|
|
722
|
+
SEAL_FIELDS,
|
|
723
|
+
);
|
|
724
|
+
checkEvent(
|
|
725
|
+
state,
|
|
726
|
+
event,
|
|
727
|
+
cohortId,
|
|
728
|
+
EVOLUTION_EVAL_COHORT_SEAL_EVENT_TYPE,
|
|
729
|
+
evidence,
|
|
730
|
+
[enrollment.enrollmentRef],
|
|
731
|
+
);
|
|
732
|
+
const previous = allEvents(state).find(
|
|
733
|
+
(item) => item.sequence === event.sequence - 1,
|
|
734
|
+
);
|
|
735
|
+
if (
|
|
736
|
+
evidence.cohortId !== cohortId ||
|
|
737
|
+
evidence.enrollmentDigest !== enrollment.enrollmentDigest ||
|
|
738
|
+
event.sequence <= enrollment.enrollmentSequence ||
|
|
739
|
+
canonical(evidence.preSealHead) !==
|
|
740
|
+
canonical({
|
|
741
|
+
headDigest: previous?.eventDigest ?? null,
|
|
742
|
+
sequence: event.sequence - 1,
|
|
743
|
+
})
|
|
744
|
+
)
|
|
745
|
+
fail("cohort seal boundary differs");
|
|
746
|
+
const contents = await inventory(state, enrollment, event.sequence);
|
|
747
|
+
if (canonical(contents) !== canonical(evidence.inventory))
|
|
748
|
+
fail("sealed cohort inventory differs from complete Ledger events");
|
|
749
|
+
const currentHead = head(state);
|
|
750
|
+
if (
|
|
751
|
+
currentHead.headDigest !== expectedHead.headDigest ||
|
|
752
|
+
currentHead.sequence !== expectedHead.sequence
|
|
753
|
+
)
|
|
754
|
+
fail("Ledger changed during cohort reconciliation; retry audit");
|
|
755
|
+
return frozen({
|
|
756
|
+
schema: "chainlesschain.evolution-eval-cohort-reconciliation/v1",
|
|
757
|
+
cohortId,
|
|
758
|
+
enrollmentDigest: enrollment.enrollmentDigest,
|
|
759
|
+
sealDigest: hash(evidence.schema, evidence),
|
|
760
|
+
sealSequence: event.sequence,
|
|
761
|
+
inventory: contents,
|
|
762
|
+
plannedTestObservationsPerArm:
|
|
763
|
+
enrollment.evidence.manifest.plannedTestObservationsPerArm,
|
|
764
|
+
admissionInventoryAuthenticated: true,
|
|
765
|
+
executionCoverageAuthenticated: false,
|
|
766
|
+
authenticated: true,
|
|
767
|
+
durable: true,
|
|
768
|
+
...LIMITS,
|
|
769
|
+
});
|
|
770
|
+
}
|