chainlesschain 0.166.97 → 0.166.98
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 +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-BB9kKNVw.js → AIOps-DCIQFtF1.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DTg-lWE0.js → ActionButton-BxhHU3nE.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BWUZ0Tpc.js → Analytics-DdM_307O.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Dj8WDnCf.js → AppLayout-C43-kSrh.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-x8NiiPTg.js → Artifacts-B2Vp2Am6.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-q7otRAqO.js → Audit-s-lYUfOp.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-f6qlO2au.js → BackgroundAgents-DTE7Kzio.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BbuX9qQS.js → Backup-9k1q4Mt6.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-amgV-Y0y.js → BaseInput-DlpUtK5R.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CZW3DW7j.js → Chat-CR9S8Rmb.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Xtgfw3-c.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DXHXC52i.js → Checkbox-DpFRu7Df.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DQh47r4e.js → Codegen-BIl72E4Y.js} +1 -1
- package/src/assets/web-panel/assets/{Col-lBOOXCD7.js → Col-91tl_err.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BNFPnBu9.js → Community-CswahO9-.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-7MOWfBGb.js → Compact-D9pfHmaM.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-x0UA-rxk.js → Compliance-CXSZzAO9.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-C_eLfk_Q.js → Cowork-CuT9RWTn.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BP2-_Fja.js → Cron-B71aJWDV.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dn-e1217.js → Crosschain-CcUuWyx8.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D_jverif.js → DID-CtVVGOPL.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BysweBms.js → Dashboard-CV7ZCYQq.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-osJi0Pci.js → Dropdown-DKHxwLgE.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C72k1SKQ.js → EmailListRenderer-Bd03UIvv.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-CAtA1F9s.js → EvolutionSettings-CTrG03B_.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bi0luzvO.js → FamilyGuardDashboard-DXS4bS6Q.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CIwntDLI.js → Federation-BODG2Szj.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DRfwhPW-.js → FormItemContext-D32ccUqD.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-COJTzZ61.js → GenericCardRenderer-ClsyrKvF.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CwsR46lj.js → Git-DcM2yhbL.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B1U-u9BN.js → Governance-BhUzM87n.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-vPsdYTS_.js → Inference-Dq1n0Ifg.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CVDRZM5h.js → KnowledgeGraph-dmmPwEks.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-YRslKbRL.js → Logs-CBSYrPmh.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-CRoDI77y.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CtxYHchd.js → Marketplace-Cfw7XLck.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BkfCbpAk.js → McpTools-CNrZRy4n.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-COp-8Z20.js → Memory-BESjTxdd.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-7fX-n_xn.js → MobileBridge-Boyjo07i.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DUyTVgId.js → MobileProjects-BmxmpTWz.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CLXFZ5dV.js → Mtc-CBkrD0Fq.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-yJ4eP1wB.js → MtcAudit-BA7cAK8h.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-Cwb_qTh0.js → Multisig-m0RGzkKO.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CkuojSSJ.js → NLProgramming-D_TgzifU.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-ju-QtUhJ.js → Notes-Dr-Yr9LL.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DjryXIC3.js → NotificationSettings-DGanpkqO.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-B4KNF8xr.js → OrderTableRenderer-D1FX50QY.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-6-EtcVaO.js → Organization-DRbPg-gs.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-BKja8nqr.js → Overflow-flEO37z6.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BX20f9uL.js → P2P-DqfqFbCW.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-C9zwOEUo.js → PdhVaultBrowser-Cmi5a5dW.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-YQjQVrfE.js → Permissions-DBVRlvBW.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-yZYclXxq.js → PersonalDataHub-gQqjPr9X.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-ChZCCXAI.js → Pipeline-6HlifUc9.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Ds7R-a0H.js → Privacy-bm_2-Zwg.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B3qz_xab.js → ProjectInit-BJW3isuq.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BlwNctdF.js → ProjectSettings-DD3yolz7.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BxtYpNl7.js → Projects-BF3GtWny.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BE_1SS_-.js → Providers-CQA6WAK7.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CMQ25oLb.js → QrScannerModal-DOAwp5Xo.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DQRFLDeP.js → QuickAsk-qeFXsAZT.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-ChVra4Pk.js → Recommend-zDWXwZN8.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-9vPBIowJ.js → RemoteSession-toe6Ip06.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-MdbWbyQQ.js → Reputation-DRDi_Eqp.js} +1 -1
- package/src/assets/web-panel/assets/{Row-JLcBncLR.js → Row-Do2UbYkf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CnMXnpFv.js → RssFeed-B57C6_Sa.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cf5ISVUe.js → Search-DfDyBpe9.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CywFo2EM.js → Security-CulNxeAM.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CLYnSCG3.js → Services-COfAYvs4.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BtbhOlo1.js → Skeleton-0fn0T146.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DPeqcIo2.js → Skills-pPQgAhvJ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BRb4SqDn.js → Sla-CIsRmePR.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-0Wuxts-7.js → SpeechSettings-Bn01d-8b.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BXtsOjXL.js → SyncSettings-Cx_Znk7L.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-D455Wfhx.js → Tasks-DvaskzpG.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-LGc4O0fj.js → Templates-DmHCEiDO.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DA--0GFz.js → Tenant-CqHyvnbW.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DQsA0xCq.js → Terminal-DTt3yqWL.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-VH8AuSLp.js → TimelineRenderer-BhkIxcR3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-B8RyzFRN.js → Tokens-mhjYcBBP.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CA7lVVEf.js → Trigger-CdlMQfwX.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-wUoRRLg9.js → Trust-Bzovg_Gw.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-ByoT_alW.js → UkeySign-ph3EuYi7.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D9fgAxJV.js → VideoEditing-Bo2B4VZE.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CRkTndvj.js → Wallet-BQTKsSUT.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-VwmHOxJK.js → WebAuthn-nJxsXNHV.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Z0bPZc2O.js → WorkflowEditor-CjH8g2N7.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CfX_5qUm.js → chat-CkbNmnQD.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BK7mXUnR.js → colors-BY9JcObR.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Uq755CeO.js → compact-item-Dzzq-d8n.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DWXq8Qnk.js → createContext-DiJxxdTx.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-D502_Z3w.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BXgy5JZA.js → hasIn-DaXPOw3D.js} +1 -1
- package/src/assets/web-panel/assets/{index-_I4nSJFc.js → index-6Z6Z4UwN.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4yvdQCj.js → index-7YVCjSqG.js} +1 -1
- package/src/assets/web-panel/assets/{index-D63nsr0a.js → index-B31oMRmK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdwC1i3O.js → index-B4Sf1AMk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRLOeoFE.js → index-BGvIb1Sr.js} +1 -1
- package/src/assets/web-panel/assets/{index-JX7mXB5a.js → index-BHeHyLRM.js} +3 -3
- package/src/assets/web-panel/assets/{index-Ct41B4y4.js → index-BQvtlYUd.js} +1 -1
- package/src/assets/web-panel/assets/{index-VrR8eMCk.js → index-Bhsxh-rH.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8e4SYX4.js → index-BlWg1bRA.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3VnhfYU.js → index-BqCHe05H.js} +1 -1
- package/src/assets/web-panel/assets/index-BrQ4nI4W.js +1 -0
- package/src/assets/web-panel/assets/{index-DSb7SKp5.js → index-BvgMt6Io.js} +1 -1
- package/src/assets/web-panel/assets/{index-Y77S-ZC0.js → index-BycyBM6g.js} +1 -1
- package/src/assets/web-panel/assets/index-C0_sewGO.js +1 -0
- package/src/assets/web-panel/assets/{index-CGy7b2rd.js → index-C6XSCXeb.js} +1 -1
- package/src/assets/web-panel/assets/{index-XdoslBhl.js → index-CAzfu6k5.js} +1 -1
- package/src/assets/web-panel/assets/{index-B09haI0M.js → index-CVblRqUN.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bt3tjvj-.js → index-CWLpEg34.js} +1 -1
- package/src/assets/web-panel/assets/{index-wYTro42F.js → index-C_OMH_FT.js} +1 -1
- package/src/assets/web-panel/assets/{index-H13lvPme.js → index-CbOOm8I8.js} +1 -1
- package/src/assets/web-panel/assets/{index-TDPkVyse.js → index-CnLO1_yN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuhlVXh4.js → index-CqOkm6kW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfYb8FjC.js → index-DDnqjZa2.js} +1 -1
- package/src/assets/web-panel/assets/{index-VPLA-GO7.js → index-DObXhPhH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CarQiRSA.js → index-DSqQyS9-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ait-_UUh.js → index-DWT9-E5b.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-8lN1rG.js → index-D_Eoh740.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiVH_NiY.js → index-DaylJfw6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbjUfyVq.js → index-DbmHmeP-.js} +1 -1
- package/src/assets/web-panel/assets/{index-LsBPnXHh.js → index-Djeh6rAb.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dg9P9EDV.js → index-Dl8U-0hn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRQSkXde.js → index-EiaWq1TH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZD1My0S.js → index-Igq-72Ep.js} +1 -1
- package/src/assets/web-panel/assets/{index-QXKuGlOS.js → index-Jmlk_lDX.js} +1 -1
- package/src/assets/web-panel/assets/{index-p3BlIre2.js → index-LRZSVBxC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUR7dnMg.js → index-Uh9SjtgW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqJw5WsH.js → index-cu1J4avY.js} +1 -1
- package/src/assets/web-panel/assets/{index-9XsaovMH.js → index-dC2JACyJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxSClhg5.js → index-i9eu2Kir.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DTuF67Yy.js → initDefaultProps-B0WuG3fa.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DZasLgsl.js → motion-1r5YB22w.js} +1 -1
- package/src/assets/web-panel/assets/{move-pPR4O1Du.js → move-CvtXWA_V.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Dc7fidhm.js → mtc-parser-ChedmEE_.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CZ1IcubN.js → omit-DpEA3MP0.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BMtJilhr.js → pickAttrs-BWgrUZF6.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D0EXaZA7.js → placementArrow-BWfo_VbI.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-HftdThc5.js → responsiveObserve-CRft03Vk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CT1JEPWV.js → slide-l5LeXusH.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-rwE-IPZB.js → statusUtils-CCEC0JR-.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B2B8XHVq.js → styleChecker-Bw5Gw_2w.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-TXNvIFVa.js → useFlexGapSupport-BAuxWB7K.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BcWgJKvf.js → useFs-CxUP97Cw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DWBDnOSR.js → usePersonalDataHub-BJDjT4Sy.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Cf_LjUuu.js → vnode-BcCsFzIs.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DM2Bfuyl.js → zoom-MLmG09h6.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/eval.js +79 -3
- package/src/commands/llm.js +40 -5
- package/src/data/changelog.json +13 -0
- package/src/lib/context-memory-kernel/message-adapter.js +41 -24
- package/src/lib/context-memory-kernel/segmented-memory-port.js +18 -0
- package/src/lib/eval/runner.js +22 -1
- package/src/lib/eval/verify01-contracts.js +106 -51
- package/src/lib/eval/verify01-execution.js +148 -166
- package/src/lib/eval/verify01-host-evidence.js +34 -2
- package/src/lib/eval/verify01-workspace.js +302 -0
- package/src/lib/execution-location-failure-site.js +18 -0
- package/src/lib/execution-location-target.js +10 -0
- package/src/lib/llm-connection-probe.js +147 -6
- package/src/lib/provider-http-error.js +30 -11
- package/src/lib/task-progress-tracker.js +1 -0
- package/src/runtime/agent-core.js +22 -0
- package/src/runtime/headless-runner.js +30 -20
- package/src/runtime/headless-stream.js +15 -10
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DgMYDmBW.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-CUBuc97a.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CbtBfs7a.js +0 -1
- package/src/assets/web-panel/assets/index-CicoHC0s.js +0 -1
- package/src/assets/web-panel/assets/index-DttyUwDx.js +0 -1
package/src/commands/eval.js
CHANGED
|
@@ -15,8 +15,12 @@ import { fileURLToPath } from "url";
|
|
|
15
15
|
import { runEvalSuite } from "../lib/eval/runner.js";
|
|
16
16
|
import { getSuite } from "../lib/eval/tasks.js";
|
|
17
17
|
import { verifyAgentTerminal } from "../lib/eval/stream-terminal.js";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
captureVerify01AgentBinding,
|
|
20
|
+
persistVerify01Receipts,
|
|
21
|
+
} from "../lib/eval/verify01-execution.js";
|
|
19
22
|
import executionBroker from "../lib/process-execution-broker/index.js";
|
|
23
|
+
import { BUILT_IN_PROVIDERS } from "../lib/llm-providers.js";
|
|
20
24
|
import {
|
|
21
25
|
TelemetryRecorder,
|
|
22
26
|
formatTelemetry,
|
|
@@ -93,7 +97,68 @@ function killAgentTree(child) {
|
|
|
93
97
|
* workspace. acceptEdits lets it write files without an interactive prompt.
|
|
94
98
|
*/
|
|
95
99
|
function makeHeadlessRunAgent(opts = {}) {
|
|
96
|
-
return function runAgent({
|
|
100
|
+
return function runAgent({
|
|
101
|
+
prompt,
|
|
102
|
+
cwd,
|
|
103
|
+
timeoutMs,
|
|
104
|
+
costBudgetUsd,
|
|
105
|
+
verify01Binding,
|
|
106
|
+
}) {
|
|
107
|
+
const binding =
|
|
108
|
+
verify01Binding === undefined
|
|
109
|
+
? null
|
|
110
|
+
: captureVerify01AgentBinding(verify01Binding, cwd);
|
|
111
|
+
if (opts.requireVerify01Binding && !binding)
|
|
112
|
+
throw new Error("frozen suite requires a task-specific agent binding");
|
|
113
|
+
if (
|
|
114
|
+
binding &&
|
|
115
|
+
(binding.provider !== opts.provider || binding.model !== opts.model)
|
|
116
|
+
)
|
|
117
|
+
throw new Error(
|
|
118
|
+
"VERIFY01 provider/model binding differs from the launcher",
|
|
119
|
+
);
|
|
120
|
+
const inherited = { ...process.env, ...(opts.env || {}) };
|
|
121
|
+
const environmentValue = (name) => {
|
|
122
|
+
if (process.platform !== "win32") return inherited[name];
|
|
123
|
+
// Windows environment keys are case-insensitive, but spreading env into
|
|
124
|
+
// a plain object loses that lookup behavior (PATH is usually Path).
|
|
125
|
+
const key = Object.keys(inherited)
|
|
126
|
+
.reverse()
|
|
127
|
+
.find((candidate) => candidate.toLowerCase() === name.toLowerCase());
|
|
128
|
+
return key === undefined ? undefined : inherited[key];
|
|
129
|
+
};
|
|
130
|
+
const providerKey = BUILT_IN_PROVIDERS[binding?.provider]?.apiKeyEnv;
|
|
131
|
+
// Formal children retain platform plumbing and only the selected provider's
|
|
132
|
+
// credential (or the explicitly selected generic CC_API_KEY). Hooks,
|
|
133
|
+
// fallback configuration, NODE_OPTIONS and unrelated account tokens are
|
|
134
|
+
// excluded. Normal, non-formal Eval retains its existing environment.
|
|
135
|
+
const childEnvironment = binding
|
|
136
|
+
? {
|
|
137
|
+
...Object.fromEntries(
|
|
138
|
+
[
|
|
139
|
+
"PATH",
|
|
140
|
+
"SystemRoot",
|
|
141
|
+
"WINDIR",
|
|
142
|
+
"ComSpec",
|
|
143
|
+
"PATHEXT",
|
|
144
|
+
"TEMP",
|
|
145
|
+
"TMP",
|
|
146
|
+
"TMPDIR",
|
|
147
|
+
"LANG",
|
|
148
|
+
"LC_ALL",
|
|
149
|
+
"LC_CTYPE",
|
|
150
|
+
"CC_API_KEY",
|
|
151
|
+
...(providerKey ? [providerKey] : []),
|
|
152
|
+
]
|
|
153
|
+
.map((key) => [key, environmentValue(key)])
|
|
154
|
+
.filter(([, value]) => value !== undefined),
|
|
155
|
+
),
|
|
156
|
+
...binding.environment,
|
|
157
|
+
CC_MAX_RETRIES: "0",
|
|
158
|
+
CLAUDE_CODE_MAX_RETRIES: "0",
|
|
159
|
+
CLAUDECODE: "1",
|
|
160
|
+
}
|
|
161
|
+
: { ...inherited, CLAUDECODE: "1" };
|
|
97
162
|
return new Promise((resolve) => {
|
|
98
163
|
let args;
|
|
99
164
|
if (opts._argv) {
|
|
@@ -115,12 +180,22 @@ function makeHeadlessRunAgent(opts = {}) {
|
|
|
115
180
|
if (opts.provider) args.push("--provider", opts.provider);
|
|
116
181
|
if (opts.ephemeral === true) args.push("--ephemeral");
|
|
117
182
|
if (opts.sandboxMode) args.push("--sandbox-mode", opts.sandboxMode);
|
|
183
|
+
if (binding)
|
|
184
|
+
args.push(
|
|
185
|
+
"--no-project-memory",
|
|
186
|
+
"--no-file-refs",
|
|
187
|
+
"--no-slash-macros",
|
|
188
|
+
"--no-mcp",
|
|
189
|
+
"--no-ide",
|
|
190
|
+
"--no-pdh",
|
|
191
|
+
"--no-jetbrains",
|
|
192
|
+
);
|
|
118
193
|
if (Number.isFinite(costBudgetUsd) && costBudgetUsd >= 0)
|
|
119
194
|
args.push("--max-budget-usd", String(costBudgetUsd));
|
|
120
195
|
}
|
|
121
196
|
const child = _deps.spawn(process.execPath, args, {
|
|
122
197
|
cwd,
|
|
123
|
-
env:
|
|
198
|
+
env: childEnvironment,
|
|
124
199
|
windowsHide: true,
|
|
125
200
|
// Own process group on POSIX so a timeout can reap the whole tree.
|
|
126
201
|
detached: _deps.platform !== "win32",
|
|
@@ -417,6 +492,7 @@ export function registerEvalCommand(program, { logger } = {}) {
|
|
|
417
492
|
? {
|
|
418
493
|
ephemeral: true,
|
|
419
494
|
sandboxMode: tasks.verification.requiredSandboxMode,
|
|
495
|
+
requireVerify01Binding: true,
|
|
420
496
|
}
|
|
421
497
|
: {}),
|
|
422
498
|
});
|
package/src/commands/llm.js
CHANGED
|
@@ -47,7 +47,10 @@ import {
|
|
|
47
47
|
readLlmConnectionInput,
|
|
48
48
|
saveLlmConnection,
|
|
49
49
|
} from "../lib/llm-connection-config.js";
|
|
50
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
probeLlmConnection,
|
|
52
|
+
llmProbeReceipt,
|
|
53
|
+
} from "../lib/llm-connection-probe.js";
|
|
51
54
|
import { resolveModelCapabilityProfile } from "../lib/model-capabilities.js";
|
|
52
55
|
|
|
53
56
|
/**
|
|
@@ -313,6 +316,10 @@ export function registerLlmCommand(program) {
|
|
|
313
316
|
.option("--model <model>", "Model to test (default: configured)")
|
|
314
317
|
.option("--base-url <url>", "API base URL (default: configured/provider)")
|
|
315
318
|
.option("--api-key <key>", "API key (default: configured)")
|
|
319
|
+
.option(
|
|
320
|
+
"--json",
|
|
321
|
+
"Output connection result and token cost estimate as JSON",
|
|
322
|
+
)
|
|
316
323
|
.action(async (options) => {
|
|
317
324
|
const config = loadConfig();
|
|
318
325
|
const target = resolveLlmTestTarget(
|
|
@@ -321,18 +328,46 @@ export function registerLlmCommand(program) {
|
|
|
321
328
|
BUILT_IN_PROVIDERS,
|
|
322
329
|
process.env,
|
|
323
330
|
);
|
|
324
|
-
const spinner =
|
|
331
|
+
const spinner = options.json
|
|
332
|
+
? null
|
|
333
|
+
: ora(`Testing ${target.provider}...`).start();
|
|
334
|
+
const safe = (text) =>
|
|
335
|
+
target.apiKey
|
|
336
|
+
? String(text).replaceAll(target.apiKey, "[REDACTED]")
|
|
337
|
+
: String(text);
|
|
325
338
|
try {
|
|
326
339
|
const start = Date.now();
|
|
327
340
|
|
|
328
|
-
const reply = await probeLlmConnection(target
|
|
341
|
+
const reply = await probeLlmConnection(target, {
|
|
342
|
+
includeUsage: !!options.json,
|
|
343
|
+
});
|
|
344
|
+
if (options.json) {
|
|
345
|
+
console.log(
|
|
346
|
+
JSON.stringify({
|
|
347
|
+
...reply,
|
|
348
|
+
reply: safe(reply.reply),
|
|
349
|
+
elapsedMs: Date.now() - start,
|
|
350
|
+
}),
|
|
351
|
+
);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
329
354
|
spinner.succeed(
|
|
330
355
|
`${chalk.green("Connected")} to ${target.label} (${target.model}) in ${Date.now() - start}ms`,
|
|
331
356
|
);
|
|
332
357
|
logger.log(` Response: ${chalk.gray(reply)}`);
|
|
333
358
|
} catch (err) {
|
|
334
|
-
|
|
335
|
-
|
|
359
|
+
if (options.json) {
|
|
360
|
+
console.log(
|
|
361
|
+
JSON.stringify({
|
|
362
|
+
...(err.probe || llmProbeReceipt(target)),
|
|
363
|
+
error: safe(err.message),
|
|
364
|
+
}),
|
|
365
|
+
);
|
|
366
|
+
process.exitCode = 1;
|
|
367
|
+
} else {
|
|
368
|
+
spinner.fail(`Test failed: ${err.message}`);
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
336
371
|
}
|
|
337
372
|
});
|
|
338
373
|
|
package/src/data/changelog.json
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "CHANGELOG.md",
|
|
3
3
|
"releases": [
|
|
4
|
+
{
|
|
5
|
+
"productVersion": null,
|
|
6
|
+
"cliVersion": "0.166.98",
|
|
7
|
+
"cliVersions": ["0.166.98"],
|
|
8
|
+
"date": null,
|
|
9
|
+
"title": "",
|
|
10
|
+
"sections": [
|
|
11
|
+
{
|
|
12
|
+
"heading": "Fixed - cc CLI 0.166.98: apply real-task findings and preserve task delivery",
|
|
13
|
+
"body": "- Bind formal task file scope and tool allowlists to isolated per-task configuration;\n preserve rejected call identities and strict trace acceptance.\n- Keep authentication usage on failed answers, redact credentials before truncation,\n and separate tool estimates from unknown authentication or whole-journey costs.\n- Bootstrap first-run diagnostics without development dependencies and retain the\n actual failed journey, empty candidate, and unexecuted semantic outcomes.\n- Give finite-budget runs fresh delivery guidance without placing the changing\n counter before the stable OpenAI-compatible conversation prefix. Preserve the\n current user task across host and goal/hook suffixes in the canonical planner.\n- Publish changed Session Core 0.3.19 before CLI 0.166.98; retain unchanged child\n versions only after exact-source, registry-byte and provenance verification.\n- Pair VS Code 0.37.142 and JetBrains 0.4.160 after the final source gates pass\n and CLI 0.166.98 is publicly available. Formal 36+9 evaluation and native\n durable authority acceptance remain open."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
4
17
|
{
|
|
5
18
|
"productVersion": null,
|
|
6
19
|
"cliVersion": "0.166.97",
|
|
@@ -68,8 +68,7 @@ function trustForBundle(messages) {
|
|
|
68
68
|
if (
|
|
69
69
|
messages.every(
|
|
70
70
|
(message) =>
|
|
71
|
-
message.role === "system" &&
|
|
72
|
-
getDurableSystemMessageProvenance(message),
|
|
71
|
+
message.role === "system" && getDurableSystemMessageProvenance(message),
|
|
73
72
|
)
|
|
74
73
|
) {
|
|
75
74
|
return "verified";
|
|
@@ -135,12 +134,16 @@ function createItem({
|
|
|
135
134
|
observedAt: new Date(sequence).toISOString(),
|
|
136
135
|
},
|
|
137
136
|
trust:
|
|
138
|
-
trustedSystemPolicy &&
|
|
137
|
+
trustedSystemPolicy &&
|
|
138
|
+
messages.every((message) => message.role === "system")
|
|
139
139
|
? "host"
|
|
140
140
|
: trustForBundle(messages),
|
|
141
141
|
sensitivity: "personal",
|
|
142
142
|
allowedSinks: allowedSinks || DEFAULT_ALLOWED_SINKS,
|
|
143
|
-
tokenEstimate: Math.max(
|
|
143
|
+
tokenEstimate: Math.max(
|
|
144
|
+
1,
|
|
145
|
+
Math.ceil(Buffer.byteLength(content, "utf8") / 4),
|
|
146
|
+
),
|
|
144
147
|
priority: priorityForBundle(messages, sequence, pendingTool),
|
|
145
148
|
pinned: false,
|
|
146
149
|
createdAt: new Date(sequence).toISOString(),
|
|
@@ -195,7 +198,8 @@ export function messagesToContextItems(messagesInput, options = {}) {
|
|
|
195
198
|
seen.add(resultId);
|
|
196
199
|
cursor += 1;
|
|
197
200
|
}
|
|
198
|
-
const pending =
|
|
201
|
+
const pending =
|
|
202
|
+
ids.length !== calls.length || seen.size !== expected.size;
|
|
199
203
|
const groupDigest = canonicalDigest(
|
|
200
204
|
{ sessionId, index, ids: [...expected].sort() },
|
|
201
205
|
"chainlesschain.cli-tool-group/v1",
|
|
@@ -245,7 +249,14 @@ export function messagesToContextItems(messagesInput, options = {}) {
|
|
|
245
249
|
);
|
|
246
250
|
}
|
|
247
251
|
|
|
248
|
-
|
|
252
|
+
// Ephemeral host guidance and hook suffixes can follow the current user
|
|
253
|
+
// request. They must not turn that request into optional conversation.
|
|
254
|
+
// Stop at the last conversational/tool bundle, so completed historical
|
|
255
|
+
// user turns are not promoted over a newer assistant or tool result.
|
|
256
|
+
const lastIndex = items.findLastIndex(
|
|
257
|
+
(item) => item.kind !== "system-policy",
|
|
258
|
+
);
|
|
259
|
+
const last = items[lastIndex];
|
|
249
260
|
if (last) {
|
|
250
261
|
const payload = JSON.parse(last.content);
|
|
251
262
|
if (payload.messages.at(-1)?.role === "user") {
|
|
@@ -257,7 +268,7 @@ export function messagesToContextItems(messagesInput, options = {}) {
|
|
|
257
268
|
taskState: "waiting",
|
|
258
269
|
requiredForRecovery: true,
|
|
259
270
|
};
|
|
260
|
-
items[
|
|
271
|
+
items[lastIndex] = normalizeContextItem(protectedItem);
|
|
261
272
|
}
|
|
262
273
|
}
|
|
263
274
|
return items;
|
|
@@ -317,7 +328,9 @@ export function memoryRecordsToContextItems(recordsInput, options = {}) {
|
|
|
317
328
|
|
|
318
329
|
function decodeBundle(item) {
|
|
319
330
|
if (typeof item?.content !== "string") {
|
|
320
|
-
throw new TypeError(
|
|
331
|
+
throw new TypeError(
|
|
332
|
+
`ContextItem ${item?.itemId || "unknown"} has no inline content`,
|
|
333
|
+
);
|
|
321
334
|
}
|
|
322
335
|
const payload = JSON.parse(item.content);
|
|
323
336
|
if (
|
|
@@ -327,17 +340,19 @@ function decodeBundle(item) {
|
|
|
327
340
|
!Array.isArray(payload.durableSystemKinds) ||
|
|
328
341
|
payload.durableSystemKinds.length !== payload.messages.length
|
|
329
342
|
) {
|
|
330
|
-
throw new TypeError(
|
|
343
|
+
throw new TypeError(
|
|
344
|
+
`ContextItem ${item.itemId} is not a CLI message bundle`,
|
|
345
|
+
);
|
|
331
346
|
}
|
|
332
347
|
return payload.messages.map((message, index) => {
|
|
333
348
|
if (!message || typeof message !== "object" || Array.isArray(message)) {
|
|
334
|
-
throw new TypeError(
|
|
349
|
+
throw new TypeError(
|
|
350
|
+
`ContextItem ${item.itemId} contains an invalid message`,
|
|
351
|
+
);
|
|
335
352
|
}
|
|
336
353
|
const copy = structuredClone(message);
|
|
337
354
|
const durableKind = payload.durableSystemKinds[index];
|
|
338
|
-
return durableKind
|
|
339
|
-
? markDurableSystemMessage(copy, durableKind)
|
|
340
|
-
: copy;
|
|
355
|
+
return durableKind ? markDurableSystemMessage(copy, durableKind) : copy;
|
|
341
356
|
});
|
|
342
357
|
}
|
|
343
358
|
|
|
@@ -376,7 +391,9 @@ export function createSummaryContextItem({
|
|
|
376
391
|
if (parents.length === 0) throw new TypeError("summary parents are required");
|
|
377
392
|
const scope = parents[0].scope;
|
|
378
393
|
const scopeId = parents[0].scopeId;
|
|
379
|
-
if (
|
|
394
|
+
if (
|
|
395
|
+
parents.some((item) => item.scope !== scope || item.scopeId !== scopeId)
|
|
396
|
+
) {
|
|
380
397
|
throw new TypeError("summary parents must share one scope");
|
|
381
398
|
}
|
|
382
399
|
const summaryMessages = safeMessages(messages).map((message) =>
|
|
@@ -398,16 +415,16 @@ export function createSummaryContextItem({
|
|
|
398
415
|
{ operationId, parentDigests, content },
|
|
399
416
|
"chainlesschain.cli-context-summary/v1",
|
|
400
417
|
);
|
|
401
|
-
const trust =
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
418
|
+
const trust =
|
|
419
|
+
TRUST_ORDER[
|
|
420
|
+
Math.max(...parents.map((item) => TRUST_ORDER.indexOf(item.trust)))
|
|
421
|
+
];
|
|
422
|
+
const sensitivity =
|
|
423
|
+
SENSITIVITY_ORDER[
|
|
424
|
+
Math.max(
|
|
425
|
+
...parents.map((item) => SENSITIVITY_ORDER.indexOf(item.sensitivity)),
|
|
426
|
+
)
|
|
427
|
+
];
|
|
411
428
|
const allowedSinks = [...intersectAllowedSinks(parents)].sort();
|
|
412
429
|
if (allowedSinks.length === 0) {
|
|
413
430
|
throw new TypeError("summary parents have no common allowed sink");
|
|
@@ -115,6 +115,24 @@ function directories(directory) {
|
|
|
115
115
|
realpathSync(current) === `/private${current}`;
|
|
116
116
|
if (!systemAlias && (!stat.isDirectory() || stat.isSymbolicLink()))
|
|
117
117
|
throw corruptStore(current, "authority directory is unsafe");
|
|
118
|
+
if (process.platform === "win32") {
|
|
119
|
+
// Some Windows runtime adapters report an ordinary directory for a
|
|
120
|
+
// junction whose target cannot be decoded in their DOS namespace. Keep
|
|
121
|
+
// the lstat guard and independently reject a different native canonical
|
|
122
|
+
// coordinate before mkdir or lock acquisition. This is an additional
|
|
123
|
+
// consistency check, not a proof against every reparse tag or a race.
|
|
124
|
+
let canonical;
|
|
125
|
+
try {
|
|
126
|
+
canonical = realpathSync.native(current);
|
|
127
|
+
} catch {
|
|
128
|
+
throw corruptStore(current, "authority directory cannot be resolved");
|
|
129
|
+
}
|
|
130
|
+
if (
|
|
131
|
+
typeof canonical !== "string" ||
|
|
132
|
+
resolve(canonical).toLowerCase() !== current.toLowerCase()
|
|
133
|
+
)
|
|
134
|
+
throw corruptStore(current, "authority directory resolves elsewhere");
|
|
135
|
+
}
|
|
118
136
|
const parent = dirname(current);
|
|
119
137
|
if (parent === current) break;
|
|
120
138
|
current = parent;
|
package/src/lib/eval/runner.js
CHANGED
|
@@ -152,7 +152,13 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
152
152
|
if (typeof task.check !== "function") {
|
|
153
153
|
throw new Error(`task "${rec.id}": check() is required`);
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
// Resolve the OS temporary directory first (macOS commonly aliases
|
|
156
|
+
// /var to /private/var), then create formal workspaces at canonical paths.
|
|
157
|
+
const taskBase =
|
|
158
|
+
typeof task.agentLaunchBinding === "function"
|
|
159
|
+
? (fs.realpathSync.native || fs.realpathSync)(base)
|
|
160
|
+
: base;
|
|
161
|
+
dir = _deps.mkdtempSync(path.join(taskBase, `cc-eval-${task.id}-`));
|
|
156
162
|
if (typeof task.setup === "function") {
|
|
157
163
|
await task.setup(dir, budget);
|
|
158
164
|
}
|
|
@@ -169,6 +175,9 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
169
175
|
prompt: task.prompt,
|
|
170
176
|
cwd: dir,
|
|
171
177
|
timeoutMs: budget.remainingMs(),
|
|
178
|
+
...(typeof task.agentLaunchBinding === "function"
|
|
179
|
+
? { verify01Binding: task.agentLaunchBinding(dir) }
|
|
180
|
+
: {}),
|
|
172
181
|
...(task.costBudgetUsd === undefined
|
|
173
182
|
? {}
|
|
174
183
|
: { costBudgetUsd: task.costBudgetUsd }),
|
|
@@ -234,6 +243,18 @@ export async function runEvalSuite(tasks, opts = {}) {
|
|
|
234
243
|
});
|
|
235
244
|
rec.pass = false;
|
|
236
245
|
} finally {
|
|
246
|
+
try {
|
|
247
|
+
await task?.cleanup?.();
|
|
248
|
+
} catch (error) {
|
|
249
|
+
rec.pass = false;
|
|
250
|
+
rec.error ||= `task cleanup failed: ${error.message}`;
|
|
251
|
+
rec.failurePhase = "cleanup";
|
|
252
|
+
task.recordFailure?.({
|
|
253
|
+
phase: "cleanup",
|
|
254
|
+
code: error.code || null,
|
|
255
|
+
error: error.message,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
237
258
|
rec.ms = _deps.now() - started;
|
|
238
259
|
if (span) {
|
|
239
260
|
span.setAttribute("pass", rec.pass);
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { requireValue, relativeFile, readBytes } from "./verify01-workspace.js";
|
|
2
|
+
import {
|
|
3
|
+
LLM_PROBE_SCHEMA,
|
|
4
|
+
llmProbeReceipt,
|
|
5
|
+
priceLlmProbeUsage,
|
|
6
|
+
} from "../llm-connection-probe.js";
|
|
2
7
|
import {
|
|
3
8
|
createEvalComparison,
|
|
4
9
|
EVAL_EXECUTION_PROTOCOL,
|
|
@@ -11,9 +16,92 @@ import {
|
|
|
11
16
|
validateOutcomePlan,
|
|
12
17
|
} from "./outcomes.js";
|
|
13
18
|
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
14
|
-
|
|
15
|
-
function
|
|
16
|
-
|
|
19
|
+
/** Task terminals only cover the tool stage; authentication is a separate call. */
|
|
20
|
+
export function createVerify01FirstRunCost({
|
|
21
|
+
authentication,
|
|
22
|
+
authenticationReceipt,
|
|
23
|
+
authenticated,
|
|
24
|
+
comparison,
|
|
25
|
+
toolCostUsd,
|
|
26
|
+
}) {
|
|
27
|
+
requireValue(
|
|
28
|
+
DIGEST.test(authenticationReceipt || ""),
|
|
29
|
+
"first-run authentication receipt digest required",
|
|
30
|
+
);
|
|
31
|
+
requireValue(
|
|
32
|
+
toolCostUsd === null || (Number.isFinite(toolCostUsd) && toolCostUsd >= 0),
|
|
33
|
+
"invalid first-run tool cost",
|
|
34
|
+
);
|
|
35
|
+
let probe = null;
|
|
36
|
+
if (authentication !== null) {
|
|
37
|
+
requireValue(
|
|
38
|
+
authentication?.schema === LLM_PROBE_SCHEMA &&
|
|
39
|
+
authentication.provider === comparison.provider &&
|
|
40
|
+
authentication.model === comparison.model &&
|
|
41
|
+
authentication.ok === authenticated &&
|
|
42
|
+
authentication.currency === "USD" &&
|
|
43
|
+
authentication.costBasis === "token-estimate" &&
|
|
44
|
+
authentication.billingVerified === false,
|
|
45
|
+
"first-run authentication identity or estimate basis differs",
|
|
46
|
+
);
|
|
47
|
+
const usage = authentication.usage;
|
|
48
|
+
requireValue(
|
|
49
|
+
usage === null ||
|
|
50
|
+
(usage &&
|
|
51
|
+
[
|
|
52
|
+
usage.input_tokens,
|
|
53
|
+
usage.output_tokens,
|
|
54
|
+
usage.cache_read_input_tokens,
|
|
55
|
+
usage.cache_creation_input_tokens,
|
|
56
|
+
].every((value) => Number.isSafeInteger(value) && value >= 0)),
|
|
57
|
+
"invalid first-run authentication usage",
|
|
58
|
+
);
|
|
59
|
+
const cost = priceLlmProbeUsage(comparison, usage);
|
|
60
|
+
requireValue(
|
|
61
|
+
authentication.totalCostUsd === cost,
|
|
62
|
+
"first-run authentication cost differs from its token estimate",
|
|
63
|
+
);
|
|
64
|
+
probe = llmProbeReceipt(comparison, { ok: authenticated, usage });
|
|
65
|
+
}
|
|
66
|
+
const authCostUsd = probe?.totalCostUsd ?? null;
|
|
67
|
+
const totalCostUsd =
|
|
68
|
+
authCostUsd !== null && toolCostUsd !== null
|
|
69
|
+
? authCostUsd + toolCostUsd
|
|
70
|
+
: null;
|
|
71
|
+
requireValue(
|
|
72
|
+
totalCostUsd === null || Number.isFinite(totalCostUsd),
|
|
73
|
+
"first-run total cost overflow",
|
|
74
|
+
);
|
|
75
|
+
return {
|
|
76
|
+
schema: "chainlesschain.verify01-first-run-cost/v1",
|
|
77
|
+
authenticationReceipt,
|
|
78
|
+
authentication: probe,
|
|
79
|
+
toolCostUsd,
|
|
80
|
+
totalCostUsd,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function validateFirstRunCost(observation, comparison, toolCostUsd) {
|
|
85
|
+
const accounting = observation.firstRun?.costAccounting;
|
|
86
|
+
if (!accounting) {
|
|
87
|
+
requireValue(
|
|
88
|
+
observation.cost === null,
|
|
89
|
+
"first-run cost without authentication accounting must remain unknown",
|
|
90
|
+
);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const expected = createVerify01FirstRunCost({
|
|
94
|
+
authentication: accounting.authentication,
|
|
95
|
+
authenticationReceipt: observation.firstRun.stages.authenticate.receipt,
|
|
96
|
+
authenticated: observation.firstRun.stages.authenticate.passed,
|
|
97
|
+
comparison,
|
|
98
|
+
toolCostUsd,
|
|
99
|
+
});
|
|
100
|
+
requireValue(
|
|
101
|
+
outcomeDigest(accounting) === outcomeDigest(expected) &&
|
|
102
|
+
observation.cost === expected.totalCostUsd,
|
|
103
|
+
"first-run journey cost differs from authentication plus tool cost",
|
|
104
|
+
);
|
|
17
105
|
}
|
|
18
106
|
function index(rows, key, label) {
|
|
19
107
|
requireValue(Array.isArray(rows), `${label} must be an array`);
|
|
@@ -29,51 +117,6 @@ function index(rows, key, label) {
|
|
|
29
117
|
}
|
|
30
118
|
return result;
|
|
31
119
|
}
|
|
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
120
|
const readJson = (file) => JSON.parse(readBytes(file).toString("utf8"));
|
|
78
121
|
|
|
79
122
|
export function validateVerify01Bundle({
|
|
@@ -278,6 +321,12 @@ export function validateVerify01Collection(
|
|
|
278
321
|
row.reasons.every((reason) => failureReasons.has(reason)),
|
|
279
322
|
"invalid first-run early-stop evidence",
|
|
280
323
|
);
|
|
324
|
+
// A failed tool stage does not prove no billable request was attempted.
|
|
325
|
+
validateFirstRunCost(
|
|
326
|
+
observation,
|
|
327
|
+
bundle.bindings.comparisons[sample.stratum],
|
|
328
|
+
null,
|
|
329
|
+
);
|
|
281
330
|
continue;
|
|
282
331
|
}
|
|
283
332
|
const run = runs.get(observation.runId);
|
|
@@ -309,10 +358,16 @@ export function validateVerify01Collection(
|
|
|
309
358
|
used.add(key);
|
|
310
359
|
const cost = result.totalCostUsd;
|
|
311
360
|
requireValue(
|
|
312
|
-
|
|
313
|
-
observation.cost === cost,
|
|
361
|
+
cost === null || (Number.isFinite(cost) && cost >= 0),
|
|
314
362
|
"unknown or mismatched cost must not become zero",
|
|
315
363
|
);
|
|
364
|
+
if (sample.kind === "first-run")
|
|
365
|
+
validateFirstRunCost(observation, run.comparison, cost);
|
|
366
|
+
else
|
|
367
|
+
requireValue(
|
|
368
|
+
observation.cost === cost,
|
|
369
|
+
"unknown or mismatched cost must not become zero",
|
|
370
|
+
);
|
|
316
371
|
requireValue(
|
|
317
372
|
Array.isArray(result.changedFiles) &&
|
|
318
373
|
new Set(result.changedFiles).size === result.changedFiles.length,
|