chainlesschain 0.166.86 → 0.166.88
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 +26 -15
- package/package.json +1 -1
- 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-DZwiXAIh.js → AIOps-QzeGep9J.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-aNzXoIJP.js → ActionButton-Dfc5bx7S.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-ETQk4ZXt.js → Analytics-tn-_ZG2E.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-D5oEbeEC.js → AppLayout-Deg3WAK8.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-ja48FAne.js → Artifacts-KU05t0a6.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DlN0YnDt.js → Audit-CkSZf54T.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CzvyNsRg.js → BackgroundAgents-i7ivfXF0.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DXgEC2MQ.js → Backup-QcVUKtf0.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D9XqejLx.js → BaseInput-B3h5ZJ0g.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BTwuYUlN.js → Chat-D7AVz0xi.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-0anIC2Wn.js → ChatBubbleRenderer-B0-euPW7.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CLuaQbDt.js → Checkbox-H0p0TMlD.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-KwQUZs8A.js → Codegen-B6HOmAY3.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BCmROkzc.js → Col-n_64Fog2.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CXlUEHR4.js → Community-CX0JGgj0.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dzx-lWI2.js → Compact-C4JWUZlx.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CfXW82FF.js → Compliance-DKyTZakB.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DIISTRm2.js → Cowork-C0joBMci.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-nyJ-KcFE.js → Cron-D6VkYpxK.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dtv1E4cV.js → Crosschain-7b6Uu8jc.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BCTpektS.js → DID-C8YPKqzY.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-C1Q_m0So.js → Dashboard-DJsOiEry.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BrQ5_PPL.js → Dropdown-CyStFY-4.js} +1 -1
- package/src/assets/web-panel/assets/EmailListRenderer-COrIx2Rg.js +1 -0
- package/src/assets/web-panel/assets/{EvolutionSettings-DaGaE6bX.js → EvolutionSettings-DpxORusH.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-nJDWBECt.js → FamilyGuardDashboard-5BYZdMG0.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DhMUY_wG.js → Federation-s1kS0ekU.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CbONJPuc.js → FormItemContext-CmgoH9HV.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CDdX4dX-.js → GenericCardRenderer-DSRWrvcL.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DXbDVJdR.js → Git-Cz3EgnS1.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DbAfAvs1.js → Governance-De4atTe7.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Dy-fGea2.js → Inference-DoitBBxJ.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DAxRpGUF.js → KnowledgeGraph-CIdmJ1pH.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-5L1UCR8X.js → Logs-Coa_qNhU.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-u0FPafvT.js → MarkdownRenderer-CeT_RocE.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-DUk_McDG.js → Marketplace-C6kbAQoM.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-B6PNsZ_p.js → McpTools-C2TZn8D-.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-BUUs8j5F.js → Memory-DYdEKDuB.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-pXRsgyuO.js → MobileBridge-pKLeVviZ.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-D4bWcHA_.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-Deaj4faB.js → Mtc-IEoVRV29.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-wUV0VUH1.js → MtcAudit-Cov-yYTY.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-C67IIkts.js → Multisig--Jr7OCmp.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BCA_CWrW.js → NLProgramming-D2gXnYAA.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D9eu14hQ.js → Notes-hk8pMyve.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Cnd-J4LM.js → NotificationSettings-D26Nc7MU.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C4pHUuyZ.js → OrderTableRenderer-DmzHMEOa.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-4YExAbnp.js → Organization-Cn-o6mHT.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BF-wFuZz.js → Overflow-DP6xpDak.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CdiajqCT.js → P2P-C9WAjG-I.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DxZb0Ux8.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-DrZ4D78_.js → Permissions-BFBN4-IL.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-lDc6OXjz.js → PersonalDataHub-BEDvoAiz.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-DqDS9ON1.js → Pipeline-Co2Ze_rR.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BMekZRZu.js → Privacy-BOTn1EId.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-LYS7NFvJ.js → ProjectInit-CObyrZYm.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CcJNHk9A.js → ProjectSettings-DVTN31rd.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DrfAHgdF.js → Projects-DQSEaVjE.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-aqsly9SR.js → Providers-BRIKWIdQ.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-ZWvR3zqg.js → QrScannerModal-3nxaEXxN.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BT5CgsvW.js → QuickAsk-iwZJEE9z.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Cz8Dz2RN.js → Recommend-D2_EEbvc.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BlxPVbtQ.js → RemoteSession-S4w2mUfq.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-B3VGBE-1.js → Reputation-CstUvfTC.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Bwv7vSEA.js → Row-DEGHFpxz.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DHI085r_.js → RssFeed-DGdZtJQl.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DBler5T0.js → Search-DhfXi99U.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BZdw43NW.js → Security-BbzISrgX.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Cslk5lUj.js → Services-CFjP2sQ3.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Bur-C-25.js → Skeleton-CFn5wbvm.js} +1 -1
- package/src/assets/web-panel/assets/Skills-fVbT8RcW.js +1 -0
- package/src/assets/web-panel/assets/{Sla-B1OWgQ51.js → Sla-D6OtC0MT.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CaBcEaV4.js → SpeechSettings-D0kteBjU.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CBbG8L6J.js → SyncSettings-BGEWCtPh.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-B1xZUG4D.js +1 -0
- package/src/assets/web-panel/assets/{Templates-VBBOZ1H5.js → Templates-COlorjqb.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CtQTj7IF.js → Tenant-yLkwfuo3.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DXVTQjnl.js → Terminal-CAmkq1wf.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BRIno0aN.js → TimelineRenderer-CcKYq1Ue.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-uiiAfkYN.js → Tokens-9hIqn_LE.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CPApN8o6.js → Trigger-Dsdkb74C.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-T2jKVwCE.js → Trust-DC4GuE3C.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C2U_gbzP.js → UkeySign-CSlh00wf.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BCdlr3Kj.js → VideoEditing-QEWLo3QY.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CWnjoSc1.js → Wallet-BkPNQgmg.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CqSbYqHq.js → WebAuthn-7---jCBl.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Dr_I3jcr.js → WorkflowEditor-Dq6Yiu8E.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Cg21FKdE.js → chat-CTYIMpWD.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CK85tY9e.js → colors-C8JtYlDN.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-m-XYPC7W.js → compact-item-spXpnsNC.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BmiEeNvs.js → createContext-D04ewPuL.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-3-s4adfp.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CCw4KAoc.js → hasIn-DZblOKXx.js} +1 -1
- package/src/assets/web-panel/assets/{index-Br9t_I1X.js → index-749P1pkM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvjC3t35.js → index-B-cKXztT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiVPFsat.js → index-B57W1RB6.js} +1 -1
- package/src/assets/web-panel/assets/{index-8KzhlvJ9.js → index-B7RA974g.js} +1 -1
- package/src/assets/web-panel/assets/{index-OIbfsi-o.js → index-BKfR2eSQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGb1j2z9.js → index-BLv-KSGc.js} +1 -1
- package/src/assets/web-panel/assets/{index-yYmjkf38.js → index-BOuUUW2U.js} +3 -3
- package/src/assets/web-panel/assets/{index-J81uvUMN.js → index-BSO33_O2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DI9GJFcn.js → index-B_65aY6c.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHsiSoGY.js → index-BjMY3Y_L.js} +1 -1
- package/src/assets/web-panel/assets/{index-6jXf-Lln.js → index-Bm0z1M6s.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGUYgc96.js → index-Bw-3CtK2.js} +1 -1
- package/src/assets/web-panel/assets/{index-sWUmvT8H.js → index-CE3TYhl0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN2xbLGz.js → index-CHtwoTKX.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7gS_TJl.js → index-CLkua5sJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BStyjmLG.js → index-COvZnoIg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmSgfXuz.js → index-CZmBlh5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-lhoexBDH.js → index-Cfk4o9eI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMbrl43d.js → index-Cgztj1JO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxRhnsEC.js → index-Cz0gkRz_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAlGVix-.js → index-DHOV24VR.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIlGxS2W.js → index-DLUHbPl3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYEzWoyZ.js → index-DSoyEHi2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CBcgIWOe.js → index-D_Md0Jhp.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1sU5-XA.js → index-Dcd-qZ68.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8IC9ZeZ.js → index-DcjouIsi.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByVvAXdl.js → index-DdC0OsNh.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtvVupUL.js → index-DruABY-g.js} +1 -1
- package/src/assets/web-panel/assets/{index-IskAKXhx.js → index-Dssnz_1x.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpIy2HzE.js → index-DtSzmzFF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIOTRzaF.js → index-DwIEfKo7.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7xJkhtJ.js → index-EM4_wLPi.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bv90WEWa.js → index-IFEbaISP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf5arJie.js → index-KIoJ2eCK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUYyhYP6.js → index-Mxj-qi1G.js} +1 -1
- package/src/assets/web-panel/assets/index-ZMf_BGlO.js +1 -0
- package/src/assets/web-panel/assets/index-jvp8bJBF.js +1 -0
- package/src/assets/web-panel/assets/{index-Br0ZNdu1.js → index-rU6_An6N.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcfVHmFK.js → index-rVEqWa0_.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cc1XOmNe.js → initDefaultProps-Dl0wiMxn.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BehsX88u.js → motion-BFmZYrGO.js} +1 -1
- package/src/assets/web-panel/assets/{move-BPx2YsqY.js → move-Cjs64yWq.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BSFJgFQA.js → mtc-parser-NeQsnBuP.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DBN5KUeo.js → omit-4Rs-rfs9.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BDK1yZ-9.js → pickAttrs-CUhx2rDY.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-C4rMmKNJ.js → placementArrow-DbIM_OB2.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BoeoOnxX.js → responsiveObserve-B_TGx9AN.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BKlr1bl9.js → slide-C46cEP5t.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Ky1apWPI.js → statusUtils-DqeksICX.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DxxR7uXk.js → styleChecker-2rrypo5u.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DmsUqVe9.js → useFlexGapSupport-RRe1Edsg.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CwkG7sOg.js → useFs-CB0oxU1U.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CddgeEfF.js → usePersonalDataHub-B98WdlUE.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C_-H8i4Y.js → vnode-CY8AoD95.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-aAsHUMNE.js → zoom-BnT-0MbP.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/eval.js +116 -67
- package/src/commands/memory.js +34 -15
- package/src/commands/sandbox.js +9 -0
- package/src/data/changelog.json +26 -0
- package/src/lib/causal-observability.js +6 -45
- package/src/lib/context-memory-kernel/durable-memory-port.js +49 -10
- package/src/lib/context-memory-kernel/memory-query-index.js +278 -0
- package/src/lib/context-memory-kernel/memory-service.js +17 -2
- package/src/lib/context-memory-kernel/segmented-memory-port.js +277 -9
- package/src/lib/eval/outcomes.js +20 -10
- package/src/lib/eval/runner.js +49 -5
- package/src/lib/eval/stream-terminal.js +51 -0
- package/src/lib/eval/tasks.js +8 -3
- package/src/lib/eval/verify01-contracts.js +349 -0
- package/src/lib/eval/verify01-execution.js +611 -0
- package/src/lib/eval/verify01-host-evidence.js +604 -0
- package/src/lib/execution-support.js +58 -0
- package/src/lib/llm-pricing.js +98 -11
- package/src/lib/model-catalog-review.js +116 -0
- package/src/lib/model-context-catalog.js +23 -1
- package/src/lib/openai-responses.js +39 -0
- package/src/lib/process-execution-broker/index.js +8 -0
- package/src/lib/process-execution-broker/linux-subreaper-process.js +24 -2
- package/src/lib/process-execution-broker/process-ownership-journal.js +168 -7
- package/src/lib/process-execution-broker/process-ownership-quarantine.js +56 -1
- package/src/lib/process-execution-broker/process-recovery-cgroup.js +272 -0
- package/src/runtime/agent-core.js +9 -24
- package/src/runtime/permission-authority-host.js +14 -0
- package/src/assets/web-panel/assets/EmailListRenderer-DjoNlONP.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-D7v-2Hwm.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-BkjfS6Th.js +0 -7
- package/src/assets/web-panel/assets/Skills-v0zgLy0X.js +0 -1
- package/src/assets/web-panel/assets/Tasks-C7EjXrnN.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CkMEODFC.js +0 -1
- package/src/assets/web-panel/assets/index-BjE5qaKn.js +0 -1
- package/src/assets/web-panel/assets/index-CsFH-2Zk.js +0 -1
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import executionBroker from "../process-execution-broker/index.js";
|
|
5
|
+
import { evalDigest, createEvalComparison } from "./evidence.js";
|
|
6
|
+
import { outcomeDigest } from "./outcomes.js";
|
|
7
|
+
import {
|
|
8
|
+
readBytes,
|
|
9
|
+
readJson,
|
|
10
|
+
relativeFile,
|
|
11
|
+
requireValue,
|
|
12
|
+
validateVerify01Review,
|
|
13
|
+
} from "./verify01-contracts.js";
|
|
14
|
+
|
|
15
|
+
export const VERIFY01_SUITES = [
|
|
16
|
+
"verify01-plan-2026-10-04",
|
|
17
|
+
"verify01-project-36",
|
|
18
|
+
];
|
|
19
|
+
const MAX_SNAPSHOT_BYTES = 512 * 1024 * 1024;
|
|
20
|
+
const MAX_DIFF_BYTES = 32 * 1024 * 1024;
|
|
21
|
+
|
|
22
|
+
function git(directory, args, options = {}) {
|
|
23
|
+
return executionBroker.execFileSync("git", ["-C", directory, ...args], {
|
|
24
|
+
encoding: "utf8",
|
|
25
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
26
|
+
timeout: 30000,
|
|
27
|
+
windowsHide: true,
|
|
28
|
+
origin: "eval:verify01-checkout",
|
|
29
|
+
policy: "allow",
|
|
30
|
+
scope: "eval",
|
|
31
|
+
shell: false,
|
|
32
|
+
...options,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function within(root, file) {
|
|
37
|
+
const relative = path.relative(root, file);
|
|
38
|
+
requireValue(
|
|
39
|
+
relative &&
|
|
40
|
+
relative !== ".." &&
|
|
41
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
42
|
+
!path.isAbsolute(relative),
|
|
43
|
+
"path escapes its declared root",
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function regularPath(root, relative) {
|
|
48
|
+
relativeFile(relative);
|
|
49
|
+
const file = path.join(root, relative);
|
|
50
|
+
within(root, file);
|
|
51
|
+
let current = root;
|
|
52
|
+
for (const segment of relative.split("/")) {
|
|
53
|
+
current = path.join(current, segment);
|
|
54
|
+
requireValue(
|
|
55
|
+
!fs.lstatSync(current).isSymbolicLink(),
|
|
56
|
+
"review/project paths must not traverse links",
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
requireValue(
|
|
60
|
+
fs.lstatSync(file).isFile(),
|
|
61
|
+
"review/project artifact must be a regular file",
|
|
62
|
+
);
|
|
63
|
+
return file;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Copy only committed blobs, checking their actual Git object identities.
|
|
67
|
+
* Untracked credentials, .git metadata, and development dependency junctions
|
|
68
|
+
* are never part of the evaluation checkout. Setup owns dependency preparation.
|
|
69
|
+
*/
|
|
70
|
+
async function materializeCheckout(projectRoot, commit, destination, budget) {
|
|
71
|
+
requireValue(
|
|
72
|
+
git(projectRoot, ["rev-parse", "HEAD"]).trim() === commit,
|
|
73
|
+
"actual checkout SHA changed",
|
|
74
|
+
);
|
|
75
|
+
const entries = git(projectRoot, ["ls-tree", "-rz", "--full-tree", commit])
|
|
76
|
+
.split("\0")
|
|
77
|
+
.filter(Boolean)
|
|
78
|
+
.map((entry) => {
|
|
79
|
+
const match = /^(100644|100755) blob ([a-f0-9]{40})\t(.+)$/su.exec(entry);
|
|
80
|
+
requireValue(
|
|
81
|
+
match,
|
|
82
|
+
"evaluation checkout contains unsupported links or submodules",
|
|
83
|
+
);
|
|
84
|
+
relativeFile(match[3]);
|
|
85
|
+
return { mode: match[1], oid: match[2], relative: match[3] };
|
|
86
|
+
});
|
|
87
|
+
let total = 0;
|
|
88
|
+
// Read Git objects, rather than mutable checkout files or platform CRLF
|
|
89
|
+
// conversions. A single bounded batch avoids one Git process per file.
|
|
90
|
+
await new Promise((resolvePromise, reject) => {
|
|
91
|
+
const child = executionBroker.spawn(
|
|
92
|
+
"git",
|
|
93
|
+
["-C", projectRoot, "cat-file", "--batch"],
|
|
94
|
+
{
|
|
95
|
+
windowsHide: true,
|
|
96
|
+
origin: "eval:verify01-checkout-blobs",
|
|
97
|
+
policy: "allow",
|
|
98
|
+
scope: "eval",
|
|
99
|
+
shell: false,
|
|
100
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
let pending = Buffer.alloc(0),
|
|
104
|
+
offset = 0,
|
|
105
|
+
size = null,
|
|
106
|
+
failed = false,
|
|
107
|
+
stderr = "";
|
|
108
|
+
const stop = (error) => {
|
|
109
|
+
if (failed) return;
|
|
110
|
+
failed = true;
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
child.kill();
|
|
113
|
+
reject(error);
|
|
114
|
+
};
|
|
115
|
+
const timer = setTimeout(
|
|
116
|
+
() => stop(new Error("frozen checkout materialization timed out")),
|
|
117
|
+
Math.min(120000, budget.remainingMs("checkout")),
|
|
118
|
+
);
|
|
119
|
+
child.on("error", stop);
|
|
120
|
+
child.stderr.on("data", (bytes) => {
|
|
121
|
+
stderr = (stderr + bytes.toString("utf8")).slice(-4096);
|
|
122
|
+
});
|
|
123
|
+
child.stdout.on("data", (chunk) => {
|
|
124
|
+
if (failed) return;
|
|
125
|
+
try {
|
|
126
|
+
pending = Buffer.concat([pending, chunk]);
|
|
127
|
+
while (offset < entries.length) {
|
|
128
|
+
const entry = entries[offset];
|
|
129
|
+
if (size === null) {
|
|
130
|
+
const newline = pending.indexOf(10);
|
|
131
|
+
if (newline < 0) {
|
|
132
|
+
requireValue(pending.length < 128, "invalid Git batch header");
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
const parts = pending
|
|
136
|
+
.subarray(0, newline)
|
|
137
|
+
.toString("utf8")
|
|
138
|
+
.split(" ");
|
|
139
|
+
requireValue(
|
|
140
|
+
parts.length === 3 &&
|
|
141
|
+
parts[0] === entry.oid &&
|
|
142
|
+
parts[1] === "blob",
|
|
143
|
+
"Git batch object mismatch",
|
|
144
|
+
);
|
|
145
|
+
size = Number(parts[2]);
|
|
146
|
+
requireValue(
|
|
147
|
+
Number.isSafeInteger(size) &&
|
|
148
|
+
size >= 0 &&
|
|
149
|
+
size <= 16 * 1024 * 1024,
|
|
150
|
+
"Git blob exceeds materialization bound",
|
|
151
|
+
);
|
|
152
|
+
pending = pending.subarray(newline + 1);
|
|
153
|
+
}
|
|
154
|
+
if (pending.length < size + 1) break;
|
|
155
|
+
const bytes = pending.subarray(0, size);
|
|
156
|
+
requireValue(pending[size] === 10, "invalid Git batch terminator");
|
|
157
|
+
total += size;
|
|
158
|
+
requireValue(
|
|
159
|
+
total <= MAX_SNAPSHOT_BYTES,
|
|
160
|
+
"evaluation checkout exceeds 512 MiB",
|
|
161
|
+
);
|
|
162
|
+
const actual = createHash("sha1")
|
|
163
|
+
.update(`blob ${size}\0`)
|
|
164
|
+
.update(bytes)
|
|
165
|
+
.digest("hex");
|
|
166
|
+
requireValue(actual === entry.oid, "Git blob digest mismatch");
|
|
167
|
+
const target = path.join(destination, entry.relative);
|
|
168
|
+
within(destination, target);
|
|
169
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
170
|
+
fs.writeFileSync(target, bytes, {
|
|
171
|
+
flag: "wx",
|
|
172
|
+
mode: entry.mode === "100755" ? 0o755 : 0o644,
|
|
173
|
+
});
|
|
174
|
+
pending = pending.subarray(size + 1);
|
|
175
|
+
size = null;
|
|
176
|
+
offset++;
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
stop(error);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
child.on("close", (code, signal) => {
|
|
183
|
+
clearTimeout(timer);
|
|
184
|
+
if (failed) return;
|
|
185
|
+
if (code !== 0 || signal || offset !== entries.length || pending.length)
|
|
186
|
+
reject(new Error(`incomplete frozen Git checkout: ${stderr}`));
|
|
187
|
+
else resolvePromise();
|
|
188
|
+
});
|
|
189
|
+
child.stdin.on("error", stop);
|
|
190
|
+
child.stdin.end(entries.map((entry) => entry.oid).join("\n") + "\n");
|
|
191
|
+
});
|
|
192
|
+
return { commit, files: entries.length, bytes: total };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function snapshot(directory, budget, stage) {
|
|
196
|
+
const files = new Map();
|
|
197
|
+
let total = 0;
|
|
198
|
+
let dependencyBytes = 0;
|
|
199
|
+
let dependencyFiles = 0;
|
|
200
|
+
const dependencyHash = createHash("sha256");
|
|
201
|
+
const buffer = Buffer.alloc(64 * 1024);
|
|
202
|
+
const visit = (current) => {
|
|
203
|
+
for (const entry of fs
|
|
204
|
+
.readdirSync(current, { withFileTypes: true })
|
|
205
|
+
.sort((a, b) => a.name.localeCompare(b.name, "en"))) {
|
|
206
|
+
budget.remainingMs(stage);
|
|
207
|
+
const full = path.join(current, entry.name);
|
|
208
|
+
const relative = path.relative(directory, full).split(path.sep).join("/");
|
|
209
|
+
if (entry.isDirectory()) visit(full);
|
|
210
|
+
else {
|
|
211
|
+
requireValue(
|
|
212
|
+
entry.isFile() || entry.isSymbolicLink(),
|
|
213
|
+
"task snapshot contains an unsupported filesystem object",
|
|
214
|
+
);
|
|
215
|
+
// Preserve link identities without following them into another root.
|
|
216
|
+
const dependency = relative.split("/").includes("node_modules");
|
|
217
|
+
if (dependency && entry.isSymbolicLink()) {
|
|
218
|
+
// A dependency linked outside the isolated workspace cannot be
|
|
219
|
+
// fingerprinted by this capture contract; never silently omit it.
|
|
220
|
+
within(directory, fs.realpathSync(full));
|
|
221
|
+
}
|
|
222
|
+
let bytes = entry.isSymbolicLink()
|
|
223
|
+
? Buffer.from(fs.readlinkSync(full))
|
|
224
|
+
: dependency
|
|
225
|
+
? null
|
|
226
|
+
: readBytes(full);
|
|
227
|
+
let digest, size;
|
|
228
|
+
if (dependency && bytes === null) {
|
|
229
|
+
const hash = createHash("sha256");
|
|
230
|
+
const fd = fs.openSync(full, "r");
|
|
231
|
+
size = 0;
|
|
232
|
+
try {
|
|
233
|
+
let count;
|
|
234
|
+
while (
|
|
235
|
+
(count = fs.readSync(fd, buffer, 0, buffer.length, null)) > 0
|
|
236
|
+
) {
|
|
237
|
+
budget.remainingMs(stage);
|
|
238
|
+
size += count;
|
|
239
|
+
requireValue(
|
|
240
|
+
dependencyBytes + size <= 16 * 1024 ** 3,
|
|
241
|
+
"dependency fingerprint exceeds 16 GiB",
|
|
242
|
+
);
|
|
243
|
+
hash.update(buffer.subarray(0, count));
|
|
244
|
+
}
|
|
245
|
+
} finally {
|
|
246
|
+
fs.closeSync(fd);
|
|
247
|
+
}
|
|
248
|
+
digest = `sha256:${hash.digest("hex")}`;
|
|
249
|
+
} else {
|
|
250
|
+
size = bytes.length;
|
|
251
|
+
digest = evalDigest(bytes);
|
|
252
|
+
}
|
|
253
|
+
if (dependency) {
|
|
254
|
+
dependencyBytes += size;
|
|
255
|
+
dependencyFiles++;
|
|
256
|
+
bytes = null;
|
|
257
|
+
} else total += size;
|
|
258
|
+
requireValue(
|
|
259
|
+
total <= MAX_SNAPSHOT_BYTES &&
|
|
260
|
+
files.size - dependencyFiles < 100000 &&
|
|
261
|
+
dependencyFiles <= 1000000,
|
|
262
|
+
"task snapshot exceeds its capture bound",
|
|
263
|
+
);
|
|
264
|
+
const value = {
|
|
265
|
+
type: entry.isSymbolicLink() ? "link" : "file",
|
|
266
|
+
mode: fs.lstatSync(full).mode & 0o777,
|
|
267
|
+
bytes,
|
|
268
|
+
size,
|
|
269
|
+
digest,
|
|
270
|
+
dependency,
|
|
271
|
+
};
|
|
272
|
+
files.set(relative, value);
|
|
273
|
+
if (dependency)
|
|
274
|
+
dependencyHash.update(
|
|
275
|
+
JSON.stringify([relative, value.type, value.mode, size, digest]) +
|
|
276
|
+
"\n",
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
visit(directory);
|
|
282
|
+
files.dependencyBoundary = {
|
|
283
|
+
contract:
|
|
284
|
+
"all node_modules files and link identities streamed with SHA-256; links never followed; dependency bodies omitted; every change rejected",
|
|
285
|
+
files: dependencyFiles,
|
|
286
|
+
bytes: dependencyBytes,
|
|
287
|
+
digest: `sha256:${dependencyHash.digest("hex")}`,
|
|
288
|
+
};
|
|
289
|
+
return files;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function diff(before, after) {
|
|
293
|
+
const result = [];
|
|
294
|
+
let total = 0;
|
|
295
|
+
for (const file of [...new Set([...before.keys(), ...after.keys()])].sort()) {
|
|
296
|
+
const old = before.get(file),
|
|
297
|
+
next = after.get(file);
|
|
298
|
+
if (
|
|
299
|
+
old?.digest === next?.digest &&
|
|
300
|
+
old?.type === next?.type &&
|
|
301
|
+
old?.mode === next?.mode
|
|
302
|
+
)
|
|
303
|
+
continue;
|
|
304
|
+
total += (old?.bytes?.length || 0) + (next?.bytes?.length || 0);
|
|
305
|
+
requireValue(
|
|
306
|
+
total <= MAX_DIFF_BYTES,
|
|
307
|
+
"task diff exceeds 32 MiB; preserve workspace for independent inspection",
|
|
308
|
+
);
|
|
309
|
+
const describe = (value) =>
|
|
310
|
+
value
|
|
311
|
+
? {
|
|
312
|
+
type: value.type,
|
|
313
|
+
mode: value.mode,
|
|
314
|
+
digest: value.digest,
|
|
315
|
+
bytes: value.size,
|
|
316
|
+
dependency: value.dependency,
|
|
317
|
+
bytesBase64: value.bytes?.toString("base64") ?? null,
|
|
318
|
+
}
|
|
319
|
+
: null;
|
|
320
|
+
result.push({ path: file, before: describe(old), after: describe(next) });
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function reviewedProcess(bytes, directory, reviewRoot, kind, timeout) {
|
|
326
|
+
// Execute the captured bytes, not a path that task code could replace between
|
|
327
|
+
// digest verification and process startup. Evaluators are explicitly trusted
|
|
328
|
+
// operator code; their digest is not an independent-review attestation.
|
|
329
|
+
const result = executionBroker.spawnSync(
|
|
330
|
+
process.execPath,
|
|
331
|
+
[
|
|
332
|
+
"--input-type=module",
|
|
333
|
+
"--eval",
|
|
334
|
+
bytes.toString("utf8"),
|
|
335
|
+
directory,
|
|
336
|
+
String(Date.now() + timeout),
|
|
337
|
+
],
|
|
338
|
+
{
|
|
339
|
+
cwd: reviewRoot,
|
|
340
|
+
encoding: "utf8",
|
|
341
|
+
timeout,
|
|
342
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
343
|
+
windowsHide: true,
|
|
344
|
+
origin: `eval:verify01-${kind}`,
|
|
345
|
+
policy: "allow",
|
|
346
|
+
scope: "eval",
|
|
347
|
+
shell: false,
|
|
348
|
+
},
|
|
349
|
+
);
|
|
350
|
+
return {
|
|
351
|
+
exitCode: result.status ?? null,
|
|
352
|
+
signal: result.signal ?? null,
|
|
353
|
+
stdout: result.stdout || "",
|
|
354
|
+
stderr: result.stderr || "",
|
|
355
|
+
error: result.error?.message || null,
|
|
356
|
+
sourceDigest: evalDigest(bytes),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Prepare a frozen suite. No evaluator or agent runs during admission. */
|
|
361
|
+
export function loadVerify01Suite(options = {}) {
|
|
362
|
+
for (const field of [
|
|
363
|
+
"planDir",
|
|
364
|
+
"planDigest",
|
|
365
|
+
"reviewFile",
|
|
366
|
+
"reviewDigest",
|
|
367
|
+
"reviewRoot",
|
|
368
|
+
"projectRoot",
|
|
369
|
+
"sampleIds",
|
|
370
|
+
])
|
|
371
|
+
requireValue(
|
|
372
|
+
options[field],
|
|
373
|
+
`VERIFY-01 requires ${field}; an independent review binding is not optional`,
|
|
374
|
+
);
|
|
375
|
+
const planDir = path.resolve(options.planDir);
|
|
376
|
+
const bundle = {
|
|
377
|
+
plan: readJson(path.join(planDir, "plan.json")),
|
|
378
|
+
catalog: readJson(path.join(planDir, "tasks.json")),
|
|
379
|
+
bindings: readJson(path.join(planDir, "comparison-bindings.json")),
|
|
380
|
+
expectedPlanDigest: options.planDigest,
|
|
381
|
+
};
|
|
382
|
+
requireValue(
|
|
383
|
+
readBytes(path.join(planDir, "plan.sha256")).toString("utf8").trim() ===
|
|
384
|
+
options.planDigest,
|
|
385
|
+
"pinned plan.sha256 differs from external plan binding",
|
|
386
|
+
);
|
|
387
|
+
const projectRoot = fs.realpathSync(options.projectRoot),
|
|
388
|
+
reviewRoot = fs.realpathSync(options.reviewRoot);
|
|
389
|
+
requireValue(
|
|
390
|
+
projectRoot !== reviewRoot &&
|
|
391
|
+
!reviewRoot.startsWith(`${projectRoot}${path.sep}`),
|
|
392
|
+
"review root must be outside the task project",
|
|
393
|
+
);
|
|
394
|
+
const projectCommit = git(projectRoot, ["rev-parse", "HEAD"]).trim();
|
|
395
|
+
const artifacts = new Map();
|
|
396
|
+
const preparation = {
|
|
397
|
+
review: readJson(options.reviewFile),
|
|
398
|
+
expectedReviewDigest: options.reviewDigest,
|
|
399
|
+
projectCommit,
|
|
400
|
+
readReviewedFile(relative) {
|
|
401
|
+
const bytes = readBytes(regularPath(reviewRoot, relative));
|
|
402
|
+
artifacts.set(relative, bytes);
|
|
403
|
+
return bytes;
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
const validated = validateVerify01Review(bundle, preparation);
|
|
407
|
+
const ids = Array.isArray(options.sampleIds)
|
|
408
|
+
? options.sampleIds
|
|
409
|
+
: String(options.sampleIds).split(",");
|
|
410
|
+
requireValue(
|
|
411
|
+
ids.length > 0 && new Set(ids).size === ids.length,
|
|
412
|
+
"selected sample IDs are missing or duplicated",
|
|
413
|
+
);
|
|
414
|
+
const samples = ids.map((id) => validated.samples.get(id));
|
|
415
|
+
requireValue(samples.every(Boolean), "sample outside frozen population");
|
|
416
|
+
requireValue(
|
|
417
|
+
samples.every((sample) => sample.kind === "task"),
|
|
418
|
+
"first-run samples require actual installation journey collection; task execution cannot replace it",
|
|
419
|
+
);
|
|
420
|
+
requireValue(
|
|
421
|
+
new Set(samples.map((sample) => sample.stratum)).size === 1,
|
|
422
|
+
"one execution must retain one frozen comparison stratum",
|
|
423
|
+
);
|
|
424
|
+
const sampleComparison = bundle.bindings.comparisons[samples[0].stratum];
|
|
425
|
+
const entry = options.entry || "cli";
|
|
426
|
+
requireValue(
|
|
427
|
+
entry === "cli" &&
|
|
428
|
+
samples.every((sample) => sample.stratum.includes("-cli-")),
|
|
429
|
+
"IDE samples require an actual IDE host adapter; CLI cannot impersonate that entry",
|
|
430
|
+
);
|
|
431
|
+
const comparison = createEvalComparison({
|
|
432
|
+
...sampleComparison,
|
|
433
|
+
context: sampleComparison.declared,
|
|
434
|
+
platform: process.platform,
|
|
435
|
+
arch: process.arch,
|
|
436
|
+
node: process.version,
|
|
437
|
+
provider: options.provider,
|
|
438
|
+
model: options.model,
|
|
439
|
+
});
|
|
440
|
+
requireValue(
|
|
441
|
+
outcomeDigest(comparison) === samples[0].comparisonDigest,
|
|
442
|
+
"actual provider/model/runtime differs from frozen comparison",
|
|
443
|
+
);
|
|
444
|
+
const receipts = [];
|
|
445
|
+
const tasks = samples.map((sample) => {
|
|
446
|
+
const task = validated.tasks.get(sample.taskId),
|
|
447
|
+
reviewed = validated.reviewed.get(sample.taskId);
|
|
448
|
+
let baseline, after;
|
|
449
|
+
const receipt = {
|
|
450
|
+
sampleId: sample.id,
|
|
451
|
+
taskId: task.id,
|
|
452
|
+
planDigest: options.planDigest,
|
|
453
|
+
reviewDigest: options.reviewDigest,
|
|
454
|
+
projectCommit,
|
|
455
|
+
comparisonDigest: sample.comparisonDigest,
|
|
456
|
+
entry,
|
|
457
|
+
productionAttested: false,
|
|
458
|
+
dependencyBoundary: null,
|
|
459
|
+
setup: null,
|
|
460
|
+
check: null,
|
|
461
|
+
diff: null,
|
|
462
|
+
execution: null,
|
|
463
|
+
};
|
|
464
|
+
receipts.push(receipt);
|
|
465
|
+
return {
|
|
466
|
+
id: task.id,
|
|
467
|
+
description: task.description,
|
|
468
|
+
prompt: task.prompt,
|
|
469
|
+
timeoutMs: sample.timeBudgetMs,
|
|
470
|
+
totalTimeoutMs: sample.timeBudgetMs,
|
|
471
|
+
costBudgetUsd: sample.costBudget,
|
|
472
|
+
expectedFiles: [...reviewed.allowedChangedPaths],
|
|
473
|
+
async setup(directory, budget) {
|
|
474
|
+
receipt.workspace = directory;
|
|
475
|
+
receipt.checkout = await materializeCheckout(
|
|
476
|
+
projectRoot,
|
|
477
|
+
projectCommit,
|
|
478
|
+
directory,
|
|
479
|
+
budget,
|
|
480
|
+
);
|
|
481
|
+
receipt.setup = reviewedProcess(
|
|
482
|
+
artifacts.get(reviewed.setup.path),
|
|
483
|
+
directory,
|
|
484
|
+
reviewRoot,
|
|
485
|
+
"setup",
|
|
486
|
+
budget.remainingMs("setup"),
|
|
487
|
+
);
|
|
488
|
+
requireValue(
|
|
489
|
+
receipt.setup.exitCode === 0 &&
|
|
490
|
+
!receipt.setup.signal &&
|
|
491
|
+
!receipt.setup.error,
|
|
492
|
+
"reviewed setup failed",
|
|
493
|
+
);
|
|
494
|
+
},
|
|
495
|
+
snapshotWorkspace(directory, budget, stage) {
|
|
496
|
+
const captured = snapshot(directory, budget, stage);
|
|
497
|
+
if (stage === "baseline") baseline = captured;
|
|
498
|
+
else after = captured;
|
|
499
|
+
receipt.dependencyBoundary = {
|
|
500
|
+
before: baseline?.dependencyBoundary || null,
|
|
501
|
+
after: after?.dependencyBoundary || null,
|
|
502
|
+
};
|
|
503
|
+
return new Map(
|
|
504
|
+
[...captured].map(([file, value]) => [
|
|
505
|
+
file,
|
|
506
|
+
JSON.stringify([value.digest, value.type, value.mode]),
|
|
507
|
+
]),
|
|
508
|
+
);
|
|
509
|
+
},
|
|
510
|
+
recordFailure(failure) {
|
|
511
|
+
receipt.failure = failure;
|
|
512
|
+
baseline = after = null;
|
|
513
|
+
},
|
|
514
|
+
recordExecution(agentResult) {
|
|
515
|
+
receipt.execution = {
|
|
516
|
+
output: agentResult?.output ?? null,
|
|
517
|
+
error: agentResult?.error ?? null,
|
|
518
|
+
evidence: agentResult?.executionEvidence ?? null,
|
|
519
|
+
usage: agentResult?.usage ?? null,
|
|
520
|
+
totalCostUsd: agentResult?.totalCostUsd ?? null,
|
|
521
|
+
};
|
|
522
|
+
},
|
|
523
|
+
check(directory, agentResult, budget) {
|
|
524
|
+
receipt.diff = diff(baseline, after);
|
|
525
|
+
baseline = null;
|
|
526
|
+
requireValue(
|
|
527
|
+
receipt.diff.every(
|
|
528
|
+
(change) =>
|
|
529
|
+
reviewed.allowedChangedPaths.includes(change.path) &&
|
|
530
|
+
!change.before?.dependency &&
|
|
531
|
+
!change.after?.dependency &&
|
|
532
|
+
change.after?.type !== "link",
|
|
533
|
+
),
|
|
534
|
+
"task modified a path outside independent review or introduced a deliverable link",
|
|
535
|
+
);
|
|
536
|
+
requireValue(
|
|
537
|
+
task.expectedFiles.every((file) => after.get(file)?.type === "file"),
|
|
538
|
+
"task did not produce all expected regular-file deliverables",
|
|
539
|
+
);
|
|
540
|
+
after = null;
|
|
541
|
+
receipt.check = reviewedProcess(
|
|
542
|
+
artifacts.get(reviewed.check.path),
|
|
543
|
+
directory,
|
|
544
|
+
reviewRoot,
|
|
545
|
+
"check",
|
|
546
|
+
budget.remainingMs("check"),
|
|
547
|
+
);
|
|
548
|
+
requireValue(
|
|
549
|
+
receipt.check.exitCode === 0 &&
|
|
550
|
+
!receipt.check.signal &&
|
|
551
|
+
!receipt.check.error,
|
|
552
|
+
"reviewed acceptance process failed",
|
|
553
|
+
);
|
|
554
|
+
const verdict = JSON.parse(receipt.check.stdout.trim());
|
|
555
|
+
requireValue(
|
|
556
|
+
typeof verdict?.pass === "boolean" &&
|
|
557
|
+
typeof verdict?.detail === "string",
|
|
558
|
+
"reviewed check must emit one JSON pass/detail verdict",
|
|
559
|
+
);
|
|
560
|
+
return verdict;
|
|
561
|
+
},
|
|
562
|
+
};
|
|
563
|
+
});
|
|
564
|
+
Object.defineProperty(tasks, "verification", {
|
|
565
|
+
value: {
|
|
566
|
+
comparison,
|
|
567
|
+
projectCommit,
|
|
568
|
+
planDigest: options.planDigest,
|
|
569
|
+
reviewDigest: options.reviewDigest,
|
|
570
|
+
population: { tasks: 36, firstRuns: 9 },
|
|
571
|
+
selectedSamples: ids,
|
|
572
|
+
receipts,
|
|
573
|
+
productionAttested: false,
|
|
574
|
+
requiredSandboxMode: "workspace-write",
|
|
575
|
+
},
|
|
576
|
+
});
|
|
577
|
+
return tasks;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
export function persistVerify01Receipts(verification, directory, runId) {
|
|
581
|
+
requireValue(
|
|
582
|
+
typeof runId === "string" && /^[a-f0-9-]{36}$/u.test(runId),
|
|
583
|
+
"invalid evaluation run ID",
|
|
584
|
+
);
|
|
585
|
+
const root = path.resolve(directory);
|
|
586
|
+
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
587
|
+
const stat = fs.lstatSync(root);
|
|
588
|
+
requireValue(
|
|
589
|
+
stat.isDirectory() && !stat.isSymbolicLink(),
|
|
590
|
+
"evidence directory must not be a link",
|
|
591
|
+
);
|
|
592
|
+
const { receipts, ...binding } = verification;
|
|
593
|
+
const artifacts = receipts.map((receipt, index) => {
|
|
594
|
+
const bytes = Buffer.from(`${JSON.stringify(receipt, null, 2)}\n`);
|
|
595
|
+
const file = path.join(root, `verify-${runId}-${index}.json`);
|
|
596
|
+
const fd = fs.openSync(file, "wx", 0o600);
|
|
597
|
+
try {
|
|
598
|
+
fs.writeFileSync(fd, bytes);
|
|
599
|
+
fs.fsyncSync(fd);
|
|
600
|
+
} finally {
|
|
601
|
+
fs.closeSync(fd);
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
sampleId: receipt.sampleId,
|
|
605
|
+
path: file,
|
|
606
|
+
digest: evalDigest(bytes),
|
|
607
|
+
bytes: bytes.length,
|
|
608
|
+
};
|
|
609
|
+
});
|
|
610
|
+
return { ...binding, artifacts };
|
|
611
|
+
}
|