chainlesschain 0.166.91 → 0.166.92
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 +17 -17
- package/package.json +3 -3
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DgV7xb8F.js → AIOps-C74YzqwJ.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CgANpkKu.js → ActionButton-TFef1hOE.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DnvpX7RB.js → Analytics-CYsWpkkU.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-C2bHccBM.js → AppLayout-CFf9kjwu.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-BIhijC9g.js → Artifacts-TQqa94YO.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CKRjWGdp.js → Audit-B79ayqfS.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CblYtgBE.js → BackgroundAgents-pjkHfLP9.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cq35b78a.js → Backup-CE6A-t_r.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DcB7NoRz.js → BaseInput-CwcgWMBY.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-tc3b-s7i.js → Chat-BIkDNesY.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DgaokYts.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-BLD5bH5u.js → Checkbox-MbypIy5V.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BLOsoazN.js → Codegen-DiFHWDnt.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bdr7JwIx.js → Col-BNMlYMso.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C84BsWE0.js → Community-B3HVyHOX.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dzdwd04z.js → Compact-C7hlAubb.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CCG-R0EV.js → Compliance-PaXZu6sE.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BYj72SK0.js → Cowork-BGiojbm-.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B6iKAwOf.js → Cron-Bmr-1QAx.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BJ-oDC6u.js → Crosschain-BwUvWCVd.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BnMckGLr.js → DID-k_4QZocW.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cyje-gCO.js → Dashboard-_ieRo2C5.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BpNlenjK.js → Dropdown-DYHh6T27.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BhonO7Nv.js → EmailListRenderer-BNlQcWQX.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DVoNU-Id.js → EvolutionSettings-DIkZ6U2D.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-tdn-KC67.js → FamilyGuardDashboard-Dq7qSr0P.js} +1 -1
- package/src/assets/web-panel/assets/{Federation--EEVrHhz.js → Federation-C64e3Cbx.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cy8zr0-4.js → FormItemContext-D-GE2vUa.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BuUhpgFi.js → GenericCardRenderer-DO3B2gis.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Ctd3E5Pe.js → Git-0ETirIQH.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Ce7dV6aU.js → Governance-C9fnRygX.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CD1vExIH.js → Inference-CLJ9RTsK.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Dn64OdQ7.js → KnowledgeGraph-D3C_GxrN.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-PmElVRrT.js → Logs-C5ctGbkN.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Ce-eWK3j.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-OW4jTXwx.js → Marketplace-GF_t6hJ_.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BEq2Ib4x.js → McpTools-BGsGzgQs.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Can_P2oK.js → Memory-CcrY2A0j.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DJ8R-dn3.js → MobileBridge-Bi4T0RlS.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B7kV9GOt.js → MobileProjects-DvjEGyvf.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BfxamolS.js → Mtc-DL77Vf-k.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DHtuv7av.js → MtcAudit-CDy_Uswb.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DLkLpvxc.js → Multisig-DL0BAO_c.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-u4XtJTIt.js → NLProgramming-B-woh5IR.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BwuuPJLS.js → Notes-CEFVCxk7.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-HEeu-E9v.js → NotificationSettings-BqPPMuAP.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BtvN-Qwh.js → OrderTableRenderer-GUKQ1xwp.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Yh-czs3b.js → Organization-B1gX8jlr.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DmE8mYVM.js → Overflow-CeMxuUZy.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWVck8WN.js → P2P-B5aIRWwJ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DgFqekod.js → PdhVaultBrowser-6rYgejd4.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BtJBVOHV.js → Permissions-CqCp2SIl.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-6VBObXzd.js → PersonalDataHub-BsA7DJWW.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-D222FmqY.js → Pipeline-CiW6HeZh.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bi9FMikp.js → Privacy-DckUOLYq.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bo52H47H.js → ProjectInit-CZppOOYR.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BPkesfOc.js → ProjectSettings-B9QPzhDU.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-GynohSFX.js → Projects-BErjjGha.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DVdMg04n.js → Providers-DehU6Qiz.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DqJCb595.js → QrScannerModal-E1SUvv1m.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-J7loQbXi.js → QuickAsk-COWFxyH3.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BI5aURVc.js → Recommend-D26pWKxX.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BN2sqGvz.js → RemoteSession-DCOIaId3.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BGOND-Fi.js → Reputation-DT_AHGAR.js} +1 -1
- package/src/assets/web-panel/assets/{Row-77dfwaUk.js → Row-B50S-1nl.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-FtBAxS3g.js → RssFeed-BaBnHg3Q.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BaYVLFb7.js → Search-BVdnLuuS.js} +1 -1
- package/src/assets/web-panel/assets/{Security-LE3Vv6ab.js → Security-BnacH74J.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5pP-Whz.js → Services-CxM08Zch.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CLqKUVsF.js → Skeleton-DE7CIc1N.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BPjN0SX5.js → Skills-CGI0SJmf.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-14jD70kg.js → Sla-DpEzPcqc.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Dr9ij42W.js → SpeechSettings-CTmnmMHn.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BzLHP7B8.js → SyncSettings-Dxgrd9hd.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-YqV9b0rV.js → Tasks-CW4slS0A.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CxxAE4PK.js → Templates-DxvGWDgB.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CRb3PcKJ.js → Tenant-_Q0o2tNK.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CTzPpBaP.js → Terminal-BTZn8pow.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DjFUj_hy.js → TimelineRenderer-CauL0KFe.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bbb8tPvx.js → Tokens-CDoM2qeT.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CSeWGM0W.js → Trigger-B-QYGEU7.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-JgESMBo3.js → Trust-BD6XJHT-.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CiObLk0T.js → UkeySign-x4TFwCy0.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CFEZaQ2x.js → VideoEditing-t3imBK_0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DR8ZGDNn.js → Wallet-BCfkWwNC.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DxZukvu7.js → WebAuthn-WH314Mdm.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CKgSZQwn.js → WorkflowEditor-jUlcjrUg.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CTxEQE66.js → chat-Dg3VASTL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CAjKMUu3.js → colors-BNvmBRKE.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BXuz49at.js → compact-item-BGOfoqf4.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CFN_Hwr9.js → createContext-BNQeqKAs.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B7_ypN1G.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BwoSBSfP.js → hasIn-Bg3AjCrq.js} +1 -1
- package/src/assets/web-panel/assets/{index-u9_DM3ZC.js → index--I3UF5t1.js} +1 -1
- package/src/assets/web-panel/assets/{index-IahILygB.js → index-2D04Zltx.js} +3 -3
- package/src/assets/web-panel/assets/{index-Bqv_Cray.js → index-60AnjUTX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSmFby3Q.js → index-7QJUWemf.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTX9CJPx.js → index-B--0QM0S.js} +1 -1
- package/src/assets/web-panel/assets/index-B-jSKJK6.js +1 -0
- package/src/assets/web-panel/assets/{index-C8er4W9u.js → index-B0mgngoB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DViK2bkv.js → index-BBCMulQ-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmkbAADP.js → index-BSNhW95G.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2tEnBPx.js → index-B_JmInC0.js} +1 -1
- package/src/assets/web-panel/assets/{index-_ZtCyUdz.js → index-BaPvEvB4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN53dE_u.js → index-Bkz1tgFR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bj4hIiLW.js → index-BmTacaQV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Tz5dheZa.js → index-CCFZN66A.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv7V2kg6.js → index-COol3xfA.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu2P6u8m.js → index-CY8cRKHR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bw9s2d3c.js → index-Cbp-wp-U.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9yR7zqr.js → index-Co_LnCWD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK4ftQ4d.js → index-Cx2EXRfr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxunxaTw.js → index-D-mSvCQK.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7kp-zRE.js → index-D072oLjp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CB3kVd9c.js → index-D6UqK83L.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF9lWi1o.js → index-DF_FKSVH.js} +1 -1
- package/src/assets/web-panel/assets/{index-IY9bd5az.js → index-DLwEXRrb.js} +1 -1
- package/src/assets/web-panel/assets/{index-F2E5RCwz.js → index-DO0VlNtc.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2o_BBjg.js → index-DS04wRll.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY-gBSm8.js → index-DYn5DnDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0QbLlWn.js → index-D_O2ZjPk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjF5BOZx.js → index-DcCnO0RU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CehdwJ_Q.js → index-Dkp-okWa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmXpdcHI.js → index-OUFoxUgH.js} +1 -1
- package/src/assets/web-panel/assets/index-P4FXZJqI.js +1 -0
- package/src/assets/web-panel/assets/{index-t2Ch_JKn.js → index-Wo0f2iqb.js} +1 -1
- package/src/assets/web-panel/assets/{index-T3MTE6jB.js → index-ZD5Kd8tx.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp5y7lX_.js → index-fOwii3LP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cgk0YEiq.js → index-hG7jXGEW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpdDnZX_.js → index-pVdQieac.js} +1 -1
- package/src/assets/web-panel/assets/{index-o9DpkZKf.js → index-uH2LnAs_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmQITjMU.js → index-xzaUx19r.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BoiGJDoO.js → initDefaultProps-B8PN9AxJ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-5eL4E0pA.js → motion-BHivfw5Q.js} +1 -1
- package/src/assets/web-panel/assets/{move-DjggDi_1.js → move-B0QU5nDd.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Ce8Vo2T3.js → mtc-parser-DRwRM3PE.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D1yOBaO2.js → omit-SHt2rV2p.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-8NLceQe8.js → pickAttrs-CcmDlEb2.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CsIdBRmQ.js → placementArrow-DYatmXDS.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-GM5NE8En.js → responsiveObserve-B7qrsXq5.js} +1 -1
- package/src/assets/web-panel/assets/{slide-44yj3u49.js → slide-BRGhlOWd.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B8tqtWcX.js → statusUtils-CT-7NXsQ.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-NhDPBbyB.js → styleChecker-rZdw_Yyp.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C8Qz1GtN.js → useFlexGapSupport-D8YNIP4P.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-ClUv4kih.js → useFs-B8pt0Gu-.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BwkOVEh6.js → usePersonalDataHub-VMmYM1tt.js} +1 -1
- package/src/assets/web-panel/assets/{vnode--gMF33R0.js → vnode-UNDuoPoq.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DXg3TqOP.js → zoom-dN-u667S.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +39 -0
- package/src/lib/evolution/evolution-artifact-ports.js +26 -0
- package/src/lib/evolution/evolution-eval-cohort-enrollment.js +713 -47
- package/src/lib/evolution/evolution-eval-gate.js +146 -0
- package/src/lib/evolution/evolution-eval-launch-admission.js +168 -90
- package/src/lib/evolution/evolution-eval-ledger-capture.js +50 -0
- package/src/lib/evolution/evolution-eval-readonly-audit.js +106 -0
- package/src/lib/evolution/evolution-ledger-file-backend.js +20 -0
- package/src/lib/evolution/evolution-ledger-ports.js +59 -27
- package/src/lib/evolution/evolution-ledger-v2-journal.js +55 -18
- package/src/lib/evolution/evolution-workbench-file-resources.js +19 -1
- package/src/lib/evolution/rrsi-cohort-registration.js +275 -0
- package/src/lib/evolution/rrsi-contracts.js +742 -0
- package/src/lib/evolution/rrsi-data.js +196 -0
- package/src/lib/evolution/rrsi-evaluation-adapter.js +275 -0
- package/src/lib/evolution/rrsi-evaluation-variants.js +267 -0
- package/src/lib/evolution/rrsi-group-statistics.js +553 -0
- package/src/lib/evolution/rrsi-history-ledger-adapter.js +3261 -0
- package/src/lib/evolution/rrsi-native-batch-evidence.js +520 -0
- package/src/lib/evolution/rrsi-native-eval-row-collector.js +538 -0
- package/src/lib/evolution/rrsi-native-evaluation-batch.js +547 -0
- package/src/lib/evolution/rrsi-native-evaluation-plan.js +431 -0
- package/src/lib/evolution/rrsi-native-group-statistics-plan.js +121 -0
- package/src/lib/evolution/rrsi-native-group-statistics.js +482 -0
- package/src/lib/evolution/rrsi-native-quality-receipt-contracts.js +321 -0
- package/src/lib/evolution/rrsi-native-quality-receipt.js +256 -0
- package/src/lib/evolution/rrsi-native-statistics-protocol.js +330 -0
- package/src/lib/evolution/rrsi-parent-binding.js +290 -0
- package/src/lib/evolution/rrsi-pm-execution-bridge.js +500 -0
- package/src/lib/evolution/rrsi-pm-training-mapping.js +134 -0
- package/src/lib/evolution/rrsi-preparation-contracts.js +213 -0
- package/src/lib/evolution/rrsi-registry-history-binding.js +193 -0
- package/src/lib/evolution/rrsi-registry-store-policy.js +1191 -0
- package/src/lib/evolution/rrsi-runtime-composition.js +79 -0
- package/src/lib/evolution/rrsi-selector.js +434 -0
- package/src/lib/evolution/rrsi-statistics-simulation.js +354 -0
- package/src/lib/evolution/skill-candidate-registry.js +216 -29
- package/src/lib/evolution/skill-registry-maintenance.js +80 -0
- package/src/lib/evolution/skill-registry-writer-control.js +138 -0
- package/src/lib/evolution/skill-release-registry.js +399 -169
- package/src/lib/formal-quality-eval-runtime.js +2 -14
- package/src/lib/goal-store.js +225 -16
- package/src/lib/record-replay/skill-recorder.js +38 -3
- package/src/lib/scheduler-kernel/authority-resolver.js +12 -163
- package/src/lib/scheduler-kernel/contract.js +27 -414
- package/src/lib/scheduler-kernel/runtime.js +21 -823
- package/src/lib/scheduler-kernel/service.js +11 -328
- package/src/lib/scheduler-kernel/source-locator-path.js +7 -142
- package/src/lib/scheduler-kernel/store.js +67 -5931
- package/src/lib/secure-fs.js +16 -1314
- package/src/lib/with-file-lock.js +122 -20
- package/src/assets/web-panel/assets/ChatBubbleRenderer-fcc_Tvqu.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BFiVKf5t.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +0 -1
- package/src/assets/web-panel/assets/index-CCsRfd0k.js +0 -1
- package/src/assets/web-panel/assets/index-CsmiZIQ4.js +0 -1
|
@@ -6563,6 +6563,125 @@ export class EvolutionEvalReceiptVerifier {
|
|
|
6563
6563
|
}
|
|
6564
6564
|
return receiptSnapshot;
|
|
6565
6565
|
}
|
|
6566
|
+
|
|
6567
|
+
#captureReceiptValidityWindows(input) {
|
|
6568
|
+
if (
|
|
6569
|
+
!input ||
|
|
6570
|
+
isProxy(input) ||
|
|
6571
|
+
!Array.isArray(input) ||
|
|
6572
|
+
Object.getPrototypeOf(input) !== Array.prototype ||
|
|
6573
|
+
input.length > 64 ||
|
|
6574
|
+
Reflect.ownKeys(input).length !== input.length + 1
|
|
6575
|
+
) {
|
|
6576
|
+
throw evalError(
|
|
6577
|
+
EVOLUTION_EVAL_INVALID_CODE,
|
|
6578
|
+
"receipt freshness set must contain at most 64 dense own receipts",
|
|
6579
|
+
);
|
|
6580
|
+
}
|
|
6581
|
+
const windows = Array.from({ length: input.length }, (_, index) => {
|
|
6582
|
+
const field = Object.getOwnPropertyDescriptor(input, String(index));
|
|
6583
|
+
const receipt = field?.value;
|
|
6584
|
+
if (
|
|
6585
|
+
!field?.enumerable ||
|
|
6586
|
+
!("value" in field) ||
|
|
6587
|
+
!receipt ||
|
|
6588
|
+
typeof receipt !== "object" ||
|
|
6589
|
+
isProxy(receipt) ||
|
|
6590
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(receipt))
|
|
6591
|
+
) {
|
|
6592
|
+
throw evalError(
|
|
6593
|
+
EVOLUTION_EVAL_INVALID_CODE,
|
|
6594
|
+
"receipt validity windows require own data records",
|
|
6595
|
+
);
|
|
6596
|
+
}
|
|
6597
|
+
const captured = {};
|
|
6598
|
+
for (const key of ["issuedAt", "expiresAt"]) {
|
|
6599
|
+
const timestamp = Object.getOwnPropertyDescriptor(receipt, key);
|
|
6600
|
+
if (
|
|
6601
|
+
!timestamp?.enumerable ||
|
|
6602
|
+
!("value" in timestamp) ||
|
|
6603
|
+
typeof timestamp.value !== "string"
|
|
6604
|
+
)
|
|
6605
|
+
throw evalError(
|
|
6606
|
+
EVOLUTION_EVAL_INVALID_CODE,
|
|
6607
|
+
"receipt validity timestamps require own strings",
|
|
6608
|
+
);
|
|
6609
|
+
captured[key] = normalizeTimestamp(timestamp.value, `receipt.${key}`);
|
|
6610
|
+
}
|
|
6611
|
+
// Only temporal fields are needed. Independent signed documents never
|
|
6612
|
+
// become a larger aggregate canonical document just for a clock check.
|
|
6613
|
+
const { issuedAt, expiresAt } = captured;
|
|
6614
|
+
return {
|
|
6615
|
+
issuedAt,
|
|
6616
|
+
expiresAt,
|
|
6617
|
+
issuedMs: new Date(issuedAt).getTime(),
|
|
6618
|
+
expiresMs: new Date(expiresAt).getTime(),
|
|
6619
|
+
};
|
|
6620
|
+
});
|
|
6621
|
+
return windows;
|
|
6622
|
+
}
|
|
6623
|
+
|
|
6624
|
+
#assertReceiptValidityWindows(windows) {
|
|
6625
|
+
// Read the captured trusted clock once, after all bounded synchronous work.
|
|
6626
|
+
// Repeated asynchronous verification cannot establish a set-wide instant.
|
|
6627
|
+
const checked = readClock(this.#clock);
|
|
6628
|
+
if (
|
|
6629
|
+
windows.some(
|
|
6630
|
+
({ issuedMs, expiresMs }) =>
|
|
6631
|
+
expiresMs <= issuedMs ||
|
|
6632
|
+
expiresMs - issuedMs > this.#maximumReceiptTtlMs ||
|
|
6633
|
+
issuedMs > checked.milliseconds + this.#maximumClockSkewMs ||
|
|
6634
|
+
expiresMs <= checked.milliseconds,
|
|
6635
|
+
)
|
|
6636
|
+
) {
|
|
6637
|
+
throw evalError(
|
|
6638
|
+
EVOLUTION_EVAL_AUTHORITY_FAILED_CODE,
|
|
6639
|
+
"evaluation receipt set is stale or has an invalid validity window",
|
|
6640
|
+
);
|
|
6641
|
+
}
|
|
6642
|
+
return Object.freeze({
|
|
6643
|
+
checkedAt: checked.timestamp,
|
|
6644
|
+
earliestExpiresAt: windows.length
|
|
6645
|
+
? new Date(
|
|
6646
|
+
Math.min(...windows.map((window) => window.expiresMs)),
|
|
6647
|
+
).toISOString()
|
|
6648
|
+
: null,
|
|
6649
|
+
signatureAuthenticated: false,
|
|
6650
|
+
});
|
|
6651
|
+
}
|
|
6652
|
+
|
|
6653
|
+
/** Temporal check only: signature and run-context verification remain separate. */
|
|
6654
|
+
assertReceiptSetFreshness(input) {
|
|
6655
|
+
return this.#assertReceiptValidityWindows(
|
|
6656
|
+
this.#captureReceiptValidityWindows(input),
|
|
6657
|
+
);
|
|
6658
|
+
}
|
|
6659
|
+
|
|
6660
|
+
assertReceiptChunkSetFreshness(input) {
|
|
6661
|
+
if (
|
|
6662
|
+
!input ||
|
|
6663
|
+
isProxy(input) ||
|
|
6664
|
+
!Array.isArray(input) ||
|
|
6665
|
+
Object.getPrototypeOf(input) !== Array.prototype ||
|
|
6666
|
+
input.length > 128 ||
|
|
6667
|
+
Reflect.ownKeys(input).length !== input.length + 1
|
|
6668
|
+
)
|
|
6669
|
+
throw evalError(
|
|
6670
|
+
EVOLUTION_EVAL_INVALID_CODE,
|
|
6671
|
+
"receipt validity chunks require at most 128 dense own lists",
|
|
6672
|
+
);
|
|
6673
|
+
const windows = [];
|
|
6674
|
+
for (let index = 0; index < input.length; index++) {
|
|
6675
|
+
const field = Object.getOwnPropertyDescriptor(input, String(index));
|
|
6676
|
+
if (!field?.enumerable || !("value" in field))
|
|
6677
|
+
throw evalError(
|
|
6678
|
+
EVOLUTION_EVAL_INVALID_CODE,
|
|
6679
|
+
"receipt validity chunks cannot use accessors or holes",
|
|
6680
|
+
);
|
|
6681
|
+
windows.push(...this.#captureReceiptValidityWindows(field.value));
|
|
6682
|
+
}
|
|
6683
|
+
return this.#assertReceiptValidityWindows(windows);
|
|
6684
|
+
}
|
|
6566
6685
|
}
|
|
6567
6686
|
|
|
6568
6687
|
// The exported classes are composition roots. Freezing their prototypes keeps
|
|
@@ -6636,6 +6755,33 @@ export async function verifyEvolutionEvalReceipt(verifier, value, expected) {
|
|
|
6636
6755
|
);
|
|
6637
6756
|
}
|
|
6638
6757
|
|
|
6758
|
+
/** Use the genuine verifier's captured clock without exposing a callable clock port. */
|
|
6759
|
+
export function assertEvolutionEvalReceiptSetFreshness(verifier, receipts) {
|
|
6760
|
+
if (!RECEIPT_VERIFIER_INSTANCES.has(verifier)) {
|
|
6761
|
+
throw evalError(
|
|
6762
|
+
EVOLUTION_EVAL_INVALID_CODE,
|
|
6763
|
+
"receipt set freshness requires a trusted read-only verifier instance",
|
|
6764
|
+
);
|
|
6765
|
+
}
|
|
6766
|
+
return EvolutionEvalReceiptVerifier.prototype.assertReceiptSetFreshness.call(
|
|
6767
|
+
verifier,
|
|
6768
|
+
receipts,
|
|
6769
|
+
);
|
|
6770
|
+
}
|
|
6771
|
+
|
|
6772
|
+
/** Independently bounded cohort windows share one final captured-clock reading. */
|
|
6773
|
+
export function assertEvolutionEvalReceiptChunkSetFreshness(verifier, chunks) {
|
|
6774
|
+
if (!RECEIPT_VERIFIER_INSTANCES.has(verifier))
|
|
6775
|
+
throw evalError(
|
|
6776
|
+
EVOLUTION_EVAL_INVALID_CODE,
|
|
6777
|
+
"receipt chunk freshness requires a trusted read-only verifier instance",
|
|
6778
|
+
);
|
|
6779
|
+
return EvolutionEvalReceiptVerifier.prototype.assertReceiptChunkSetFreshness.call(
|
|
6780
|
+
verifier,
|
|
6781
|
+
chunks,
|
|
6782
|
+
);
|
|
6783
|
+
}
|
|
6784
|
+
|
|
6639
6785
|
const RESULT_ROW_KEYS = new Set([
|
|
6640
6786
|
"taskDigest",
|
|
6641
6787
|
"seed",
|
|
@@ -10,8 +10,12 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA,
|
|
12
12
|
EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA,
|
|
13
|
-
EvolutionLedger,
|
|
14
13
|
} from "./evolution-ledger.js";
|
|
14
|
+
import {
|
|
15
|
+
captureEvolutionEvalLedger,
|
|
16
|
+
readEvolutionEvalLedger,
|
|
17
|
+
} from "./evolution-eval-ledger-capture.js";
|
|
18
|
+
import { captureEvolutionEvalReadonlyAudit } from "./evolution-eval-readonly-audit.js";
|
|
15
19
|
|
|
16
20
|
export const EVOLUTION_EVAL_LAUNCH_ADMISSION_SCHEMA =
|
|
17
21
|
"chainlesschain.evolution-eval-launch-admission/v1";
|
|
@@ -112,11 +116,13 @@ function text(value, label) {
|
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
function digest(value, label) {
|
|
115
|
-
if (!DIGEST.test(value
|
|
119
|
+
if (typeof value !== "string" || !DIGEST.test(value))
|
|
120
|
+
fail(`${label} must be a sha256 digest`);
|
|
116
121
|
return value;
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
function timestamp(value, label) {
|
|
125
|
+
if (typeof value !== "string") fail(`${label} is invalid`);
|
|
120
126
|
const parsed = Date.parse(value);
|
|
121
127
|
if (
|
|
122
128
|
typeof value !== "string" ||
|
|
@@ -248,16 +254,14 @@ function eventId(state) {
|
|
|
248
254
|
}
|
|
249
255
|
|
|
250
256
|
function events(state) {
|
|
251
|
-
return
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
(
|
|
255
|
-
|
|
256
|
-
event.eventId === eventId(state),
|
|
257
|
-
);
|
|
257
|
+
return readEvolutionEvalLedger(state.ledgerMethods).filter(
|
|
258
|
+
(event) =>
|
|
259
|
+
event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
|
|
260
|
+
event.eventId === eventId(state),
|
|
261
|
+
);
|
|
258
262
|
}
|
|
259
263
|
|
|
260
|
-
function resolveEvent(state, event) {
|
|
264
|
+
function resolveEvent(state, event, capturedIdentity = null) {
|
|
261
265
|
if (
|
|
262
266
|
event.type !== EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE ||
|
|
263
267
|
event.tenantId !== state.descriptor.tenantId ||
|
|
@@ -270,7 +274,7 @@ function resolveEvent(state, event) {
|
|
|
270
274
|
canonical(state.enrollment ? [state.enrollment.enrollmentRef] : [])
|
|
271
275
|
)
|
|
272
276
|
fail("admission ledger event is substituted");
|
|
273
|
-
const identity =
|
|
277
|
+
const identity = capturedIdentity ?? state.ledgerMethods.verify();
|
|
274
278
|
const resolution = state.resolveArtifact({
|
|
275
279
|
epoch: identity.epoch,
|
|
276
280
|
ledgerId: identity.ledgerId,
|
|
@@ -332,13 +336,20 @@ export function createEvolutionEvalLaunchAdmissionAuthority({
|
|
|
332
336
|
if (
|
|
333
337
|
!(artifactPorts instanceof EvolutionArtifactPorts) ||
|
|
334
338
|
isProxy(artifactPorts) ||
|
|
335
|
-
!(ledger instanceof EvolutionLedger) ||
|
|
336
339
|
isProxy(ledger) ||
|
|
337
340
|
!isEvolutionLedgerArtifactResolver(ledgerArtifactResolver)
|
|
338
341
|
)
|
|
339
342
|
fail(
|
|
340
343
|
"admission requires real artifact ports, Ledger and a branded resolver",
|
|
341
344
|
);
|
|
345
|
+
let ledgerMethods;
|
|
346
|
+
try {
|
|
347
|
+
ledgerMethods = captureEvolutionEvalLedger(ledger);
|
|
348
|
+
} catch {
|
|
349
|
+
fail(
|
|
350
|
+
"admission requires real artifact ports, Ledger and a branded resolver",
|
|
351
|
+
);
|
|
352
|
+
}
|
|
342
353
|
if (typeof now !== "function" || isProxy(now) || !signer || isProxy(signer))
|
|
343
354
|
fail("admission signer and clock are required");
|
|
344
355
|
const sign = Object.getOwnPropertyDescriptor(signer, "sign")?.value;
|
|
@@ -357,6 +368,7 @@ export function createEvolutionEvalLaunchAdmissionAuthority({
|
|
|
357
368
|
sign: sign.bind(signer),
|
|
358
369
|
artifactPorts,
|
|
359
370
|
ledger,
|
|
371
|
+
ledgerMethods,
|
|
360
372
|
resolveArtifact: ledgerArtifactResolver,
|
|
361
373
|
now,
|
|
362
374
|
enrollment:
|
|
@@ -389,6 +401,12 @@ export function captureEvolutionEvalLaunchAdmissionBinding(authority) {
|
|
|
389
401
|
enrollmentDigest: state.enrollment?.enrollmentDigest ?? null,
|
|
390
402
|
cohortCompletenessAuthenticated: false,
|
|
391
403
|
promotionAuthority: false,
|
|
404
|
+
...(state.enrollment?.registrationKind
|
|
405
|
+
? {
|
|
406
|
+
registrationKind: state.enrollment.registrationKind,
|
|
407
|
+
historyBinding: state.enrollment.historyBinding,
|
|
408
|
+
}
|
|
409
|
+
: {}),
|
|
392
410
|
});
|
|
393
411
|
}
|
|
394
412
|
|
|
@@ -402,85 +420,102 @@ function authorityState(authority) {
|
|
|
402
420
|
export async function admitEvolutionEvalLaunch(authority, input) {
|
|
403
421
|
const state = authorityState(authority);
|
|
404
422
|
const captured = request(input, state, true);
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
423
|
+
let nativePrepared = false;
|
|
424
|
+
try {
|
|
425
|
+
// A native claim appends its paired budget intent before the admission CAS
|
|
426
|
+
// snapshot. Both subsequent assertOpen calls are strictly read-only.
|
|
427
|
+
if (state.enrollment?.prepare) {
|
|
428
|
+
state.enrollment.prepare(captured);
|
|
429
|
+
nativePrepared = true;
|
|
430
|
+
}
|
|
431
|
+
// Capture head BEFORE the occupancy read: a concurrent append cannot escape CAS.
|
|
432
|
+
const head = state.ledgerMethods.verify();
|
|
433
|
+
if (state.enrollment) state.enrollment.assertOpen(captured);
|
|
434
|
+
if (events(state).length !== 0) fail("admission slot is already occupied");
|
|
435
|
+
const core = {
|
|
436
|
+
schema: state.enrollment
|
|
437
|
+
? EVOLUTION_EVAL_ENROLLED_LAUNCH_ADMISSION_SCHEMA
|
|
438
|
+
: EVOLUTION_EVAL_LAUNCH_ADMISSION_SCHEMA,
|
|
439
|
+
descriptorDigest: state.descriptorDigest,
|
|
440
|
+
...captured,
|
|
441
|
+
...(state.enrollment
|
|
442
|
+
? {
|
|
443
|
+
enrollmentDigest: state.enrollment.enrollmentDigest,
|
|
444
|
+
descriptor: state.descriptor,
|
|
445
|
+
}
|
|
446
|
+
: {}),
|
|
447
|
+
};
|
|
448
|
+
const signature = state.sign(
|
|
449
|
+
Object.freeze({ message: message(core).toString("utf8") }),
|
|
450
|
+
);
|
|
451
|
+
const evidence = verifyEvidence(
|
|
452
|
+
{
|
|
453
|
+
...core,
|
|
454
|
+
attestation: {
|
|
455
|
+
algorithm: "ed25519",
|
|
456
|
+
issuer: state.descriptor.authorityId,
|
|
457
|
+
keyId: state.descriptor.keyId,
|
|
458
|
+
trustPolicyDigest: state.descriptor.trustPolicyDigest,
|
|
459
|
+
value: signature,
|
|
460
|
+
},
|
|
434
461
|
},
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
fail("admission
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
462
|
+
state,
|
|
463
|
+
);
|
|
464
|
+
request(captured, state, true);
|
|
465
|
+
const published = EvolutionArtifactPorts.prototype.putCanonical.call(
|
|
466
|
+
state.artifactPorts,
|
|
467
|
+
ARTIFACT_TYPE,
|
|
468
|
+
evidence,
|
|
469
|
+
{
|
|
470
|
+
audience: state.descriptor.audience,
|
|
471
|
+
purpose: state.descriptor.purpose,
|
|
472
|
+
retention: "ledger",
|
|
473
|
+
},
|
|
474
|
+
);
|
|
475
|
+
if (
|
|
476
|
+
published?.receipt?.persisted !== true ||
|
|
477
|
+
published.receipt.readbackVerified !== true ||
|
|
478
|
+
published.receipt.integrityVerified !== true ||
|
|
479
|
+
published.receipt.retention !== "ledger"
|
|
480
|
+
)
|
|
481
|
+
fail("admission artifact persistence failed");
|
|
482
|
+
request(captured, state, true);
|
|
483
|
+
if (state.enrollment) state.enrollment.assertOpen(captured);
|
|
484
|
+
const receipt = state.ledgerMethods.appendDomainEvent(
|
|
485
|
+
{
|
|
486
|
+
type: EVOLUTION_EVAL_LAUNCH_ADMISSION_EVENT_TYPE,
|
|
487
|
+
eventId: eventId(state),
|
|
488
|
+
tenantId: state.descriptor.tenantId,
|
|
489
|
+
artifactTenantId: state.descriptor.artifactTenantId,
|
|
490
|
+
correlationId: state.descriptor.streamId,
|
|
491
|
+
decision: "accepted",
|
|
492
|
+
skillName: "evolution-eval",
|
|
493
|
+
reason: "signed attempt admission; Actor execution is unproven",
|
|
494
|
+
sourceRefs: state.enrollment ? [state.enrollment.enrollmentRef] : [],
|
|
495
|
+
subjectRef: published.ref,
|
|
496
|
+
timestamp: captured.admittedAt,
|
|
497
|
+
},
|
|
498
|
+
{ expectedHeadDigest: head.headDigest, expectedSequence: head.sequence },
|
|
499
|
+
);
|
|
500
|
+
if (receipt?.authenticated !== true || receipt.durable !== true)
|
|
501
|
+
fail("admission ledger append failed");
|
|
502
|
+
const matches = events(state);
|
|
503
|
+
if (matches.length !== 1) fail("admission slot is absent or ambiguous");
|
|
504
|
+
const result = resolveEvent(state, matches[0]);
|
|
505
|
+
if (canonical(result.evidence) !== canonical(evidence))
|
|
506
|
+
fail("admission readback differs from signed bytes");
|
|
507
|
+
request(captured, state, true);
|
|
508
|
+
return result;
|
|
509
|
+
} catch (error) {
|
|
510
|
+
if (nativePrepared && state.enrollment?.recordFailure) {
|
|
511
|
+
try {
|
|
512
|
+
state.enrollment.recordFailure();
|
|
513
|
+
} catch {
|
|
514
|
+
/* Preserve the original failure; durable intent and ceilings remain. */
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
throw error;
|
|
518
|
+
}
|
|
484
519
|
}
|
|
485
520
|
|
|
486
521
|
/** Durable audit/recovery may outlive the execution deadline; it grants no execution permit. */
|
|
@@ -503,3 +538,46 @@ export async function resolveEvolutionEvalLaunch(authority, input) {
|
|
|
503
538
|
fail("admission lookup differs from the recorded attempt");
|
|
504
539
|
return result;
|
|
505
540
|
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Verify an admission within a genuine immutable journal view. The caller must
|
|
544
|
+
* complete the whole audit with assertUnchanged before publishing its result.
|
|
545
|
+
* This does not call admission preparation or grant an execution permit.
|
|
546
|
+
*/
|
|
547
|
+
export async function resolveEvolutionEvalLaunchFromReadonlyAudit(
|
|
548
|
+
authority,
|
|
549
|
+
input,
|
|
550
|
+
audit,
|
|
551
|
+
) {
|
|
552
|
+
const state = authorityState(authority);
|
|
553
|
+
const captured = captureEvolutionEvalReadonlyAudit(audit, state.ledger);
|
|
554
|
+
const expected = record(
|
|
555
|
+
input,
|
|
556
|
+
["runId", "runNonce", "requestDigest"],
|
|
557
|
+
"admission lookup",
|
|
558
|
+
);
|
|
559
|
+
text(expected.runId, "runId");
|
|
560
|
+
text(expected.runNonce, "runNonce");
|
|
561
|
+
digest(expected.requestDigest, "requestDigest");
|
|
562
|
+
const matches = captured
|
|
563
|
+
.eventsById(eventId(state))
|
|
564
|
+
.filter((event) => event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA);
|
|
565
|
+
if (matches.length !== 1) fail("admission slot is absent or ambiguous");
|
|
566
|
+
const result = resolveEvent(state, matches[0], captured.identity);
|
|
567
|
+
if (
|
|
568
|
+
Object.keys(expected).some((key) => result.evidence[key] !== expected[key])
|
|
569
|
+
)
|
|
570
|
+
fail("admission lookup differs from the recorded attempt");
|
|
571
|
+
// An artifact resolver can reenter another audit operation. Respect any
|
|
572
|
+
// invalidation already detected there without another full journal scan.
|
|
573
|
+
captureEvolutionEvalReadonlyAudit(audit, state.ledger);
|
|
574
|
+
return frozen({
|
|
575
|
+
...result,
|
|
576
|
+
schema:
|
|
577
|
+
"chainlesschain.evolution-eval-launch-admission-audit-resolution/v1",
|
|
578
|
+
auditHead: captured.identity,
|
|
579
|
+
historicalSnapshotOnly: true,
|
|
580
|
+
requiresFinalAuditHeadCheck: true,
|
|
581
|
+
readyForExecution: false,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Capture the actual journal; never follow a v2 journal back to its source Ledger. */
|
|
2
|
+
import { isProxy } from "node:util/types";
|
|
3
|
+
import {
|
|
4
|
+
EvolutionLedger,
|
|
5
|
+
EVOLUTION_LEDGER_MAX_EVENTS,
|
|
6
|
+
} from "./evolution-ledger.js";
|
|
7
|
+
import { isEvolutionLedgerV2Journal } from "./evolution-ledger-v2-journal.js";
|
|
8
|
+
|
|
9
|
+
export function captureEvolutionEvalLedger(ledger) {
|
|
10
|
+
if (!ledger || isProxy(ledger))
|
|
11
|
+
throw new TypeError("Eval requires a genuine Ledger journal");
|
|
12
|
+
const methods = {};
|
|
13
|
+
for (const name of ["read", "verify", "appendDomainEvent"]) {
|
|
14
|
+
if (ledger instanceof EvolutionLedger)
|
|
15
|
+
methods[name] = (...args) =>
|
|
16
|
+
Reflect.apply(EvolutionLedger.prototype[name], ledger, args);
|
|
17
|
+
else if (isEvolutionLedgerV2Journal(ledger)) {
|
|
18
|
+
const method = Object.getOwnPropertyDescriptor(ledger, name)?.value;
|
|
19
|
+
if (typeof method !== "function" || isProxy(method))
|
|
20
|
+
throw new TypeError("Eval v2 journal method is missing");
|
|
21
|
+
methods[name] = (...args) => Reflect.apply(method, ledger, args);
|
|
22
|
+
} else throw new TypeError("Eval requires a genuine Ledger journal");
|
|
23
|
+
}
|
|
24
|
+
return Object.freeze(methods);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Complete, contiguous census with bookends; defaults must not truncate at 10,000. */
|
|
28
|
+
export function readEvolutionEvalLedger(methods) {
|
|
29
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
30
|
+
const before = methods.verify();
|
|
31
|
+
const events = methods.read({
|
|
32
|
+
afterSequence: 0,
|
|
33
|
+
limit: EVOLUTION_LEDGER_MAX_EVENTS,
|
|
34
|
+
});
|
|
35
|
+
const after = methods.verify();
|
|
36
|
+
if (
|
|
37
|
+
!["ledgerId", "identityDigest", "epoch", "headDigest", "sequence"].every(
|
|
38
|
+
(name) => before[name] === after[name],
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
continue;
|
|
42
|
+
if (
|
|
43
|
+
events.length !== after.sequence ||
|
|
44
|
+
events.some((event, index) => event.sequence !== index + 1)
|
|
45
|
+
)
|
|
46
|
+
throw new Error("Eval requires complete contiguous Ledger coverage");
|
|
47
|
+
return events;
|
|
48
|
+
}
|
|
49
|
+
throw new Error("Ledger changed during Eval census; retry audit");
|
|
50
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** One immutable journal view; authentication finishes at its final head check. */
|
|
2
|
+
import {
|
|
3
|
+
captureEvolutionEvalLedger,
|
|
4
|
+
readEvolutionEvalLedger,
|
|
5
|
+
} from "./evolution-eval-ledger-capture.js";
|
|
6
|
+
|
|
7
|
+
const AUDITS = new WeakMap();
|
|
8
|
+
const HEAD_FIELDS = [
|
|
9
|
+
"ledgerId",
|
|
10
|
+
"identityDigest",
|
|
11
|
+
"epoch",
|
|
12
|
+
"sequence",
|
|
13
|
+
"headDigest",
|
|
14
|
+
];
|
|
15
|
+
const EMPTY_EVENTS = Object.freeze([]);
|
|
16
|
+
|
|
17
|
+
function fail(message) {
|
|
18
|
+
const error = new Error(message);
|
|
19
|
+
error.code = "CC_EVOLUTION_EVAL_READONLY_AUDIT_FAILED";
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readHead(methods) {
|
|
24
|
+
const current = methods.verify();
|
|
25
|
+
return Object.freeze(
|
|
26
|
+
Object.fromEntries(HEAD_FIELDS.map((field) => [field, current[field]])),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function sameHead(left, right) {
|
|
31
|
+
return HEAD_FIELDS.every((field) => left[field] === right[field]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Events come only from the genuine journal's verified read. Preserve native
|
|
35
|
+
// null-prototype references and freeze each event independently; the complete
|
|
36
|
+
// journal must not become one RRSI-sized canonical document.
|
|
37
|
+
function freezeEvent(value) {
|
|
38
|
+
if (value && typeof value === "object") {
|
|
39
|
+
Object.values(value).forEach(freezeEvent);
|
|
40
|
+
Object.freeze(value);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function createEvolutionEvalReadonlyAudit(ledger) {
|
|
46
|
+
const methods = captureEvolutionEvalLedger(ledger);
|
|
47
|
+
const identity = readHead(methods);
|
|
48
|
+
const events = Object.freeze(
|
|
49
|
+
readEvolutionEvalLedger(methods).map(freezeEvent),
|
|
50
|
+
);
|
|
51
|
+
const byEventId = new Map();
|
|
52
|
+
for (const event of events) {
|
|
53
|
+
if (typeof event.eventId !== "string") continue;
|
|
54
|
+
let matches = byEventId.get(event.eventId);
|
|
55
|
+
if (!matches) byEventId.set(event.eventId, (matches = []));
|
|
56
|
+
matches.push(event);
|
|
57
|
+
}
|
|
58
|
+
for (const matches of byEventId.values()) Object.freeze(matches);
|
|
59
|
+
if (!sameHead(identity, readHead(methods)))
|
|
60
|
+
fail("Ledger changed while capturing the read-only audit");
|
|
61
|
+
|
|
62
|
+
let invalidated = false;
|
|
63
|
+
function assertActive() {
|
|
64
|
+
if (invalidated) fail("read-only audit was invalidated by a Ledger change");
|
|
65
|
+
}
|
|
66
|
+
const captured = Object.freeze({
|
|
67
|
+
identity,
|
|
68
|
+
events,
|
|
69
|
+
eventsById(id) {
|
|
70
|
+
assertActive();
|
|
71
|
+
if (typeof id !== "string") fail("audit event ID must be a string");
|
|
72
|
+
return byEventId.get(id) ?? EMPTY_EVENTS;
|
|
73
|
+
},
|
|
74
|
+
assertUnchanged() {
|
|
75
|
+
assertActive();
|
|
76
|
+
let current;
|
|
77
|
+
try {
|
|
78
|
+
current = readHead(methods);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
invalidated = true;
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
if (!sameHead(identity, current)) {
|
|
84
|
+
invalidated = true;
|
|
85
|
+
fail(
|
|
86
|
+
"Ledger changed during the read-only audit; retry with a new view",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return identity;
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
const audit = Object.freeze({
|
|
93
|
+
schema: "chainlesschain.evolution-eval-readonly-audit/v1",
|
|
94
|
+
});
|
|
95
|
+
AUDITS.set(audit, { ledger, captured, assertActive });
|
|
96
|
+
return audit;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Capture does not rescan the journal; the consumer must finish with assertUnchanged. */
|
|
100
|
+
export function captureEvolutionEvalReadonlyAudit(audit, ledger) {
|
|
101
|
+
const state = AUDITS.get(audit);
|
|
102
|
+
if (!state || state.ledger !== ledger)
|
|
103
|
+
fail("a genuine read-only audit of the same Ledger journal is required");
|
|
104
|
+
state.assertActive();
|
|
105
|
+
return state.captured;
|
|
106
|
+
}
|
|
@@ -11,6 +11,7 @@ export const EVOLUTION_LEDGER_FILE_BACKEND_SCHEMA =
|
|
|
11
11
|
"chainlesschain.evolution-ledger-file-backend/v1";
|
|
12
12
|
|
|
13
13
|
const BACKENDS = new WeakSet();
|
|
14
|
+
const BACKEND_BINDINGS = new WeakMap();
|
|
14
15
|
|
|
15
16
|
function requiredString(value, label) {
|
|
16
17
|
if (typeof value !== "string" || value.trim() === "") {
|
|
@@ -205,6 +206,15 @@ export function createEvolutionLedgerFileBackend({
|
|
|
205
206
|
witness,
|
|
206
207
|
});
|
|
207
208
|
BACKENDS.add(backend);
|
|
209
|
+
BACKEND_BINDINGS.set(
|
|
210
|
+
backend,
|
|
211
|
+
Object.freeze({
|
|
212
|
+
matchesLedger: Object.freeze((value) => value === ledger),
|
|
213
|
+
matchesArtifactResolver: Object.freeze(
|
|
214
|
+
(value) => value === artifactResolver,
|
|
215
|
+
),
|
|
216
|
+
}),
|
|
217
|
+
);
|
|
208
218
|
return backend;
|
|
209
219
|
}
|
|
210
220
|
|
|
@@ -214,3 +224,13 @@ export function captureEvolutionLedgerFileBackend(value) {
|
|
|
214
224
|
}
|
|
215
225
|
return value;
|
|
216
226
|
}
|
|
227
|
+
|
|
228
|
+
/** Compare the original journal/resolver objects without exposing signing ports. */
|
|
229
|
+
export function captureEvolutionLedgerFileBackendBinding(value) {
|
|
230
|
+
const binding = BACKEND_BINDINGS.get(value);
|
|
231
|
+
if (!binding)
|
|
232
|
+
throw new TypeError(
|
|
233
|
+
"a branded EvolutionLedger file backend binding is required",
|
|
234
|
+
);
|
|
235
|
+
return binding;
|
|
236
|
+
}
|