chainlesschain 0.166.86 → 0.166.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/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-DdQjhXg9.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-aNzXoIJP.js → ActionButton-CuwA3hPA.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-ETQk4ZXt.js → Analytics-DTVXJSAC.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-D5oEbeEC.js → AppLayout-j06JBfEQ.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-ja48FAne.js → Artifacts-BFAK8LEW.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DlN0YnDt.js → Audit-BiGxRpOf.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CzvyNsRg.js → BackgroundAgents-B6uHaPkZ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DXgEC2MQ.js → Backup-BNAesB8q.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D9XqejLx.js → BaseInput-BOuetfCd.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BTwuYUlN.js → Chat-cVzo3m_D.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-0anIC2Wn.js → ChatBubbleRenderer-DZ2Ys-CI.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CLuaQbDt.js → Checkbox-BaCTS-H8.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-KwQUZs8A.js → Codegen-CBE8NiYh.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BCmROkzc.js → Col-C9wLiUTN.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CXlUEHR4.js → Community-jdClBSIp.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dzx-lWI2.js → Compact-BIjauIlM.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CfXW82FF.js → Compliance-CZ-AoaNj.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DIISTRm2.js → Cowork-BbTKtDS4.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-nyJ-KcFE.js → Cron-ImKdtwNi.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dtv1E4cV.js → Crosschain-B54GSHf5.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BCTpektS.js → DID-BQt5WUzs.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-C1Q_m0So.js → Dashboard--gNOffif.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BrQ5_PPL.js → Dropdown-342A5YJw.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DjoNlONP.js → EmailListRenderer-CtIZ3ZHd.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DaGaE6bX.js → EvolutionSettings-CyZPoTio.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-nJDWBECt.js → FamilyGuardDashboard-B1MCkFEu.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DhMUY_wG.js → Federation-DZWoERUy.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CbONJPuc.js → FormItemContext-Onmb0mp3.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CDdX4dX-.js → GenericCardRenderer-u1qhNNc7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DXbDVJdR.js → Git-BEowR1C5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DbAfAvs1.js → Governance-BiYd3AAg.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Dy-fGea2.js → Inference-CsC4Vjh5.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DAxRpGUF.js → KnowledgeGraph-BXA7ikPM.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-5L1UCR8X.js → Logs-C9WoplQm.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-u0FPafvT.js → MarkdownRenderer-DecEsXsy.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-DUk_McDG.js → Marketplace-CCoJBfRL.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-B6PNsZ_p.js → McpTools-CzaOWBoA.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-BUUs8j5F.js → Memory-BPwh7u1-.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-pXRsgyuO.js → MobileBridge-Bk47v6z2.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-D7v-2Hwm.js → MobileProjects-D-CY--Sb.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Deaj4faB.js → Mtc-ExVyAGlW.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-wUV0VUH1.js → MtcAudit-Rrw10csE.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-C67IIkts.js → Multisig-8TxxwxZZ.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BCA_CWrW.js → NLProgramming-CNckjtnY.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D9eu14hQ.js → Notes-C4j6cZTu.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Cnd-J4LM.js → NotificationSettings-CchU8rWd.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C4pHUuyZ.js → OrderTableRenderer-ZJBoyJ16.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-4YExAbnp.js → Organization-F0Je7EdZ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BF-wFuZz.js → Overflow-B2k-JA3u.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CdiajqCT.js → P2P-yui9Xxe6.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BkjfS6Th.js → PdhVaultBrowser-CegM7hT6.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DrZ4D78_.js → Permissions-CSFL0uvh.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-lDc6OXjz.js → PersonalDataHub-BrMcd-vr.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DqDS9ON1.js → Pipeline-fzrliaVP.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BMekZRZu.js → Privacy-BrkUjJ_g.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-LYS7NFvJ.js → ProjectInit-CF_QCsW9.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CcJNHk9A.js → ProjectSettings-Duwrd8aC.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DrfAHgdF.js → Projects-B0dLVXzU.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-aqsly9SR.js → Providers-Db8iS1xQ.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-ZWvR3zqg.js → QrScannerModal-CHbNzEQs.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BT5CgsvW.js → QuickAsk-CIESMfeR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Cz8Dz2RN.js → Recommend-BTMbCMtR.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BlxPVbtQ.js → RemoteSession-DavyK6J-.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-B3VGBE-1.js → Reputation-BFKtMelA.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Bwv7vSEA.js → Row-BI9AZUvw.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DHI085r_.js → RssFeed-1nwXt8NY.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DBler5T0.js → Search-Ck8PDYbk.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BZdw43NW.js → Security-BgDqpCbq.js} +3 -3
- package/src/assets/web-panel/assets/{Services-Cslk5lUj.js → Services-DF8anXm4.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Bur-C-25.js → Skeleton-CoHyY4ZX.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-v0zgLy0X.js → Skills-dOaD4Ztl.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-B1OWgQ51.js → Sla-XuOawvQY.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CaBcEaV4.js → SpeechSettings-DFJ7nAiu.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CBbG8L6J.js → SyncSettings-B2xYj-Pi.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-C7EjXrnN.js → Tasks-D_SzNTLi.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-VBBOZ1H5.js → Templates-BXFmKh7W.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CtQTj7IF.js → Tenant-CRg2AXbd.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DXVTQjnl.js → Terminal-DQgxnuep.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BRIno0aN.js → TimelineRenderer-BrPQhQVc.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-uiiAfkYN.js → Tokens-RByy4USy.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CPApN8o6.js → Trigger-pE3y8u73.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-T2jKVwCE.js → Trust-DhID9C33.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C2U_gbzP.js → UkeySign-CPxEPNBH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BCdlr3Kj.js → VideoEditing-ZD8DUxeQ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CWnjoSc1.js → Wallet-Br9JREEd.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CqSbYqHq.js → WebAuthn-Cn-YacJg.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Dr_I3jcr.js → WorkflowEditor-BTu0oqMp.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Cg21FKdE.js → chat-CEjws_QF.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CK85tY9e.js → colors-Bv2RNebW.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-m-XYPC7W.js → compact-item-gSc3EofP.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BmiEeNvs.js → createContext-kyFDaqWC.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Dcc8pILJ.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CCw4KAoc.js → hasIn-BuMWcjhx.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByVvAXdl.js → index--nrQmk8X.js} +1 -1
- package/src/assets/web-panel/assets/index-05NB95_V.js +1 -0
- package/src/assets/web-panel/assets/{index-BIOTRzaF.js → index-42PTBO7a.js} +1 -1
- package/src/assets/web-panel/assets/{index-8KzhlvJ9.js → index-BCS5j4SQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-lhoexBDH.js → index-BSSIJ-rv.js} +1 -1
- package/src/assets/web-panel/assets/{index-6jXf-Lln.js → index-BUOCcXou.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7gS_TJl.js → index-Bg5jis0q.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtvVupUL.js → index-C-LPpwe9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGb1j2z9.js → index-C56Drzol.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpIy2HzE.js → index-C7Jo20JB.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf5arJie.js → index-C9U9SjcT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CBcgIWOe.js → index-CF3TjDNz.js} +1 -1
- package/src/assets/web-panel/assets/{index-J81uvUMN.js → index-CMS3Mk93.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGUYgc96.js → index-CNt2X-aK.js} +1 -1
- package/src/assets/web-panel/assets/index-Cb6q8wlI.js +1 -0
- package/src/assets/web-panel/assets/{index-CN2xbLGz.js → index-Cj4RA7oA.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1sU5-XA.js → index-CkfvP2dN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmSgfXuz.js → index-Cm8K8Evn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMbrl43d.js → index-CvSuM_CB.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7xJkhtJ.js → index-Czo_hw97.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvjC3t35.js → index-D3m3EXbL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAlGVix-.js → index-DR561Sqc.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8IC9ZeZ.js → index-DRa4R7vv.js} +1 -1
- package/src/assets/web-panel/assets/{index-yYmjkf38.js → index-DYKSuD02.js} +3 -3
- package/src/assets/web-panel/assets/{index-Br9t_I1X.js → index-DYcPWVN9.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bv90WEWa.js → index-DbVUA5l3.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiVPFsat.js → index-DbkyTMj-.js} +1 -1
- package/src/assets/web-panel/assets/{index-IskAKXhx.js → index-Dej4AGOz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYEzWoyZ.js → index-EpxWlmip.js} +1 -1
- package/src/assets/web-panel/assets/{index-Br0ZNdu1.js → index-GpvWtvw3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIlGxS2W.js → index-NQ0c4hJ1.js} +1 -1
- package/src/assets/web-panel/assets/{index-sWUmvT8H.js → index-OjZUHz5z.js} +1 -1
- package/src/assets/web-panel/assets/{index-OIbfsi-o.js → index-U-ytt84A.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUYyhYP6.js → index-_0bfDTDu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxRhnsEC.js → index-jmMAqBAm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DI9GJFcn.js → index-nLemnBZ2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BStyjmLG.js → index-q65c1kp8.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHsiSoGY.js → index-sJ1F5Txa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcfVHmFK.js → index-xfS_WO9b.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cc1XOmNe.js → initDefaultProps-B-wqiSu7.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BehsX88u.js → motion-BK4_B4MD.js} +1 -1
- package/src/assets/web-panel/assets/{move-BPx2YsqY.js → move-BU2TgDDO.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BSFJgFQA.js → mtc-parser-DA3E4_EX.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DBN5KUeo.js → omit-CaHz1e_q.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BDK1yZ-9.js → pickAttrs-NXZ19amf.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-C4rMmKNJ.js → placementArrow-BCXI9AHO.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BoeoOnxX.js → responsiveObserve-DdlZ9tLk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BKlr1bl9.js → slide-DCZm_Vc4.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Ky1apWPI.js → statusUtils-CuEULKQr.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DxxR7uXk.js → styleChecker-Bo_UXG8x.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DmsUqVe9.js → useFlexGapSupport-B9PaTcFH.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CwkG7sOg.js → useFs-DwSTGdVR.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CddgeEfF.js → usePersonalDataHub-FswSxnDC.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C_-H8i4Y.js → vnode-EUztvYTj.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-aAsHUMNE.js → zoom-D41MAgV-.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 +118 -18
- package/src/commands/memory.js +34 -15
- package/src/commands/sandbox.js +9 -0
- package/src/data/changelog.json +13 -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/tasks.js +8 -3
- package/src/lib/eval/verify01-contracts.js +349 -0
- package/src/lib/eval/verify01-execution.js +605 -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/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
package/src/lib/eval/outcomes.js
CHANGED
|
@@ -132,9 +132,14 @@ function summarize(rows) {
|
|
|
132
132
|
/** Read-only measurement. Declarations and local Eval files are not attestations. */
|
|
133
133
|
export function buildOutcomeReport(
|
|
134
134
|
{ plan, history, observations = [], maintenance = null },
|
|
135
|
-
{ now = Date.now(), expectedPlanDigest } = {},
|
|
135
|
+
{ now = Date.now(), expectedPlanDigest, expectedExecutionCommit } = {},
|
|
136
136
|
) {
|
|
137
137
|
const samples = validateOutcomePlan(plan);
|
|
138
|
+
const executionCommit = expectedExecutionCommit ?? plan.commitSha;
|
|
139
|
+
assert(
|
|
140
|
+
/^[a-f0-9]{40}$/u.test(executionCommit),
|
|
141
|
+
"invalid execution source SHA",
|
|
142
|
+
);
|
|
138
143
|
assert(Number.isFinite(now), "invalid report time");
|
|
139
144
|
const planDigest = outcomeDigest(plan);
|
|
140
145
|
assert(
|
|
@@ -182,10 +187,12 @@ export function buildOutcomeReport(
|
|
|
182
187
|
else reasons.push(`missing_or_invalid_${key}`);
|
|
183
188
|
}
|
|
184
189
|
const observedAt = epoch(observation.observedAt);
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
if (
|
|
191
|
+
!(
|
|
192
|
+
observedAt <= Math.min(now, epoch(plan.window.end)) &&
|
|
193
|
+
observedAt - (row.elapsedMs ?? 0) >= epoch(plan.window.start)
|
|
194
|
+
)
|
|
195
|
+
)
|
|
189
196
|
reasons.push("observation_outside_window");
|
|
190
197
|
const run = runs.get(observation.runId);
|
|
191
198
|
const stoppedBeforeTask =
|
|
@@ -210,13 +217,15 @@ export function buildOutcomeReport(
|
|
|
210
217
|
Math.max(1, now - epoch(plan.window.start)),
|
|
211
218
|
).filter((reason) => reason !== "execution_not_successful");
|
|
212
219
|
reasons.push(...integrity);
|
|
213
|
-
if (run.label !==
|
|
220
|
+
if (run.label !== executionCommit) reasons.push("commit_mismatch");
|
|
214
221
|
if (outcomeDigest(run.comparison) !== sample.comparisonDigest)
|
|
215
222
|
reasons.push("comparison_mismatch");
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
223
|
+
if (
|
|
224
|
+
!(
|
|
225
|
+
epoch(run.ranAt) >= epoch(plan.window.start) &&
|
|
226
|
+
epoch(run.ranAt) <= epoch(plan.window.end)
|
|
227
|
+
)
|
|
228
|
+
)
|
|
220
229
|
reasons.push("run_outside_window");
|
|
221
230
|
}
|
|
222
231
|
const result = run?.results?.find((item) => item?.id === sample.taskId);
|
|
@@ -310,6 +319,7 @@ export function buildOutcomeReport(
|
|
|
310
319
|
improvementVerdict: "NOT_EVALUATED",
|
|
311
320
|
planDigest,
|
|
312
321
|
commitSha: plan.commitSha,
|
|
322
|
+
executionCommitSha: executionCommit,
|
|
313
323
|
currency: plan.currency,
|
|
314
324
|
window: plan.window,
|
|
315
325
|
task: summarize(tasks),
|
package/src/lib/eval/runner.js
CHANGED
|
@@ -20,11 +20,13 @@ import fs from "fs";
|
|
|
20
20
|
import os from "os";
|
|
21
21
|
import path from "path";
|
|
22
22
|
import crypto from "crypto";
|
|
23
|
+
import { performance } from "node:perf_hooks";
|
|
23
24
|
|
|
24
25
|
export const _deps = {
|
|
25
26
|
mkdtempSync: fs.mkdtempSync,
|
|
26
27
|
rmSync: fs.rmSync,
|
|
27
28
|
now: () => Date.now(),
|
|
29
|
+
monotonicNow: () => performance.now(),
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -100,6 +102,26 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
100
102
|
const recorder = opts.recorder || null;
|
|
101
103
|
for (const task of tasks) {
|
|
102
104
|
const started = _deps.now();
|
|
105
|
+
const deadline =
|
|
106
|
+
task?.totalTimeoutMs === undefined
|
|
107
|
+
? null
|
|
108
|
+
: _deps.monotonicNow() + task.totalTimeoutMs;
|
|
109
|
+
let phase = "setup";
|
|
110
|
+
const budget = {
|
|
111
|
+
remainingMs(stage = phase) {
|
|
112
|
+
if (deadline === null) return task.timeoutMs;
|
|
113
|
+
const remaining = Math.floor(deadline - _deps.monotonicNow());
|
|
114
|
+
if (remaining <= 0) {
|
|
115
|
+
const error = new Error(
|
|
116
|
+
`task total time budget exhausted during ${stage}`,
|
|
117
|
+
);
|
|
118
|
+
error.code = "EVAL_TOTAL_TIMEOUT";
|
|
119
|
+
error.phase = stage;
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
return remaining;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
103
125
|
let dir = null;
|
|
104
126
|
const rec = {
|
|
105
127
|
id: task?.id || "(unnamed)",
|
|
@@ -132,17 +154,24 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
132
154
|
}
|
|
133
155
|
dir = _deps.mkdtempSync(path.join(base, `cc-eval-${task.id}-`));
|
|
134
156
|
if (typeof task.setup === "function") {
|
|
135
|
-
await task.setup(dir);
|
|
157
|
+
await task.setup(dir, budget);
|
|
136
158
|
}
|
|
137
159
|
// Baseline AFTER setup, BEFORE the agent — so the diff is exactly the
|
|
138
160
|
// agent's edits (not the task's starting files).
|
|
139
|
-
|
|
161
|
+
phase = "baseline";
|
|
162
|
+
const capture = task.snapshotWorkspace || snapshotWorkspace;
|
|
163
|
+
const before = capture(dir, budget, "baseline");
|
|
164
|
+
budget.remainingMs();
|
|
140
165
|
let agentResult;
|
|
166
|
+
phase = "agent";
|
|
141
167
|
try {
|
|
142
168
|
agentResult = await runAgent({
|
|
143
169
|
prompt: task.prompt,
|
|
144
170
|
cwd: dir,
|
|
145
|
-
timeoutMs:
|
|
171
|
+
timeoutMs: budget.remainingMs(),
|
|
172
|
+
...(task.costBudgetUsd === undefined
|
|
173
|
+
? {}
|
|
174
|
+
: { costBudgetUsd: task.costBudgetUsd }),
|
|
146
175
|
});
|
|
147
176
|
} catch (agentErr) {
|
|
148
177
|
// An agent crash is a task failure, not a harness failure — record it
|
|
@@ -159,6 +188,8 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
159
188
|
rec.totalCostUsd = Number.isFinite(agentResult?.totalCostUsd)
|
|
160
189
|
? agentResult.totalCostUsd
|
|
161
190
|
: null;
|
|
191
|
+
task.recordExecution?.(agentResult);
|
|
192
|
+
budget.remainingMs();
|
|
162
193
|
if (agentResult?.evaluationMetrics !== undefined) {
|
|
163
194
|
rec.evaluationMetrics = agentResult.evaluationMetrics;
|
|
164
195
|
}
|
|
@@ -169,7 +200,12 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
169
200
|
// workspace themselves). `unrelatedChanges` = files touched outside the
|
|
170
201
|
// task's declared legitimate surface; null when the task doesn't declare
|
|
171
202
|
// `expectedFiles` (→ excluded from the suite's 无关改动率).
|
|
172
|
-
|
|
203
|
+
phase = "after-snapshot";
|
|
204
|
+
const changed = diffSnapshots(
|
|
205
|
+
before,
|
|
206
|
+
capture(dir, budget, "after-snapshot"),
|
|
207
|
+
);
|
|
208
|
+
budget.remainingMs();
|
|
173
209
|
rec.changedFiles = changed;
|
|
174
210
|
if (Array.isArray(task.expectedFiles)) {
|
|
175
211
|
const expected = new Set(
|
|
@@ -179,7 +215,9 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
179
215
|
} else {
|
|
180
216
|
rec.unrelatedChanges = null; // not measured
|
|
181
217
|
}
|
|
182
|
-
|
|
218
|
+
phase = "check";
|
|
219
|
+
const verdict = await task.check(dir, agentResult, budget);
|
|
220
|
+
budget.remainingMs();
|
|
183
221
|
rec.artifactCheckPassed = verdict?.pass === true;
|
|
184
222
|
// A useful artifact survives a provider/transport failure, but it is not
|
|
185
223
|
// evidence that the Agent completed the task successfully.
|
|
@@ -188,6 +226,12 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
188
226
|
} catch (err) {
|
|
189
227
|
// A harness-level error (bad task def / setup threw) — mark failed.
|
|
190
228
|
rec.error = rec.error || err.message;
|
|
229
|
+
rec.failurePhase = err.phase || phase;
|
|
230
|
+
task.recordFailure?.({
|
|
231
|
+
phase: rec.failurePhase,
|
|
232
|
+
code: err.code || null,
|
|
233
|
+
error: err.message,
|
|
234
|
+
});
|
|
191
235
|
rec.pass = false;
|
|
192
236
|
} finally {
|
|
193
237
|
rec.ms = _deps.now() - started;
|
package/src/lib/eval/tasks.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import fs from "fs";
|
|
13
13
|
import path from "path";
|
|
14
14
|
import executionBroker from "../process-execution-broker/index.js";
|
|
15
|
+
import { loadVerify01Suite, VERIFY01_SUITES } from "./verify01-execution.js";
|
|
15
16
|
|
|
16
17
|
export const _deps = {
|
|
17
18
|
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
@@ -634,8 +635,12 @@ export const BUILTIN_TASKS = [
|
|
|
634
635
|
},
|
|
635
636
|
];
|
|
636
637
|
|
|
637
|
-
/**
|
|
638
|
-
export function getSuite(name = "builtin") {
|
|
638
|
+
/** Frozen project suites require explicit plan/reviewer/checkout bindings. */
|
|
639
|
+
export function getSuite(name = "builtin", options = {}) {
|
|
639
640
|
if (name === "builtin" || !name) return BUILTIN_TASKS;
|
|
640
|
-
|
|
641
|
+
if (VERIFY01_SUITES.includes(name))
|
|
642
|
+
return loadVerify01Suite(options.verify01);
|
|
643
|
+
throw new Error(
|
|
644
|
+
`unknown eval suite: "${name}" (available: builtin, ${VERIFY01_SUITES.join(", ")})`,
|
|
645
|
+
);
|
|
641
646
|
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import {
|
|
3
|
+
createEvalComparison,
|
|
4
|
+
EVAL_EXECUTION_PROTOCOL,
|
|
5
|
+
evalDigest,
|
|
6
|
+
evalHistoryRecordIssues,
|
|
7
|
+
} from "./evidence.js";
|
|
8
|
+
import {
|
|
9
|
+
buildOutcomeReport,
|
|
10
|
+
outcomeDigest,
|
|
11
|
+
validateOutcomePlan,
|
|
12
|
+
} from "./outcomes.js";
|
|
13
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
14
|
+
const MAX_BYTES = 16 * 1024 * 1024;
|
|
15
|
+
function requireValue(condition, message) {
|
|
16
|
+
if (!condition) throw new Error(message);
|
|
17
|
+
}
|
|
18
|
+
function index(rows, key, label) {
|
|
19
|
+
requireValue(Array.isArray(rows), `${label} must be an array`);
|
|
20
|
+
const result = new Map();
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
requireValue(
|
|
23
|
+
typeof row?.[key] === "string" &&
|
|
24
|
+
row[key].length > 0 &&
|
|
25
|
+
!result.has(row[key]),
|
|
26
|
+
`${label}: missing or duplicate ${key}`,
|
|
27
|
+
);
|
|
28
|
+
result.set(row[key], row);
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
function relativeFile(value) {
|
|
33
|
+
requireValue(
|
|
34
|
+
typeof value === "string" &&
|
|
35
|
+
value.length > 0 &&
|
|
36
|
+
!/[\\:*?<>|"\u0000]/u.test(value) &&
|
|
37
|
+
!value.startsWith("/") &&
|
|
38
|
+
value.split("/").every((part) => part && !/[. ]$/u.test(part)),
|
|
39
|
+
"review paths must be exact relative files",
|
|
40
|
+
);
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
function readBytes(file) {
|
|
44
|
+
const descriptor = fs.openSync(file, "r");
|
|
45
|
+
try {
|
|
46
|
+
const before = fs.fstatSync(descriptor, { bigint: true });
|
|
47
|
+
requireValue(
|
|
48
|
+
before.isFile() && before.size <= BigInt(MAX_BYTES),
|
|
49
|
+
"input must be a regular file within 16 MiB",
|
|
50
|
+
);
|
|
51
|
+
const bytes = Buffer.alloc(Number(before.size) + 1);
|
|
52
|
+
let count = 0;
|
|
53
|
+
while (count < bytes.length) {
|
|
54
|
+
const size = fs.readSync(
|
|
55
|
+
descriptor,
|
|
56
|
+
bytes,
|
|
57
|
+
count,
|
|
58
|
+
bytes.length - count,
|
|
59
|
+
null,
|
|
60
|
+
);
|
|
61
|
+
if (!size) break;
|
|
62
|
+
count += size;
|
|
63
|
+
}
|
|
64
|
+
const after = fs.fstatSync(descriptor, { bigint: true });
|
|
65
|
+
requireValue(
|
|
66
|
+
count === Number(before.size) &&
|
|
67
|
+
["dev", "ino", "size", "mtimeNs", "ctimeNs"].every(
|
|
68
|
+
(key) => before[key] === after[key],
|
|
69
|
+
),
|
|
70
|
+
"input changed during read",
|
|
71
|
+
);
|
|
72
|
+
return bytes.subarray(0, count);
|
|
73
|
+
} finally {
|
|
74
|
+
fs.closeSync(descriptor);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const readJson = (file) => JSON.parse(readBytes(file).toString("utf8"));
|
|
78
|
+
|
|
79
|
+
export function validateVerify01Bundle({
|
|
80
|
+
plan,
|
|
81
|
+
catalog,
|
|
82
|
+
bindings,
|
|
83
|
+
expectedPlanDigest,
|
|
84
|
+
}) {
|
|
85
|
+
const samples = validateOutcomePlan(plan);
|
|
86
|
+
requireValue(
|
|
87
|
+
DIGEST.test(expectedPlanDigest || "") &&
|
|
88
|
+
outcomeDigest(plan) === expectedPlanDigest,
|
|
89
|
+
"frozen plan digest mismatch",
|
|
90
|
+
);
|
|
91
|
+
requireValue(
|
|
92
|
+
catalog?.schema === "chainlesschain.verify01-task-catalog/v1" &&
|
|
93
|
+
catalog.projectCommit === plan.commitSha,
|
|
94
|
+
"catalog project SHA mismatch",
|
|
95
|
+
);
|
|
96
|
+
const tasks = index(catalog.tasks, "id", "catalog tasks");
|
|
97
|
+
requireValue(
|
|
98
|
+
tasks.size === 36 && samples.size === 45,
|
|
99
|
+
"VERIFY-01 requires all 36 tasks and 45 samples",
|
|
100
|
+
);
|
|
101
|
+
const taskSamples = [...samples.values()].filter(
|
|
102
|
+
(sample) => sample.kind === "task",
|
|
103
|
+
);
|
|
104
|
+
requireValue(
|
|
105
|
+
taskSamples.length === 36 &&
|
|
106
|
+
new Set(taskSamples.map((sample) => sample.taskId)).size === 36,
|
|
107
|
+
"task population is incomplete or duplicated",
|
|
108
|
+
);
|
|
109
|
+
for (const task of tasks.values()) {
|
|
110
|
+
requireValue(
|
|
111
|
+
task.status === "NOT_RUN" &&
|
|
112
|
+
typeof task.prompt === "string" &&
|
|
113
|
+
task.prompt.length > 0,
|
|
114
|
+
"frozen task definition changed",
|
|
115
|
+
);
|
|
116
|
+
requireValue(
|
|
117
|
+
Array.isArray(task.sourcePaths) &&
|
|
118
|
+
Array.isArray(task.expectedFiles) &&
|
|
119
|
+
task.expectedFiles.length > 0,
|
|
120
|
+
"task paths are required",
|
|
121
|
+
);
|
|
122
|
+
[...task.sourcePaths, ...task.expectedFiles].forEach(relativeFile);
|
|
123
|
+
}
|
|
124
|
+
for (const sample of samples.values()) {
|
|
125
|
+
requireValue(
|
|
126
|
+
tasks.has(sample.taskId),
|
|
127
|
+
"sample task is absent from catalog",
|
|
128
|
+
);
|
|
129
|
+
const comparison = bindings?.comparisons?.[sample.stratum];
|
|
130
|
+
requireValue(
|
|
131
|
+
comparison &&
|
|
132
|
+
outcomeDigest(comparison) === sample.comparisonDigest &&
|
|
133
|
+
comparison.corpusDigest === outcomeDigest(catalog),
|
|
134
|
+
"catalog/comparison digest mismatch",
|
|
135
|
+
);
|
|
136
|
+
const rebuilt = createEvalComparison({
|
|
137
|
+
...comparison,
|
|
138
|
+
context: comparison.declared,
|
|
139
|
+
...comparison.runtime,
|
|
140
|
+
});
|
|
141
|
+
requireValue(
|
|
142
|
+
outcomeDigest(rebuilt) === outcomeDigest(comparison),
|
|
143
|
+
"invalid frozen comparison",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return { tasks, samples };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Review is operator configuration, not proof of independent human review. */
|
|
150
|
+
export function validateVerify01Review(
|
|
151
|
+
bundle,
|
|
152
|
+
{ review, expectedReviewDigest, projectCommit, readReviewedFile },
|
|
153
|
+
) {
|
|
154
|
+
const { tasks, samples } = validateVerify01Bundle(bundle);
|
|
155
|
+
requireValue(
|
|
156
|
+
DIGEST.test(expectedReviewDigest || "") &&
|
|
157
|
+
outcomeDigest(review) === expectedReviewDigest,
|
|
158
|
+
"review digest mismatch",
|
|
159
|
+
);
|
|
160
|
+
requireValue(
|
|
161
|
+
projectCommit === bundle.catalog.projectCommit &&
|
|
162
|
+
review.projectCommit === projectCommit,
|
|
163
|
+
"review/project SHA mismatch",
|
|
164
|
+
);
|
|
165
|
+
requireValue(
|
|
166
|
+
review.planDigest === bundle.expectedPlanDigest &&
|
|
167
|
+
review.catalogDigest === outcomeDigest(bundle.catalog),
|
|
168
|
+
"review frozen identity mismatch",
|
|
169
|
+
);
|
|
170
|
+
const reviewed = index(review.tasks, "taskId", "review tasks");
|
|
171
|
+
requireValue(
|
|
172
|
+
reviewed.size === tasks.size &&
|
|
173
|
+
[...tasks.keys()].every((id) => reviewed.has(id)),
|
|
174
|
+
"review tasks omitted or outside catalog",
|
|
175
|
+
);
|
|
176
|
+
const protectedPaths = new Set();
|
|
177
|
+
for (const [id, entry] of reviewed) {
|
|
178
|
+
const task = tasks.get(id);
|
|
179
|
+
requireValue(
|
|
180
|
+
Array.isArray(entry.allowedChangedPaths) &&
|
|
181
|
+
new Set(entry.allowedChangedPaths).size ===
|
|
182
|
+
entry.allowedChangedPaths.length,
|
|
183
|
+
"review allowed paths missing or duplicated",
|
|
184
|
+
);
|
|
185
|
+
const declared = new Set([...task.expectedFiles, ...task.sourcePaths]);
|
|
186
|
+
requireValue(
|
|
187
|
+
task.expectedFiles.every((file) =>
|
|
188
|
+
entry.allowedChangedPaths.includes(file),
|
|
189
|
+
),
|
|
190
|
+
"review omits expected deliverable",
|
|
191
|
+
);
|
|
192
|
+
for (const file of entry.allowedChangedPaths)
|
|
193
|
+
requireValue(
|
|
194
|
+
declared.has(relativeFile(file)),
|
|
195
|
+
"review expands task change surface",
|
|
196
|
+
);
|
|
197
|
+
for (const kind of ["setup", "check"]) {
|
|
198
|
+
const artifact = entry[kind];
|
|
199
|
+
relativeFile(artifact?.path);
|
|
200
|
+
requireValue(
|
|
201
|
+
DIGEST.test(artifact?.digest || ""),
|
|
202
|
+
`review ${kind} digest required`,
|
|
203
|
+
);
|
|
204
|
+
requireValue(
|
|
205
|
+
typeof readReviewedFile === "function" &&
|
|
206
|
+
evalDigest(readReviewedFile(artifact.path)) === artifact.digest,
|
|
207
|
+
`reviewed ${kind} file changed`,
|
|
208
|
+
);
|
|
209
|
+
protectedPaths.add(artifact.path.toLowerCase());
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (const entry of reviewed.values())
|
|
213
|
+
requireValue(
|
|
214
|
+
entry.allowedChangedPaths.every(
|
|
215
|
+
(file) => !protectedPaths.has(file.toLowerCase()),
|
|
216
|
+
),
|
|
217
|
+
"reviewed evaluator must not be an allowed task edit",
|
|
218
|
+
);
|
|
219
|
+
return { tasks, samples, reviewed };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Validate imported existing Eval records; never mint terminal/provider facts. */
|
|
223
|
+
export function validateVerify01Collection(
|
|
224
|
+
bundle,
|
|
225
|
+
preparation,
|
|
226
|
+
{ sampleIds, history, observations, sourceCommit, now = Date.now() },
|
|
227
|
+
) {
|
|
228
|
+
const { samples, reviewed } = validateVerify01Review(bundle, preparation);
|
|
229
|
+
requireValue(
|
|
230
|
+
/^[a-f0-9]{40}$/u.test(sourceCommit || ""),
|
|
231
|
+
"collection requires an independently supplied tested source SHA",
|
|
232
|
+
);
|
|
233
|
+
requireValue(
|
|
234
|
+
Array.isArray(sampleIds) &&
|
|
235
|
+
sampleIds.length > 0 &&
|
|
236
|
+
new Set(sampleIds).size === sampleIds.length &&
|
|
237
|
+
sampleIds.every((id) => samples.has(id)),
|
|
238
|
+
"selected samples missing, duplicate or outside plan",
|
|
239
|
+
);
|
|
240
|
+
const observed = index(observations, "sampleId", "observations");
|
|
241
|
+
requireValue(
|
|
242
|
+
observed.size === sampleIds.length &&
|
|
243
|
+
sampleIds.every((id) => observed.has(id)),
|
|
244
|
+
"selected observations omitted or unexpected",
|
|
245
|
+
);
|
|
246
|
+
requireValue(
|
|
247
|
+
Array.isArray(history?.issues) && history.issues.length === 0,
|
|
248
|
+
"Eval history contains parse issues",
|
|
249
|
+
);
|
|
250
|
+
const runs = index(history?.runs, "runId", "Eval history");
|
|
251
|
+
const used = new Set();
|
|
252
|
+
const report = buildOutcomeReport(
|
|
253
|
+
{ plan: bundle.plan, history, observations },
|
|
254
|
+
{
|
|
255
|
+
now,
|
|
256
|
+
expectedPlanDigest: bundle.expectedPlanDigest,
|
|
257
|
+
expectedExecutionCommit: sourceCommit,
|
|
258
|
+
},
|
|
259
|
+
);
|
|
260
|
+
for (const id of sampleIds) {
|
|
261
|
+
const sample = samples.get(id);
|
|
262
|
+
const observation = observed.get(id);
|
|
263
|
+
if (
|
|
264
|
+
sample.kind === "first-run" &&
|
|
265
|
+
observation.runId === null &&
|
|
266
|
+
observation.firstRun?.stages?.tool?.passed === false
|
|
267
|
+
) {
|
|
268
|
+
const row = report.rows.find((item) => item.sampleId === id);
|
|
269
|
+
const failureReasons = new Set([
|
|
270
|
+
"task_not_successful",
|
|
271
|
+
"first_run_not_completed",
|
|
272
|
+
"budget_exceeded",
|
|
273
|
+
"manual_repair",
|
|
274
|
+
...(observation.cost === null ? ["missing_or_invalid_cost"] : []),
|
|
275
|
+
]);
|
|
276
|
+
requireValue(
|
|
277
|
+
row.failureCause &&
|
|
278
|
+
row.reasons.every((reason) => failureReasons.has(reason)),
|
|
279
|
+
"invalid first-run early-stop evidence",
|
|
280
|
+
);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
const run = runs.get(observation.runId);
|
|
284
|
+
requireValue(
|
|
285
|
+
run && run.label === sourceCommit,
|
|
286
|
+
"collected run SHA mismatch or missing run",
|
|
287
|
+
);
|
|
288
|
+
requireValue(
|
|
289
|
+
outcomeDigest(run.comparison) === sample.comparisonDigest,
|
|
290
|
+
"collected comparison mismatch",
|
|
291
|
+
);
|
|
292
|
+
const issues = evalHistoryRecordIssues(
|
|
293
|
+
run,
|
|
294
|
+
now,
|
|
295
|
+
Math.max(1, now - Date.parse(bundle.plan.window.start)),
|
|
296
|
+
).filter((issue) => issue !== "execution_not_successful");
|
|
297
|
+
requireValue(
|
|
298
|
+
issues.length === 0,
|
|
299
|
+
`invalid Eval record: ${issues.join(",")}`,
|
|
300
|
+
);
|
|
301
|
+
const result = run.results.find((row) => row.id === sample.taskId);
|
|
302
|
+
requireValue(
|
|
303
|
+
result?.executionEvidence?.terminalVerified === true &&
|
|
304
|
+
result.executionEvidence.protocol === EVAL_EXECUTION_PROTOCOL,
|
|
305
|
+
"collected task has no verified terminal",
|
|
306
|
+
);
|
|
307
|
+
const key = JSON.stringify([run.runId, sample.taskId]);
|
|
308
|
+
requireValue(!used.has(key), "task execution reused across samples");
|
|
309
|
+
used.add(key);
|
|
310
|
+
const cost = result.totalCostUsd;
|
|
311
|
+
requireValue(
|
|
312
|
+
(cost === null || (Number.isFinite(cost) && cost >= 0)) &&
|
|
313
|
+
observation.cost === cost,
|
|
314
|
+
"unknown or mismatched cost must not become zero",
|
|
315
|
+
);
|
|
316
|
+
requireValue(
|
|
317
|
+
Array.isArray(result.changedFiles) &&
|
|
318
|
+
new Set(result.changedFiles).size === result.changedFiles.length,
|
|
319
|
+
"changed-file inventory missing or duplicated",
|
|
320
|
+
);
|
|
321
|
+
const allowed = reviewed.get(sample.taskId).allowedChangedPaths;
|
|
322
|
+
requireValue(
|
|
323
|
+
result.changedFiles.every((file) => allowed.includes(relativeFile(file))),
|
|
324
|
+
"collected task changed an unreviewed path",
|
|
325
|
+
);
|
|
326
|
+
requireValue(
|
|
327
|
+
Array.isArray(result.unrelatedChanges) &&
|
|
328
|
+
result.unrelatedChanges.length === 0,
|
|
329
|
+
"collected task has unreviewed edits",
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
for (const run of runs.values())
|
|
333
|
+
for (const result of run.results)
|
|
334
|
+
requireValue(
|
|
335
|
+
used.has(JSON.stringify([run.runId, result.id])),
|
|
336
|
+
"unbound Eval result outside selected samples",
|
|
337
|
+
);
|
|
338
|
+
return {
|
|
339
|
+
...report,
|
|
340
|
+
executionSource: {
|
|
341
|
+
declaredCommit: sourceCommit,
|
|
342
|
+
declarationOnly: true,
|
|
343
|
+
identityVerified: false,
|
|
344
|
+
},
|
|
345
|
+
projectCommit: preparation.projectCommit,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export { requireValue, relativeFile, readBytes, readJson };
|