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.
Files changed (166) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-BlIvP3k1.js → AIOps-CNaejClV.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DYF7atSV.js → ActionButton-CF_CVKT_.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-LZYaYek6.js → Analytics-a3Z6J7gv.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BJxrjNbj.js → AppLayout-BFtWEnct.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-gEDhxhmE.js → Artifacts-BQ8oeMvX.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-B0MR950Q.js → Audit-NOo9bmgk.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-3e6Os_Kl.js → BackgroundAgents-QRc7F3Tp.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DB_X8KUg.js → Backup-UlVgLn2P.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-DTNcvNeG.js → BaseInput-BER9LJAr.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-SnqdA62j.js → Chat-Z8z2Fdfz.js} +6 -6
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BaiWNH_V.js → ChatBubbleRenderer-DdmuBrdQ.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-Dj0O4dyP.js → Checkbox-CXPgyB8L.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-BeelW3dx.js → Codegen-D1vOsLJ7.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BmstiyBM.js → Col-ucLnUJC7.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-CrbmFk3f.js → Community-COsV9n9t.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DCg5ZPIw.js → Compact-D0EkBEYh.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-B3sajhq7.js → Compliance-C8w9SUjt.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-DWcdvrDK.js → Cowork-CmVaKEJS.js} +4 -4
  20. package/src/assets/web-panel/assets/{Cron-Bjwp_NDf.js → Cron-B_FiMMV2.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BXTLC9o8.js → Crosschain-ByO3YL8N.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-Di62M46b.js → DID-DwpsLM9r.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-BQED8Rkt.js → Dashboard-B_8IUvM_.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DEf9VYaj.js → Dropdown-Bo6WQkuX.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-DhFpPMAM.js → EmailListRenderer-C9LiQesx.js} +1 -1
  26. package/src/assets/web-panel/assets/{EvolutionSettings-BOqmzkpS.js → EvolutionSettings-Pc1IpRfk.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BxBnJ4fe.js → FamilyGuardDashboard-Dst6VUnO.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BN9Q8nsZ.js → Federation-Ci7CoLkJ.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-CGeqFEd-.js → FormItemContext-bdDyUhUM.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-DElmWQTc.js → GenericCardRenderer-CrRwOUVi.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-BHBSgKck.js → Git-Dis8h-Z-.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-Breo3NTU.js → Governance-DX7OH5w2.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CCABy4E0.js → Inference-Cavv_Q_Z.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-B6_ryn-X.js → KnowledgeGraph-Cck8tnZn.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-CkmJjJok.js → Logs-BQt3aGMu.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-BIUeeiVA.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-iip65jxv.js → Marketplace-CdmAKNSN.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DDwp_QLb.js → McpTools-BUlJdyPY.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-2ZmNDRkC.js → Memory-DQRTQDr-.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C6HilwZl.js → MobileBridge-C0dnxgsl.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BeMtYRhx.js → MobileProjects-DQ5Gy7fa.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-Bp-FEcoo.js → Mtc-Xl7u2isS.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-DNdkTCe5.js → MtcAudit-C3KX0574.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-PnKg2_Eo.js → Multisig-CHEhfkn8.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-DDp4lZeG.js → NLProgramming-Ce38mH-8.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-DEjFktcO.js → Notes-C7nuTd7c.js} +4 -4
  47. package/src/assets/web-panel/assets/{NotificationSettings-FR8fJDAn.js → NotificationSettings-BcoEcyq8.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-Cyc-XI0L.js → OrderTableRenderer-D-t5hKkx.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-DNW2E_JU.js → Organization-C_BGi4xi.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-BHfd6wk6.js → Overflow-BodhraDq.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-COIkaXH4.js → P2P-BTa3sAIy.js} +2 -2
  52. package/src/assets/web-panel/assets/PdhVaultBrowser-BjZslP9T.js +7 -0
  53. package/src/assets/web-panel/assets/{Permissions-BfVRGMy8.js → Permissions-u3UDzGef.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-BWYjO6Aa.js → PersonalDataHub-Cb7ybv65.js} +4 -4
  55. package/src/assets/web-panel/assets/{Pipeline-C0e0fPBW.js → Pipeline-CS24k-P7.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-CnId4Jv-.js → Privacy-Ddj6Kqs7.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-CYf1grXg.js → ProjectInit-Bg5uQIgg.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-HsXgJdiH.js → ProjectSettings-AmPR8T12.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-Bi0r9QcC.js → Projects-DGSbAyTK.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-B-Tu_-_4.js → Providers-Dc1C3lbB.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-CPDqYT2F.js → QrScannerModal-Cv3HXpce.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-Df6qcjXy.js → QuickAsk-3dpbXARb.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-dP6sfGSY.js → Recommend-5aGRVnJK.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-VAt9-tM3.js → RemoteSession-CTS2jx0p.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-DtRVRiLI.js → Reputation-BxaKI0hY.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-B6Ukqvli.js → Row-C23uQdwd.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-DfVRQMrZ.js → RssFeed-ssX9YOhm.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-CyncAiqQ.js → Search-C24GogII.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-DEO7nrkb.js → Security-DdAcGKkk.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-CkusQEhN.js → Services-D0dCiEuq.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-CbGtO3kc.js → Skeleton-DEY44o0v.js} +1 -1
  72. package/src/assets/web-panel/assets/Skills-CYt0Mu2W.js +1 -0
  73. package/src/assets/web-panel/assets/{Sla-CIu9Ahak.js → Sla-B_bbo2vB.js} +1 -1
  74. package/src/assets/web-panel/assets/SpeechSettings-a2BBjtTL.js +1 -0
  75. package/src/assets/web-panel/assets/{SyncSettings-BAOLFlRq.js → SyncSettings-CpIXql0Z.js} +2 -2
  76. package/src/assets/web-panel/assets/Tasks-BYQKU-GL.js +1 -0
  77. package/src/assets/web-panel/assets/{Templates-Dkr_vRdJ.js → Templates-C_44nVPq.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-kM7lHUFR.js → Tenant-CyZ2ey2P.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-9zfc41aU.js → Terminal-DwGNHWnp.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-Cg_7j6cj.js → TimelineRenderer-BTAHNkqU.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-Cs1aikaM.js → Tokens-DCJWkUwc.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DKYPJ9gl.js → Trigger-BCjDO9-E.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-BFy1Sm8B.js → Trust-_YS8WbRb.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-B31L9NBH.js → UkeySign-m6R8xGq7.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-OMmUYdIC.js → VideoEditing-xOfk29c4.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-y3aE7oru.js → Wallet-B1Gw0awc.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-C0ICKvpu.js → WebAuthn-CHK5ft18.js} +4 -4
  88. package/src/assets/web-panel/assets/{WorkflowEditor-Cq5UYbr5.js → WorkflowEditor-DEp1ukQQ.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-B1ijaKFv.js → chat-B2sFizun.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-CHkI8PDg.js → colors-DJ17YV1E.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-1BYvgWEs.js → compact-item-CBhJJgEC.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-BGti56u4.js → createContext-BZkpvNJy.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DZhu13vj.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-Cr87Fph1.js → hasIn-C0ZKo6Ei.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CkcWhgLB.js → index-4oULtRqE.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Duv0TfJa.js → index-5K2z_tgO.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-D6g4jxdE.js → index-8ueG48gl.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Dnp-4yPc.js → index-BEnd5fiz.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Dam-LB_J.js → index-BGIvhCPl.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-fhpMyq0u.js → index-BMxOoITz.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-C_lEztok.js → index-BNp6HKFh.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CjBkVrq9.js → index-BOfPp5OV.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DzevrmLK.js → index-Bc3vVG2X.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Bni5GodE.js → index-BoDUYyuo.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BA0FMuDX.js → index-BpyrhOeh.js} +1 -1
  106. package/src/assets/web-panel/assets/index-C6iFyQYz.js +1 -0
  107. package/src/assets/web-panel/assets/{index-B1yur8MU.js → index-C7gv9dvb.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CS0MIE2C.js → index-C9gYiACH.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DHJtAEx8.js → index-CCOr6Q27.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-6Ta8Pg47.js → index-CW5o1Gar.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BOjTRSHE.js → index-CZW84cEf.js} +3 -3
  112. package/src/assets/web-panel/assets/{index-CvcpesEZ.js → index-CZlkPrxb.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BkFXPrdx.js → index-CdxJm-HB.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Bdkrut2A.js → index-Chct9tL8.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-rO6VKJv5.js → index-Cn5UzvgR.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BYpqBWlt.js → index-Ctguam0K.js} +1 -1
  117. package/src/assets/web-panel/assets/index-CztThH9f.js +1 -0
  118. package/src/assets/web-panel/assets/{index-tY479EoQ.js → index-DHtpMr1G.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CmmSJBNi.js → index-DJkoJzTU.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BjgtiMdY.js → index-DLMr5KMd.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-1WxCzqYq.js → index-DLo8Ls9u.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B4BSM3BK.js → index-DM0rWF6z.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DJjnXDAD.js → index-DOBXNMdh.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CDTNnQDz.js → index-Dfgxe-fw.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DcoI3ENn.js → index-DjdSFO0d.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Cvu95WPI.js → index-DrU5xVpF.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-rVnXNFST.js → index-DumLgj1t.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DCkvhzaY.js → index-Dxe0YlZe.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CevUJTXd.js → index-DyiCbHeL.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BKb16YKp.js → index-IHgzfc1u.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CQWMHlY7.js → index-KzNhWykP.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CbkGda_k.js → index-LPPe0val.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-B8Jb_cGt.js → index-vFMwiAN4.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DAGtnwoX.js → initDefaultProps-Cqfoq0TJ.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-02FXBi5C.js → motion-CIiVJHNu.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-BLf7rhzJ.js → move-CFl1o_A8.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-Ct6i1vqQ.js → mtc-parser-DYoCxcZ1.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DKvTU8IT.js → omit-C1P2q5TY.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DqDsKoMe.js → pickAttrs-BtTRpJtC.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-kae6Cnwx.js → placementArrow-Cst2PcNM.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-DzFM_TQf.js → responsiveObserve-CF5kalV2.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-qDjNFPuM.js → slide-CtHGqpXN.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-BihSr7G3.js → statusUtils-N__biHXf.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BzoT0TfJ.js → styleChecker-DR8V_H-i.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-CjXXcU1j.js → useFlexGapSupport-D274dqun.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-DrWcbDJ1.js → useFs-BwHLYU5b.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-DO1oBNTE.js → usePersonalDataHub-BiA-hVqt.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BR6crWko.js → vnode-Bugl94dy.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-DmKLfw6W.js → zoom-DEFl8GCu.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/data/changelog.json +26 -0
  152. package/src/lib/evolution/evolution-eval-child-evidence-ledger-adapter.js +2 -0
  153. package/src/lib/evolution/evolution-eval-cohort-enrollment.js +770 -0
  154. package/src/lib/evolution/evolution-eval-contracts.js +86 -0
  155. package/src/lib/evolution/evolution-eval-gate.js +136 -85
  156. package/src/lib/evolution/evolution-eval-launch-admission.js +505 -0
  157. package/src/lib/evolution/skill-target-matrix-eval.js +84 -3
  158. package/src/lib/with-file-lock.js +81 -16
  159. package/src/assets/web-panel/assets/MarkdownRenderer-DQEQBaRu.js +0 -1
  160. package/src/assets/web-panel/assets/PdhVaultBrowser-DuRP0UeX.js +0 -7
  161. package/src/assets/web-panel/assets/Skills-diOh0gAr.js +0 -1
  162. package/src/assets/web-panel/assets/SpeechSettings-_Nzyi4K9.js +0 -1
  163. package/src/assets/web-panel/assets/Tasks-BpmvL1Eq.js +0 -1
  164. package/src/assets/web-panel/assets/devWarning-Isft1nEX.js +0 -1
  165. package/src/assets/web-panel/assets/index-B_T9NUk7.js +0 -1
  166. 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(value) {
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
- AGGREGATOR_OPTION_KEYS,
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