@tangle-network/agent-eval 0.217.1 → 0.218.1
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/CHANGELOG.md +36 -1
- package/dist/adapters/http.d.ts +2 -2
- package/dist/analyst/index.d.ts +1 -1
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +9 -9
- package/dist/analyst/index.js.map +1 -1
- package/dist/{analyze-runs-DyeNcenW.d.ts → analyze-runs-DjlZOVXx.d.ts} +2 -2
- package/dist/{analyze-runs-DyeNcenW.d.ts.map → analyze-runs-DjlZOVXx.d.ts.map} +1 -1
- package/dist/{benchmark-command-xQK8nOI6.js → benchmark-command-BupdHRyf.js} +661 -562
- package/dist/benchmark-command-BupdHRyf.js.map +1 -0
- package/dist/benchmarks/index.d.ts +4 -4
- package/dist/benchmarks/index.js +3 -3
- package/dist/campaign/index.d.ts +4 -4
- package/dist/campaign/index.js +10 -10
- package/dist/{campaign-CJGkxAQ6.js → campaign-CGvUTnmc.js} +312 -281
- package/dist/{campaign-CJGkxAQ6.js.map → campaign-CGvUTnmc.js.map} +1 -1
- package/dist/{campaign-evidence-CQYw8_0H.js → campaign-evidence-DunzcJGv.js} +2 -2
- package/dist/{campaign-evidence-CQYw8_0H.js.map → campaign-evidence-DunzcJGv.js.map} +1 -1
- package/dist/{chat-client-ldqxYYTN.js → chat-client-B2pXlPdx.js} +2 -2
- package/dist/{chat-client-ldqxYYTN.js.map → chat-client-B2pXlPdx.js.map} +1 -1
- package/dist/{chat-json-call-DavzexSp.js → chat-json-call-Dm9c-b41.js} +2 -2
- package/dist/{chat-json-call-DavzexSp.js.map → chat-json-call-Dm9c-b41.js.map} +1 -1
- package/dist/cli.js +10 -10
- package/dist/{completion-verifier-B_jw6C9p.js → completion-verifier-DbLVf3i8.js} +4 -4
- package/dist/{completion-verifier-B_jw6C9p.js.map → completion-verifier-DbLVf3i8.js.map} +1 -1
- package/dist/contract/index.d.ts +7 -7
- package/dist/contract/index.js +90 -10
- package/dist/contract/index.js.map +1 -1
- package/dist/{default-registry-ClYjq3QE.js → default-registry-BJ-Pq6yL.js} +309 -277
- package/dist/{default-registry-ClYjq3QE.js.map → default-registry-BJ-Pq6yL.js.map} +1 -1
- package/dist/{define-agent-eval-BDxNlP3D.js → define-agent-eval-BGdFKlrc.js} +165 -105
- package/dist/define-agent-eval-BGdFKlrc.js.map +1 -0
- package/dist/{define-agent-eval-BIkH_gAR.d.ts → define-agent-eval-BlH10zEw.d.ts} +6 -6
- package/dist/{define-agent-eval-BIkH_gAR.d.ts.map → define-agent-eval-BlH10zEw.d.ts.map} +1 -1
- package/dist/diagnosis/index.d.ts +1 -1
- package/dist/{dspy-rlm-engine-DhdCr1Dc.js → dspy-rlm-engine-CSMwudLO.js} +2 -2
- package/dist/{dspy-rlm-engine-DhdCr1Dc.js.map → dspy-rlm-engine-CSMwudLO.js.map} +1 -1
- package/dist/eval-campaign-BUMIxKTE.js +393 -0
- package/dist/eval-campaign-BUMIxKTE.js.map +1 -0
- package/dist/{evaluation-jTjC_QQD.d.ts → evaluation-BOZ38vOH.d.ts} +2 -2
- package/dist/{evaluation-jTjC_QQD.d.ts.map → evaluation-BOZ38vOH.d.ts.map} +1 -1
- package/dist/evaluation.d.ts +1 -1
- package/dist/experiment/index.d.ts +1 -1
- package/dist/experiment/index.d.ts.map +1 -1
- package/dist/experiment/index.js +110 -71
- package/dist/experiment/index.js.map +1 -1
- package/dist/{exporters-Cl6IeNAu.js → exporters-DWvM16LE.js} +2 -2
- package/dist/{exporters-Cl6IeNAu.js.map → exporters-DWvM16LE.js.map} +1 -1
- package/dist/{external-optimizer-process-KVFGvYX1.js → external-optimizer-process-C3Wm7Vhn.js} +2 -2
- package/dist/{external-optimizer-process-KVFGvYX1.js.map → external-optimizer-process-C3Wm7Vhn.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-XIHBOSKt.js → external-optimizer-subprocess-B5gdLRZv.js} +3 -3
- package/dist/{external-optimizer-subprocess-XIHBOSKt.js.map → external-optimizer-subprocess-B5gdLRZv.js.map} +1 -1
- package/dist/{findings-store-BMVQtEsm.js → findings-store-BtTzPL0d.js} +5 -5
- package/dist/{findings-store-BMVQtEsm.js.map → findings-store-BtTzPL0d.js.map} +1 -1
- package/dist/{hf-dataset-D9f7-oX7.js → hf-dataset-CKxIJQba.js} +3 -3
- package/dist/{hf-dataset-D9f7-oX7.js.map → hf-dataset-CKxIJQba.js.map} +1 -1
- package/dist/hosted/index.js +1 -1
- package/dist/{index-ZuWx52WG.d.ts → index-B16FNdW5.d.ts} +34 -17
- package/dist/index-B16FNdW5.d.ts.map +1 -0
- package/dist/{index-9jJ2fKSX.d.ts → index-CalAsXMR.d.ts} +7 -5
- package/dist/index-CalAsXMR.d.ts.map +1 -0
- package/dist/{index-BiT6RtNH.d.ts → index-DbMOXYnP.d.ts} +6 -6
- package/dist/{index-BiT6RtNH.d.ts.map → index-DbMOXYnP.d.ts.map} +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +611 -688
- package/dist/index.js.map +1 -1
- package/dist/{integrity-DOd9Q86O.js → integrity-C8oUeB0g.js} +322 -197
- package/dist/integrity-C8oUeB0g.js.map +1 -0
- package/dist/{journal-CR4QikYp.js → journal-C7om8Gum.js} +48 -38
- package/dist/journal-C7om8Gum.js.map +1 -0
- package/dist/ledger-core/index.d.ts +1 -1
- package/dist/ledger-core/index.js +2 -2
- package/dist/ledger-core/lock-holder.d.ts +2 -0
- package/dist/ledger-core/lock-holder.js +181 -0
- package/dist/ledger-core/lock-holder.js.map +1 -0
- package/dist/{ledger-core-DrJhbms9.js → ledger-core-CAxUdDk0.js} +2 -2
- package/dist/{ledger-core-DrJhbms9.js.map → ledger-core-CAxUdDk0.js.map} +1 -1
- package/dist/{llm-client-BshCREn6.js → llm-client-_Y6ic-tf.js} +238 -248
- package/dist/llm-client-_Y6ic-tf.js.map +1 -0
- package/dist/{llm-judge-C8jMTNNG.js → llm-judge-Djxh-Uhs.js} +646 -458
- package/dist/llm-judge-Djxh-Uhs.js.map +1 -0
- package/dist/lock-holder-DaJbfpci.d.ts +86 -0
- package/dist/lock-holder-DaJbfpci.d.ts.map +1 -0
- package/dist/{matrix-DHe-dwVJ.d.ts → matrix-CCSBna4q.d.ts} +2 -2
- package/dist/{matrix-DHe-dwVJ.d.ts.map → matrix-CCSBna4q.d.ts.map} +1 -1
- package/dist/{mint-zszyYlpA.js → mint-CbdwjTPW.js} +2 -2
- package/dist/{mint-zszyYlpA.js.map → mint-CbdwjTPW.js.map} +1 -1
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/openapi.json +1 -1
- package/dist/{pareto-BzsxidFD.js → pareto-CTv8vozZ.js} +4 -4
- package/dist/{pareto-BzsxidFD.js.map → pareto-CTv8vozZ.js.map} +1 -1
- package/dist/{promotion-gate-DaY95yU6.d.ts → promotion-gate-CxEHRsZW.d.ts} +2 -2
- package/dist/{promotion-gate-DaY95yU6.d.ts.map → promotion-gate-CxEHRsZW.d.ts.map} +1 -1
- package/dist/{proposal-findings-BbWidvUk.js → proposal-findings-n-5WBbEx.js} +2 -2
- package/dist/{proposal-findings-BbWidvUk.js.map → proposal-findings-n-5WBbEx.js.map} +1 -1
- package/dist/{render-C-w2EZ6p.js → render-Cs34y0iX.js} +404 -208
- package/dist/render-Cs34y0iX.js.map +1 -0
- package/dist/reporting.d.ts +2 -2
- package/dist/{researcher-0ABVIdGa.d.ts → researcher-GU1tV4dn.d.ts} +2 -2
- package/dist/{researcher-0ABVIdGa.d.ts.map → researcher-GU1tV4dn.d.ts.map} +1 -1
- package/dist/rl.d.ts +2 -2
- package/dist/rl.js +4 -4
- package/dist/rollout/index.js +5 -5
- package/dist/{rollout-D6C50mfA.js → rollout-Dd1ucT_M.js} +5 -5
- package/dist/{rollout-D6C50mfA.js.map → rollout-Dd1ucT_M.js.map} +1 -1
- package/dist/schema-C-ziyJD7.d.ts.map +1 -1
- package/dist/{schema-DxcKTzbi.js → schema-CvhfLjtZ.js} +77 -47
- package/dist/schema-CvhfLjtZ.js.map +1 -0
- package/dist/search/index.d.ts +2 -2
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +2 -2
- package/dist/{search-kernel-DxqjBxA-.d.ts → search-kernel-p9JB3SmL.d.ts} +3 -3
- package/dist/{search-kernel-DxqjBxA-.d.ts.map → search-kernel-p9JB3SmL.d.ts.map} +1 -1
- package/dist/{search-ledger-TUvB5gWH.js → search-ledger-ClpN4I3e.js} +4 -4
- package/dist/{search-ledger-TUvB5gWH.js.map → search-ledger-ClpN4I3e.js.map} +1 -1
- package/dist/{search-ledger-file-UKCO2r8a.js → search-ledger-file-Bd5Tioq6.js} +3 -3
- package/dist/{search-ledger-file-UKCO2r8a.js.map → search-ledger-file-Bd5Tioq6.js.map} +1 -1
- package/dist/{search-shipper-Cw2z3-td.js → search-shipper-Bg2HW3Uv.js} +3 -3
- package/dist/{search-shipper-Cw2z3-td.js.map → search-shipper-Bg2HW3Uv.js.map} +1 -1
- package/dist/{search-summary-DQIvJsSB.js → search-summary-CrBuvVnf.js} +3 -3
- package/dist/{search-summary-DQIvJsSB.js.map → search-summary-CrBuvVnf.js.map} +1 -1
- package/dist/{server-DoVbqqtJ.js → server-C6M0qR8h.js} +2 -2
- package/dist/{server-DoVbqqtJ.js.map → server-C6M0qR8h.js.map} +1 -1
- package/dist/{single-run-lock-U58yf8N6.js → single-run-lock-Dekd8_Wv.js} +7 -7
- package/dist/single-run-lock-Dekd8_Wv.js.map +1 -0
- package/dist/{skillopt-optimization-method-kyL94-ri.js → skillopt-optimization-method-5dlex7MJ.js} +1339 -1059
- package/dist/skillopt-optimization-method-5dlex7MJ.js.map +1 -0
- package/dist/{statistical-heldout-C9AbgREN.d.ts → statistical-heldout-BHfLZHrm.d.ts} +2 -2
- package/dist/{statistical-heldout-C9AbgREN.d.ts.map → statistical-heldout-BHfLZHrm.d.ts.map} +1 -1
- package/dist/{summary-report-DM7tlml1.d.ts → summary-report-CkbRcSuu.d.ts} +16 -1
- package/dist/summary-report-CkbRcSuu.d.ts.map +1 -0
- package/dist/supervisor-run/index.d.ts.map +1 -1
- package/dist/supervisor-run/index.js +3 -3
- package/dist/{systemone-Bp_Ac0p1.d.ts → systemone-BMzDJb1i.d.ts} +3 -3
- package/dist/{systemone-Bp_Ac0p1.d.ts.map → systemone-BMzDJb1i.d.ts.map} +1 -1
- package/dist/systemone.d.ts +2 -2
- package/dist/{terminal-record-78g6E4vh.js → terminal-record-D4Rv-j1W.js} +241 -193
- package/dist/{terminal-record-78g6E4vh.js.map → terminal-record-D4Rv-j1W.js.map} +1 -1
- package/dist/trajectory-replay/index.d.ts +4 -1
- package/dist/trajectory-replay/index.d.ts.map +1 -1
- package/dist/trajectory-replay/index.js +834 -824
- package/dist/trajectory-replay/index.js.map +1 -1
- package/dist/{tree-BGRglkKd.js → tree-B5e1uAeL.js} +122 -14
- package/dist/tree-B5e1uAeL.js.map +1 -0
- package/dist/{types-DtMbFw6U.d.ts → types-BKCzzmit.d.ts} +2 -2
- package/dist/{types-DtMbFw6U.d.ts.map → types-BKCzzmit.d.ts.map} +1 -1
- package/dist/{types-D8GhJoHk.d.ts → types-DtkO1G9L.d.ts} +2 -2
- package/dist/{types-D8GhJoHk.d.ts.map → types-DtkO1G9L.d.ts.map} +1 -1
- package/dist/wire/index.js +1 -1
- package/docs/design/statistics-decisions.md +1 -1
- package/docs/eval-surface-map.md +1 -0
- package/docs/profile-json-identity.md +1 -2
- package/docs/public-api.md +27 -16
- package/package.json +7 -2
- package/dist/benchmark-command-xQK8nOI6.js.map +0 -1
- package/dist/define-agent-eval-BDxNlP3D.js.map +0 -1
- package/dist/eval-campaign-BLEfBGbA.js +0 -343
- package/dist/eval-campaign-BLEfBGbA.js.map +0 -1
- package/dist/index-9jJ2fKSX.d.ts.map +0 -1
- package/dist/index-ZuWx52WG.d.ts.map +0 -1
- package/dist/integrity-DOd9Q86O.js.map +0 -1
- package/dist/journal-CR4QikYp.js.map +0 -1
- package/dist/llm-client-BshCREn6.js.map +0 -1
- package/dist/llm-judge-C8jMTNNG.js.map +0 -1
- package/dist/render-C-w2EZ6p.js.map +0 -1
- package/dist/schema-DxcKTzbi.js.map +0 -1
- package/dist/single-run-lock-U58yf8N6.js.map +0 -1
- package/dist/skillopt-optimization-method-kyL94-ri.js.map +0 -1
- package/dist/summary-report-DM7tlml1.d.ts.map +0 -1
- package/dist/tree-BGRglkKd.js.map +0 -1
|
@@ -8,18 +8,18 @@ import { a as heldoutSignificance, i as dimensionRegressions, o as pairHoldout }
|
|
|
8
8
|
import { n as contentHash } from "./verdict-cache-CL_7tePD.js";
|
|
9
9
|
import { r as projectCampaignCellQuality, t as campaignCellCostProvenance } from "./run-record-CysKLB93.js";
|
|
10
10
|
import { n as CostAccountingIncompleteError, t as CostLedger } from "./cost-ledger-D0352Z4d.js";
|
|
11
|
-
import { A as surfaceHashMatches, D as surfaceContentHash, E as renderSurfaceDiff, F as assertCampaignSplitIdentity, I as assertCompleteCampaign, L as campaignCoverage, O as surfaceDispatchRef, P as assertCampaignDesign, R as campaignScenarioIdentity, V as formatCoverageFailures, b as FinalEvidenceConflictError, f as campaignBreakdown, j as BackendIntegrityError, k as surfaceHash, m as campaignMeanCompositeOrNull, p as campaignMeanComposite, x as FinalEvidenceError, z as campaignSplitDigest } from "./campaign-evidence-
|
|
11
|
+
import { A as surfaceHashMatches, D as surfaceContentHash, E as renderSurfaceDiff, F as assertCampaignSplitIdentity, I as assertCompleteCampaign, L as campaignCoverage, O as surfaceDispatchRef, P as assertCampaignDesign, R as campaignScenarioIdentity, V as formatCoverageFailures, b as FinalEvidenceConflictError, f as campaignBreakdown, j as BackendIntegrityError, k as surfaceHash, m as campaignMeanCompositeOrNull, p as campaignMeanComposite, x as FinalEvidenceError, z as campaignSplitDigest } from "./campaign-evidence-DunzcJGv.js";
|
|
12
12
|
import { t as deepFreezeCanonicalJson } from "./deep-freeze-CurcOQg3.js";
|
|
13
|
-
import { M as fsCampaignStorage, h as isExternalTextCandidate, j as createRunCostLedger } from "./external-optimizer-subprocess-
|
|
13
|
+
import { M as fsCampaignStorage, h as isExternalTextCandidate, j as createRunCostLedger } from "./external-optimizer-subprocess-B5gdLRZv.js";
|
|
14
14
|
import { r as summarizeEvaluationUnits, t as defineEvaluationClaim } from "./claim-BPVuyHuy.js";
|
|
15
15
|
import { d as detectPersonalData, s as redactText, t as REDACTION_VERSION, u as detectCredential } from "./redact-mtkTiJVk.js";
|
|
16
16
|
import { t as detectRewardHacking } from "./reward-hacking-ByuETaIb.js";
|
|
17
|
-
import { t as assertProposalFindings } from "./proposal-findings-
|
|
18
|
-
import { i as runSearch, m as searchExpansionIndex, n as paretoFrontier, o as searchPolicyView, p as SEARCH_KERNEL_SOURCE, r as paretoFrontierWithCrowding, s as EXPANSION_OPERATORS, w as estimateNode } from "./pareto-
|
|
19
|
-
import { a as validateSearchLedgerEvent, d as searchNodeId, f as searchTaskSetDigest, i as replaySearchLedgerText, n as openSearchLedger, u as searchCellId } from "./search-ledger-
|
|
20
|
-
import { n as searchProposerView, t as renderSearchSummary } from "./search-summary-
|
|
17
|
+
import { t as assertProposalFindings } from "./proposal-findings-n-5WBbEx.js";
|
|
18
|
+
import { i as runSearch, m as searchExpansionIndex, n as paretoFrontier, o as searchPolicyView, p as SEARCH_KERNEL_SOURCE, r as paretoFrontierWithCrowding, s as EXPANSION_OPERATORS, w as estimateNode } from "./pareto-CTv8vozZ.js";
|
|
19
|
+
import { a as validateSearchLedgerEvent, d as searchNodeId, f as searchTaskSetDigest, i as replaySearchLedgerText, n as openSearchLedger, u as searchCellId } from "./search-ledger-ClpN4I3e.js";
|
|
20
|
+
import { n as searchProposerView, t as renderSearchSummary } from "./search-summary-CrBuvVnf.js";
|
|
21
21
|
import { i as stripFencedJson, n as isRecord } from "./json-BhdsJaOQ.js";
|
|
22
|
-
import { a as maximumChargeForLlmRequest, i as costReceiptFromLlmError, r as costReceiptFromLlm } from "./llm-client-
|
|
22
|
+
import { a as maximumChargeForLlmRequest, i as costReceiptFromLlmError, r as costReceiptFromLlm } from "./llm-client-_Y6ic-tf.js";
|
|
23
23
|
import { createHash } from "node:crypto";
|
|
24
24
|
import { writeFileSync } from "node:fs";
|
|
25
25
|
import { z } from "zod";
|
|
@@ -337,52 +337,41 @@ function hasLlmCall(value) {
|
|
|
337
337
|
* persisted cell result. `runCampaign` owns the schedule; this module owns
|
|
338
338
|
* everything that happens inside a single cell.
|
|
339
339
|
*/
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
340
|
+
/** A cached cell is reused only when its receipts still match the ledger; invalid cache entries need an explicit rerun. */
|
|
341
|
+
function reuseCachedCell(args, cachePath, stableCostTags) {
|
|
342
|
+
const cached = readCachedCell({
|
|
343
|
+
storage: args.storage,
|
|
344
|
+
cachePath,
|
|
345
|
+
cellId: args.slot.cellId,
|
|
346
|
+
manifestHash: args.manifestHash
|
|
347
|
+
});
|
|
348
|
+
if (cached.status === "miss" && cacheIssueRequiresExplicitRerun(cached.reason) && !args.opts.rerunInvalidCachedCells) throw invalidCachedCellsError([{
|
|
349
|
+
cellId: args.slot.cellId,
|
|
350
|
+
reason: cached.reason
|
|
351
|
+
}]);
|
|
352
|
+
if (cached.status === "hit" && (!cached.cell.error || args.opts.reuseFailedCells)) {
|
|
353
|
+
const receiptProblem = cachedCellReceiptProblem(cached.cell, args.costLedger, stableCostTags);
|
|
354
|
+
if (receiptProblem === void 0) {
|
|
355
|
+
const cell = withCurrentAgentModelEvidence(cached.cell, args.costLedger, stableCostTags);
|
|
356
|
+
enforceDispatchUsage(cell, args.opts.expectUsage ?? "warn");
|
|
357
|
+
return {
|
|
358
|
+
cell: {
|
|
359
|
+
...cell,
|
|
360
|
+
cached: true
|
|
361
|
+
},
|
|
362
|
+
artifactsByPath: {}
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
if (!args.opts.rerunInvalidCachedCells) throw invalidCachedCellsError([{
|
|
362
366
|
cellId: args.slot.cellId,
|
|
363
|
-
reason:
|
|
367
|
+
reason: "invalid-cost-receipts",
|
|
368
|
+
detail: receiptProblem
|
|
364
369
|
}]);
|
|
365
|
-
if (cached.status === "hit" && (!cached.cell.error || args.opts.reuseFailedCells)) {
|
|
366
|
-
const receiptProblem = cachedCellReceiptProblem(cached.cell, args.costLedger, stableCostTags);
|
|
367
|
-
if (receiptProblem === void 0) {
|
|
368
|
-
const cell = withCurrentAgentModelEvidence(cached.cell, args.costLedger, stableCostTags);
|
|
369
|
-
enforceDispatchUsage(cell, args.opts.expectUsage ?? "warn");
|
|
370
|
-
return {
|
|
371
|
-
cell: {
|
|
372
|
-
...cell,
|
|
373
|
-
cached: true
|
|
374
|
-
},
|
|
375
|
-
artifactsByPath: {}
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
if (!args.opts.rerunInvalidCachedCells) throw invalidCachedCellsError([{
|
|
379
|
-
cellId: args.slot.cellId,
|
|
380
|
-
reason: "invalid-cost-receipts",
|
|
381
|
-
detail: receiptProblem
|
|
382
|
-
}]);
|
|
383
|
-
}
|
|
384
370
|
}
|
|
385
|
-
|
|
371
|
+
}
|
|
372
|
+
/** The directories, writers, abort chain and dispatch context of one execution attempt. */
|
|
373
|
+
function openAttempt(args, cellDir, attemptCostTags) {
|
|
374
|
+
const { storage } = args;
|
|
386
375
|
const attempt = {
|
|
387
376
|
runAttemptId: args.runAttemptId,
|
|
388
377
|
number: args.attempt
|
|
@@ -407,7 +396,7 @@ async function executeCell(args) {
|
|
|
407
396
|
artifactsByPath[`${args.slot.cellId}/${attemptPrefix}/identity.json`] = identityPath;
|
|
408
397
|
storage.write(join(cellDir, "latest-attempt.json"), JSON.stringify(attempt));
|
|
409
398
|
const trace = args.buildTraceWriter(args.slot.cellId, traceDir);
|
|
410
|
-
|
|
399
|
+
const paid = { started: false };
|
|
411
400
|
const artifacts = {
|
|
412
401
|
async write(path, content) {
|
|
413
402
|
const fullPath = resolve(artifactDir, path);
|
|
@@ -422,8 +411,10 @@ async function executeCell(args) {
|
|
|
422
411
|
return artifacts.write(path, JSON.stringify(value, null, 2));
|
|
423
412
|
}
|
|
424
413
|
};
|
|
414
|
+
const cellAbort = new AbortController();
|
|
415
|
+
const onCampaignAbort = () => cellAbort.abort(args.signal.reason);
|
|
425
416
|
const cost = { async runPaidCall(input) {
|
|
426
|
-
|
|
417
|
+
paid.started = true;
|
|
427
418
|
const result = await args.costLedger.runPaidCall({
|
|
428
419
|
...input,
|
|
429
420
|
channel: input.channel ?? "agent",
|
|
@@ -439,25 +430,36 @@ async function executeCell(args) {
|
|
|
439
430
|
scenario: args.slot.scenario,
|
|
440
431
|
rep: args.slot.rep
|
|
441
432
|
});
|
|
442
|
-
const cellAbort = new AbortController();
|
|
443
|
-
const onCampaignAbort = () => cellAbort.abort(args.signal.reason);
|
|
444
433
|
if (args.signal.aborted) cellAbort.abort(args.signal.reason);
|
|
445
434
|
else args.signal.addEventListener("abort", onCampaignAbort, { once: true });
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
signal: cellAbort.signal,
|
|
435
|
+
return {
|
|
436
|
+
attempt,
|
|
437
|
+
attemptDir,
|
|
438
|
+
attemptPrefix,
|
|
439
|
+
artifactsByPath,
|
|
452
440
|
trace,
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
441
|
+
paid,
|
|
442
|
+
cellAbort,
|
|
443
|
+
onCampaignAbort,
|
|
444
|
+
ctx: {
|
|
445
|
+
cellId: args.slot.cellId,
|
|
446
|
+
runAttemptId: args.runAttemptId,
|
|
447
|
+
rep: args.slot.rep,
|
|
448
|
+
seed: args.slot.cellSeed,
|
|
449
|
+
signal: cellAbort.signal,
|
|
450
|
+
trace,
|
|
451
|
+
artifacts,
|
|
452
|
+
cost,
|
|
453
|
+
placement
|
|
454
|
+
}
|
|
456
455
|
};
|
|
456
|
+
}
|
|
457
|
+
/** Dispatch the scenario under the per-cell abort and the dispatch deadline. A failure is recorded, not thrown. */
|
|
458
|
+
async function dispatchCell(args, run) {
|
|
459
|
+
const { cellAbort, onCampaignAbort, ctx } = run;
|
|
457
460
|
let artifact;
|
|
458
461
|
let errorMessage;
|
|
459
462
|
let failure;
|
|
460
|
-
let fatalCellError;
|
|
461
463
|
let dispatched;
|
|
462
464
|
const timeoutMs = args.dispatchTimeoutMs;
|
|
463
465
|
let timeoutTimer;
|
|
@@ -500,29 +502,41 @@ async function executeCell(args) {
|
|
|
500
502
|
removeAbortListener();
|
|
501
503
|
args.signal.removeEventListener("abort", onCampaignAbort);
|
|
502
504
|
}
|
|
505
|
+
return {
|
|
506
|
+
artifact,
|
|
507
|
+
errorMessage,
|
|
508
|
+
failure,
|
|
509
|
+
dispatched
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
/** A dispatch that ignored cancellation, or paid calls that never settled, mean no trustworthy cell result exists. */
|
|
513
|
+
async function awaitCellShutdown(args, run, dispatched, costTags) {
|
|
514
|
+
const { trace, paid } = run;
|
|
503
515
|
if (dispatched) {
|
|
504
516
|
if (!await settlesWithin(dispatched, args.dispatchShutdownTimeoutMs)) {
|
|
505
517
|
await trace.flush();
|
|
506
518
|
throw new CostAccountingIncompleteError(`dispatch for cell '${args.slot.cellId}' ignored cancellation and did not stop within ${args.dispatchShutdownTimeoutMs}ms; no campaign result was produced`);
|
|
507
519
|
}
|
|
508
520
|
}
|
|
509
|
-
if (
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
})) {
|
|
522
|
-
await trace.flush();
|
|
523
|
-
throw new CostAccountingIncompleteError(`paid calls for cell '${args.slot.cellId}' did not settle within ${args.dispatchShutdownTimeoutMs}ms; no campaign result was produced`);
|
|
521
|
+
if (!paid.started) return;
|
|
522
|
+
if (typeof args.costLedger.waitForIdle !== "function") {
|
|
523
|
+
await trace.flush();
|
|
524
|
+
throw new CostAccountingIncompleteError(`cost ledger for cell '${args.slot.cellId}' cannot prove that paid calls stopped`);
|
|
525
|
+
}
|
|
526
|
+
if (!await args.costLedger.waitForIdle({
|
|
527
|
+
timeoutMs: args.dispatchShutdownTimeoutMs,
|
|
528
|
+
filter: {
|
|
529
|
+
channel: "agent",
|
|
530
|
+
phase: args.costPhase,
|
|
531
|
+
tags: costTags
|
|
524
532
|
}
|
|
533
|
+
})) {
|
|
534
|
+
await trace.flush();
|
|
535
|
+
throw new CostAccountingIncompleteError(`paid calls for cell '${args.slot.cellId}' did not settle within ${args.dispatchShutdownTimeoutMs}ms; no campaign result was produced`);
|
|
525
536
|
}
|
|
537
|
+
}
|
|
538
|
+
/** The agent spend of this attempt: cost, token usage and the models that served it. */
|
|
539
|
+
function measureAgentUsage(args, costTags) {
|
|
526
540
|
const agentReceipts = args.costLedger.list({
|
|
527
541
|
channel: "agent",
|
|
528
542
|
tags: costTags
|
|
@@ -531,29 +545,29 @@ async function executeCell(args) {
|
|
|
531
545
|
channel: "agent",
|
|
532
546
|
tags: costTags
|
|
533
547
|
});
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
artifact,
|
|
546
|
-
error: errorMessage,
|
|
547
|
-
costUsd: agentCost.totalCostUsd,
|
|
548
|
-
tokenUsage
|
|
548
|
+
return {
|
|
549
|
+
agentCost,
|
|
550
|
+
tokenUsage: {
|
|
551
|
+
input: agentCost.inputTokens,
|
|
552
|
+
output: agentCost.outputTokens,
|
|
553
|
+
...agentCost.usageComplete ? {} : { tokensKnown: false },
|
|
554
|
+
...agentCost.reasoningTokens !== void 0 && agentCost.reasoningTokens > 0 ? { reasoning: agentCost.reasoningTokens } : {},
|
|
555
|
+
...agentCost.cachedTokens > 0 ? { cached: agentCost.cachedTokens } : {},
|
|
556
|
+
...agentCost.cacheWriteTokens !== void 0 && agentCost.cacheWriteTokens > 0 ? { cacheWrite: agentCost.cacheWriteTokens } : {}
|
|
557
|
+
},
|
|
558
|
+
agentModelEvidence: modelEvidenceFromReceipts(agentReceipts)
|
|
549
559
|
};
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Run judges (only if we have an artifact). A judge that throws invalidates
|
|
563
|
+
* the cell — recorded as `error`, NOT folded into a fake composite:0 (a fake
|
|
564
|
+
* zero is indistinguishable from a real zero and poisons every aggregate).
|
|
565
|
+
*/
|
|
566
|
+
async function judgeArtifact(args, artifact, attemptCostTags) {
|
|
556
567
|
const judgeScores = {};
|
|
568
|
+
let errorMessage;
|
|
569
|
+
let failure;
|
|
570
|
+
let fatalCellError;
|
|
557
571
|
if (artifact !== void 0) for (const judge of args.opts.judges ?? []) {
|
|
558
572
|
if (judge.appliesTo && !judge.appliesTo(args.slot.scenario)) continue;
|
|
559
573
|
try {
|
|
@@ -577,6 +591,79 @@ async function executeCell(args) {
|
|
|
577
591
|
break;
|
|
578
592
|
}
|
|
579
593
|
}
|
|
594
|
+
return {
|
|
595
|
+
judgeScores,
|
|
596
|
+
errorMessage,
|
|
597
|
+
failure,
|
|
598
|
+
fatalCellError
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
/** Write the failure receipt and decide whether `cellRetry` dispatches this slot again. */
|
|
602
|
+
function recordCellFailure(args, run, failure, cell, costTags, fatalCellError) {
|
|
603
|
+
const { attemptDir, attemptPrefix, artifactsByPath } = run;
|
|
604
|
+
const receipt = {
|
|
605
|
+
schemaVersion: 1,
|
|
606
|
+
runAttemptId: args.runAttemptId,
|
|
607
|
+
recordedAt: args.now().toISOString(),
|
|
608
|
+
failure: {
|
|
609
|
+
stage: failure.stage,
|
|
610
|
+
...failure.judge ? { judge: failure.judge } : {},
|
|
611
|
+
error: serializeCellError(failure.cause)
|
|
612
|
+
},
|
|
613
|
+
cell,
|
|
614
|
+
cost: args.costLedger.summary({
|
|
615
|
+
phase: args.costPhase,
|
|
616
|
+
tags: costTags
|
|
617
|
+
})
|
|
618
|
+
};
|
|
619
|
+
const retry = args.cellRetry !== void 0 && args.attempt < args.cellRetry.attempts && !args.signal.aborted && fatalCellError === void 0 && args.cellRetry.retryable(receipt.failure);
|
|
620
|
+
const failurePath = join(attemptDir, "failure-receipt.json");
|
|
621
|
+
args.storage.write(failurePath, JSON.stringify(receipt, null, 2));
|
|
622
|
+
artifactsByPath[`${args.slot.cellId}/${attemptPrefix}/failure-receipt.json`] = failurePath;
|
|
623
|
+
if (!retry) args.onFailure?.(failure);
|
|
624
|
+
return retry;
|
|
625
|
+
}
|
|
626
|
+
async function executeCell(args) {
|
|
627
|
+
const storage = args.storage;
|
|
628
|
+
const cellDir = cellDirectory(args.opts.runDir, args.slot.cellId);
|
|
629
|
+
storage.ensureDir(cellDir);
|
|
630
|
+
const stableCostTags = stableCostTagsFor(args.opts, args.slot);
|
|
631
|
+
const costTags = {
|
|
632
|
+
...stableCostTags,
|
|
633
|
+
runAttemptId: args.runAttemptId
|
|
634
|
+
};
|
|
635
|
+
const attemptCostTags = {
|
|
636
|
+
...costTags,
|
|
637
|
+
attemptNumber: String(args.attempt)
|
|
638
|
+
};
|
|
639
|
+
const cachePath = join(cellDir, "cached-result.json");
|
|
640
|
+
if (args.resumable) {
|
|
641
|
+
const reused = reuseCachedCell(args, cachePath, stableCostTags);
|
|
642
|
+
if (reused) return reused;
|
|
643
|
+
}
|
|
644
|
+
const startMs = Date.now();
|
|
645
|
+
const run = openAttempt(args, cellDir, attemptCostTags);
|
|
646
|
+
const { attempt, attemptDir, attemptPrefix, artifactsByPath, trace } = run;
|
|
647
|
+
const dispatch = await dispatchCell(args, run);
|
|
648
|
+
await awaitCellShutdown(args, run, dispatch.dispatched, costTags);
|
|
649
|
+
const { artifact } = dispatch;
|
|
650
|
+
const { agentCost, tokenUsage, agentModelEvidence } = measureAgentUsage(args, costTags);
|
|
651
|
+
try {
|
|
652
|
+
enforceDispatchUsage({
|
|
653
|
+
cellId: args.slot.cellId,
|
|
654
|
+
artifact,
|
|
655
|
+
error: dispatch.errorMessage,
|
|
656
|
+
costUsd: agentCost.totalCostUsd,
|
|
657
|
+
tokenUsage
|
|
658
|
+
}, args.opts.expectUsage ?? "warn");
|
|
659
|
+
} catch (error) {
|
|
660
|
+
await trace.flush();
|
|
661
|
+
throw error;
|
|
662
|
+
}
|
|
663
|
+
const judged = await judgeArtifact(args, artifact, attemptCostTags);
|
|
664
|
+
const failure = judged.failure ?? dispatch.failure;
|
|
665
|
+
const errorMessage = judged.failure ? judged.errorMessage : dispatch.errorMessage;
|
|
666
|
+
const { judgeScores, fatalCellError } = judged;
|
|
580
667
|
if (failure) await waitForFailedCellCostSettlement({
|
|
581
668
|
costLedger: args.costLedger,
|
|
582
669
|
costPhase: args.costPhase,
|
|
@@ -606,29 +693,7 @@ async function executeCell(args) {
|
|
|
606
693
|
...failure?.judge ? { errorJudge: failure.judge } : {},
|
|
607
694
|
error: errorMessage
|
|
608
695
|
};
|
|
609
|
-
|
|
610
|
-
if (failure) {
|
|
611
|
-
const receipt = {
|
|
612
|
-
schemaVersion: 1,
|
|
613
|
-
runAttemptId: args.runAttemptId,
|
|
614
|
-
recordedAt: args.now().toISOString(),
|
|
615
|
-
failure: {
|
|
616
|
-
stage: failure.stage,
|
|
617
|
-
...failure.judge ? { judge: failure.judge } : {},
|
|
618
|
-
error: serializeCellError(failure.cause)
|
|
619
|
-
},
|
|
620
|
-
cell,
|
|
621
|
-
cost: args.costLedger.summary({
|
|
622
|
-
phase: args.costPhase,
|
|
623
|
-
tags: costTags
|
|
624
|
-
})
|
|
625
|
-
};
|
|
626
|
-
retry = args.cellRetry !== void 0 && args.attempt < args.cellRetry.attempts && !args.signal.aborted && fatalCellError === void 0 && args.cellRetry.retryable(receipt.failure);
|
|
627
|
-
const failurePath = join(attemptDir, "failure-receipt.json");
|
|
628
|
-
storage.write(failurePath, JSON.stringify(receipt, null, 2));
|
|
629
|
-
artifactsByPath[`${args.slot.cellId}/${attemptPrefix}/failure-receipt.json`] = failurePath;
|
|
630
|
-
if (!retry) args.onFailure?.(failure);
|
|
631
|
-
}
|
|
696
|
+
const retry = failure ? recordCellFailure(args, run, failure, cell, costTags, fatalCellError) : false;
|
|
632
697
|
await trace.flush();
|
|
633
698
|
const resultPath = join(attemptDir, "result.json");
|
|
634
699
|
storage.write(resultPath, JSON.stringify(cell));
|
|
@@ -1890,261 +1955,269 @@ function excerptAt(source, at, needleLength) {
|
|
|
1890
1955
|
return (start > 0 ? "…" : "") + source.slice(start, end) + (end < source.length ? "…" : "");
|
|
1891
1956
|
}
|
|
1892
1957
|
//#endregion
|
|
1893
|
-
//#region src/campaign/gates/default-production-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
const
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1958
|
+
//#region src/campaign/gates/default-production-checks.ts
|
|
1959
|
+
function newFindings() {
|
|
1960
|
+
const reasons = [];
|
|
1961
|
+
const contributing = [];
|
|
1962
|
+
const requiredUnavailable = /* @__PURE__ */ new Set();
|
|
1963
|
+
const unavailable = (name, required, reason, detail = {}) => {
|
|
1964
|
+
contributing.push({
|
|
1965
|
+
name,
|
|
1966
|
+
status: "not_evaluated",
|
|
1967
|
+
detail: {
|
|
1968
|
+
reason,
|
|
1969
|
+
required,
|
|
1970
|
+
...detail
|
|
1971
|
+
}
|
|
1972
|
+
});
|
|
1973
|
+
if (required) {
|
|
1974
|
+
requiredUnavailable.add(name);
|
|
1975
|
+
reasons.push(`${name}: ${reason}`);
|
|
1976
|
+
}
|
|
1977
|
+
};
|
|
1911
1978
|
return {
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
delta
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
deltaMedianDiagnostic: sig.medianBootstrap.median,
|
|
1963
|
-
deltaMedian: sig.medianBootstrap.median,
|
|
1964
|
-
tieFraction: sig.tieFraction,
|
|
1965
|
-
ciLow: dec.low,
|
|
1966
|
-
ciHigh: dec.high,
|
|
1967
|
-
bootstrapCiLow: sig.bootstrap.low,
|
|
1968
|
-
bootstrapCiHigh: sig.bootstrap.high,
|
|
1969
|
-
confidence: dec.confidence,
|
|
1970
|
-
deltaThreshold,
|
|
1971
|
-
fewRuns: sig.fewRuns
|
|
1972
|
-
}
|
|
1973
|
-
});
|
|
1974
|
-
if (sig.fewRuns) requiredUnavailable.add("heldout-significance");
|
|
1975
|
-
if (!heldoutPass) {
|
|
1976
|
-
const tieNote = sig.tieFraction >= .4 ? `; ${(sig.tieFraction * 100).toFixed(0)}% tied observation units` : "";
|
|
1977
|
-
const ci = `${(dec.confidence * 100).toFixed(0)}% CI [${dec.low.toFixed(3)}, ${dec.high.toFixed(3)}]`;
|
|
1978
|
-
reasons.push(sig.fewRuns ? `held-out: only ${sig.n} paired observation units (< ${sig.minimumRequired}) — too few to claim significance` : dec.indeterminate ? `held-out: ${dec.indeterminateCause}, so the paired CI is ${ci} and carries no direction — it cannot clear threshold ${deltaThreshold} on evidence${tieNote}` : dec.exactTestVetoes ? `held-out: McNemar exact p=${dec.mcnemar?.pValue.toExponential(2)} does not reject at α=${(1 - dec.confidence).toFixed(4)} (${dec.label} Δ ${delta.toFixed(3)}, ${ci}${tieNote})` : dec.method === "exact-sign" ? `held-out: exact one-sided sign test p=${dec.pValue} does not reject at α=${((1 - dec.confidence) / 2).toFixed(4)} (${dec.label} Δ ${delta.toFixed(3)}, diagnostic ${ci}${tieNote})` : `held-out CI.low ${dec.low.toFixed(3)} ≤ threshold ${deltaThreshold} (${dec.label} Δ ${delta.toFixed(3)}, ${ci}${tieNote})`);
|
|
1979
|
-
}
|
|
1979
|
+
reasons,
|
|
1980
|
+
contributing,
|
|
1981
|
+
requiredUnavailable,
|
|
1982
|
+
unavailable
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1985
|
+
/** Held-out significance of the candidate over the baseline, paired by cell before any averaging. */
|
|
1986
|
+
function checkHeldout(g, cfg, ctx) {
|
|
1987
|
+
const { reasons, contributing, requiredUnavailable, unavailable } = g;
|
|
1988
|
+
const { deltaThreshold, confidence, resamples, seed, minProductiveRuns, heldoutStatistic, scenarioIds, independentUnitByScenarioId } = cfg;
|
|
1989
|
+
let delta;
|
|
1990
|
+
if (!ctx.baselineJudgeScores) unavailable("heldout-significance", true, "baselineJudgeScores is required for a held-out comparison");
|
|
1991
|
+
else {
|
|
1992
|
+
const sig = heldoutSignificance(pairHoldout(ctx.judgeScores, ctx.baselineJudgeScores, scenarioIds, (s) => s.composite), {
|
|
1993
|
+
deltaThreshold,
|
|
1994
|
+
minProductiveRuns,
|
|
1995
|
+
confidence,
|
|
1996
|
+
resamples,
|
|
1997
|
+
seed,
|
|
1998
|
+
statistic: heldoutStatistic,
|
|
1999
|
+
independentUnitByScenarioId
|
|
2000
|
+
});
|
|
2001
|
+
const dec = sig.decision;
|
|
2002
|
+
delta = dec.delta;
|
|
2003
|
+
const heldoutPass = sig.significant;
|
|
2004
|
+
contributing.push({
|
|
2005
|
+
name: "heldout-significance",
|
|
2006
|
+
status: sig.fewRuns ? "not_evaluated" : heldoutPass ? "pass" : "fail",
|
|
2007
|
+
detail: {
|
|
2008
|
+
n: sig.n,
|
|
2009
|
+
pairedCellN: sig.pairedCellN,
|
|
2010
|
+
observationUnit: sig.observationUnit,
|
|
2011
|
+
unitIds: sig.unitIds,
|
|
2012
|
+
delta,
|
|
2013
|
+
decisionStatistic: sig.decisionStatistic,
|
|
2014
|
+
decisionMethod: sig.decisionMethod,
|
|
2015
|
+
binaryScale: dec.binaryScale,
|
|
2016
|
+
mcnemar: dec.mcnemar,
|
|
2017
|
+
indeterminate: dec.indeterminate,
|
|
2018
|
+
deltaMean: sig.bootstrap.mean,
|
|
2019
|
+
deltaMedianDiagnostic: sig.medianBootstrap.median,
|
|
2020
|
+
deltaMedian: sig.medianBootstrap.median,
|
|
2021
|
+
tieFraction: sig.tieFraction,
|
|
2022
|
+
ciLow: dec.low,
|
|
2023
|
+
ciHigh: dec.high,
|
|
2024
|
+
bootstrapCiLow: sig.bootstrap.low,
|
|
2025
|
+
bootstrapCiHigh: sig.bootstrap.high,
|
|
2026
|
+
confidence: dec.confidence,
|
|
2027
|
+
deltaThreshold,
|
|
2028
|
+
fewRuns: sig.fewRuns
|
|
1980
2029
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2030
|
+
});
|
|
2031
|
+
if (sig.fewRuns) requiredUnavailable.add("heldout-significance");
|
|
2032
|
+
if (!heldoutPass) {
|
|
2033
|
+
const tieNote = sig.tieFraction >= .4 ? `; ${(sig.tieFraction * 100).toFixed(0)}% tied observation units` : "";
|
|
2034
|
+
const ci = `${(dec.confidence * 100).toFixed(0)}% CI [${dec.low.toFixed(3)}, ${dec.high.toFixed(3)}]`;
|
|
2035
|
+
reasons.push(sig.fewRuns ? `held-out: only ${sig.n} paired observation units (< ${sig.minimumRequired}) — too few to claim significance` : dec.indeterminate ? `held-out: ${dec.indeterminateCause}, so the paired CI is ${ci} and carries no direction — it cannot clear threshold ${deltaThreshold} on evidence${tieNote}` : dec.exactTestVetoes ? `held-out: McNemar exact p=${dec.mcnemar?.pValue.toExponential(2)} does not reject at α=${(1 - dec.confidence).toFixed(4)} (${dec.label} Δ ${delta.toFixed(3)}, ${ci}${tieNote})` : dec.method === "exact-sign" ? `held-out: exact one-sided sign test p=${dec.pValue} does not reject at α=${((1 - dec.confidence) / 2).toFixed(4)} (${dec.label} Δ ${delta.toFixed(3)}, diagnostic ${ci}${tieNote})` : `held-out CI.low ${dec.low.toFixed(3)} ≤ threshold ${deltaThreshold} (${dec.label} Δ ${delta.toFixed(3)}, ${ci}${tieNote})`);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
return delta;
|
|
2039
|
+
}
|
|
2040
|
+
/** Anti-Goodhart guard: a net composite gain must not hide a regression on a critical dimension. */
|
|
2041
|
+
function checkDimensions(g, cfg, ctx) {
|
|
2042
|
+
const { reasons, contributing, requiredUnavailable, unavailable } = g;
|
|
2043
|
+
const { options, confidence, resamples, seed, minProductiveRuns, explicitlyRequired, scenarioIds, independentUnitByScenarioId } = cfg;
|
|
2044
|
+
const dimensionsProvided = options.criticalDimensions !== void 0;
|
|
2045
|
+
const criticalDimensions = [...new Set(options.criticalDimensions ?? [])];
|
|
2046
|
+
const dimensionsRequired = dimensionsProvided || explicitlyRequired.has("dimension-regression");
|
|
2047
|
+
if (!dimensionsProvided) unavailable("dimension-regression", dimensionsRequired, "criticalDimensions is not configured");
|
|
2048
|
+
else if (criticalDimensions.length === 0) unavailable("dimension-regression", true, "criticalDimensions must contain at least one dimension");
|
|
2049
|
+
else if (!ctx.baselineJudgeScores) unavailable("dimension-regression", true, "baselineJudgeScores is required to measure dimension regressions", { guarded: criticalDimensions });
|
|
2050
|
+
else {
|
|
2051
|
+
const dimRegs = dimensionRegressions(ctx.judgeScores, ctx.baselineJudgeScores, scenarioIds, criticalDimensions, {
|
|
2052
|
+
tolerance: options.regressionTolerance,
|
|
2053
|
+
confidence,
|
|
2054
|
+
resamples,
|
|
2055
|
+
seed,
|
|
2056
|
+
independentUnitByScenarioId,
|
|
2057
|
+
minProductiveRuns
|
|
2058
|
+
});
|
|
2059
|
+
const measured = new Set(dimRegs.map((result) => result.dimension));
|
|
2060
|
+
const missingDimensions = criticalDimensions.filter((dimension) => !measured.has(dimension));
|
|
2061
|
+
const regressed = dimRegs.filter((result) => result.regressed);
|
|
2062
|
+
const incompleteDimensions = dimRegs.filter((result) => result.fewRuns || result.missingCellIds.length > 0 || result.missingScenarioIds.length > 0);
|
|
2063
|
+
const dimensionStatus = regressed.length > 0 ? "fail" : missingDimensions.length > 0 || incompleteDimensions.length > 0 ? "not_evaluated" : "pass";
|
|
2064
|
+
contributing.push({
|
|
2065
|
+
name: "dimension-regression",
|
|
2066
|
+
status: dimensionStatus,
|
|
2067
|
+
detail: {
|
|
2068
|
+
guarded: criticalDimensions,
|
|
2069
|
+
missingDimensions,
|
|
2070
|
+
incompleteDimensions: incompleteDimensions.map((result) => result.dimension),
|
|
2071
|
+
regressions: dimRegs.map((result) => ({
|
|
2072
|
+
dimension: result.dimension,
|
|
2073
|
+
ciLow: result.ci.low,
|
|
2074
|
+
ciHigh: result.ci.high,
|
|
2075
|
+
decisionStatistic: result.decisionStatistic,
|
|
2076
|
+
indeterminate: result.indeterminate,
|
|
2077
|
+
bootstrapCiLow: result.bootstrap.low,
|
|
2078
|
+
median: result.bootstrap.median,
|
|
2079
|
+
tolerance: result.tolerance,
|
|
2080
|
+
n: result.n,
|
|
2081
|
+
pairedCellN: result.pairedCellN,
|
|
2082
|
+
observationUnit: result.observationUnit,
|
|
2083
|
+
minimumRequired: result.minimumRequired,
|
|
2084
|
+
fewRuns: result.fewRuns,
|
|
2085
|
+
missingCellIds: result.missingCellIds,
|
|
2086
|
+
missingScenarioIds: result.missingScenarioIds,
|
|
2087
|
+
regressed: result.regressed
|
|
2088
|
+
}))
|
|
2037
2089
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2090
|
+
});
|
|
2091
|
+
if (missingDimensions.length > 0) {
|
|
2092
|
+
requiredUnavailable.add("dimension-regression");
|
|
2093
|
+
reasons.push(`critical dimension(s) were not scored: ${missingDimensions.join(", ")}`);
|
|
2094
|
+
}
|
|
2095
|
+
if (incompleteDimensions.length > 0) {
|
|
2096
|
+
requiredUnavailable.add("dimension-regression");
|
|
2097
|
+
reasons.push(`critical dimension evidence is incomplete: ${incompleteDimensions.map((result) => `${result.dimension} has ${result.n} paired observation units (minimum ${result.minimumRequired}), ${result.missingCellIds.length} unscored cells, ${result.missingScenarioIds.length} unscored scenarios`).join("; ")}`);
|
|
2098
|
+
}
|
|
2099
|
+
if (regressed.length > 0) reasons.push(`critical dimension(s) regressed: ${regressed.map((result) => result.bootstrap.low < -result.tolerance ? `${result.dimension} bootstrap CI.low ${result.bootstrap.low.toFixed(3)} < -${result.tolerance}` : `${result.dimension} paired test supports a drop greater than ${result.tolerance}`).join("; ")}`);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
/** Total spend of the improvement run against `budgetUsd`, from complete cost accounting only. */
|
|
2103
|
+
function checkBudget(g, cfg, ctx) {
|
|
2104
|
+
const { reasons, contributing, requiredUnavailable, unavailable } = g;
|
|
2105
|
+
const { options, explicitlyRequired } = cfg;
|
|
2106
|
+
const budgetUsd = options.budgetUsd;
|
|
2107
|
+
const budgetConfigured = budgetUsd !== void 0;
|
|
2108
|
+
const budgetRequired = budgetConfigured || explicitlyRequired.has("budget");
|
|
2109
|
+
if (!budgetConfigured) unavailable("budget", budgetRequired, "budgetUsd is not configured");
|
|
2110
|
+
else if (!ctx.costLedger) unavailable("budget", true, "costLedger is required to measure complete run spend", { budgetUsd });
|
|
2111
|
+
else {
|
|
2112
|
+
const cost = ctx.costLedger.summary();
|
|
2113
|
+
const accountingComplete = cost.accountingComplete && cost.pendingCalls === 0 && cost.unresolvedCalls === 0;
|
|
2114
|
+
const budgetPass = cost.totalCostUsd <= budgetUsd;
|
|
2115
|
+
contributing.push({
|
|
2116
|
+
name: "budget",
|
|
2117
|
+
status: !accountingComplete ? "not_evaluated" : budgetPass ? "pass" : "fail",
|
|
2118
|
+
detail: {
|
|
2119
|
+
totalCostUsd: cost.totalCostUsd,
|
|
2120
|
+
budgetUsd,
|
|
2121
|
+
accountingComplete,
|
|
2122
|
+
pendingCalls: cost.pendingCalls,
|
|
2123
|
+
unresolvedCalls: cost.unresolvedCalls
|
|
2062
2124
|
}
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2125
|
+
});
|
|
2126
|
+
if (!accountingComplete) {
|
|
2127
|
+
requiredUnavailable.add("budget");
|
|
2128
|
+
reasons.push("budget: cost accounting is incomplete");
|
|
2129
|
+
} else if (!budgetPass) reasons.push(`spend ${cost.totalCostUsd.toFixed(2)} > budget ${budgetUsd}`);
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
/** Static red-team screening of the candidate artifacts. */
|
|
2133
|
+
function checkRedTeam(g, cfg, ctx) {
|
|
2134
|
+
const { reasons, contributing, requiredUnavailable, unavailable } = g;
|
|
2135
|
+
const { options, explicitlyRequired } = cfg;
|
|
2136
|
+
const redTeamRequired = options.redTeamBattery !== void 0 || explicitlyRequired.has("red-team");
|
|
2137
|
+
if (!options.redTeamBattery) unavailable("red-team", redTeamRequired, "redTeamBattery is not configured");
|
|
2138
|
+
else if (options.redTeamBattery.length === 0) unavailable("red-team", true, "redTeamBattery must contain at least one case");
|
|
2139
|
+
else {
|
|
2140
|
+
const redTeam = probeRedTeam(ctx.candidateArtifacts, options.redTeamBattery);
|
|
2141
|
+
const incomplete = redTeam.unsupportedCases.length > 0 || redTeam.unscoredArtifacts.length > 0 || redTeam.evaluatedCases === 0;
|
|
2142
|
+
const redTeamStatus = redTeam.findings.length > 0 ? "fail" : incomplete ? "not_evaluated" : "pass";
|
|
2143
|
+
contributing.push({
|
|
2144
|
+
name: "red-team",
|
|
2145
|
+
status: redTeamStatus,
|
|
2146
|
+
detail: {
|
|
2147
|
+
evaluatedCases: redTeam.evaluatedCases,
|
|
2148
|
+
unsupportedCases: redTeam.unsupportedCases,
|
|
2149
|
+
unscoredArtifacts: redTeam.unscoredArtifacts,
|
|
2150
|
+
failures: redTeam.findings.length,
|
|
2151
|
+
sample: redTeam.findings.slice(0, 3)
|
|
2086
2152
|
}
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2153
|
+
});
|
|
2154
|
+
if (incomplete) requiredUnavailable.add("red-team");
|
|
2155
|
+
if (redTeam.unsupportedCases.length > 0) reasons.push(`red-team: static artifact screening cannot evaluate case(s): ${redTeam.unsupportedCases.join(", ")}`);
|
|
2156
|
+
if (redTeam.unscoredArtifacts.length > 0) reasons.push(`red-team: no text could be extracted from artifact(s): ${redTeam.unscoredArtifacts.join(", ")}`);
|
|
2157
|
+
if (redTeam.evaluatedCases === 0) reasons.push("red-team: no artifact/case pair was evaluated");
|
|
2158
|
+
if (redTeam.findings.length > 0) reasons.push(`red-team probe failed (${redTeam.findings.length} findings)`);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
/** Reward-hacking detector over the run-history window. */
|
|
2162
|
+
function checkRewardHacking(g, cfg) {
|
|
2163
|
+
const { reasons, contributing, unavailable } = g;
|
|
2164
|
+
const { options, explicitlyRequired } = cfg;
|
|
2165
|
+
const rewardHacking = options.rewardHacking;
|
|
2166
|
+
const rewardHackingConfigured = rewardHacking !== void 0;
|
|
2167
|
+
const rewardHackingRequired = rewardHackingConfigured || explicitlyRequired.has("reward-hacking");
|
|
2168
|
+
if (!rewardHackingConfigured) unavailable("reward-hacking", rewardHackingRequired, "rewardHacking is not configured");
|
|
2169
|
+
else if (!options.recentRuns) unavailable("reward-hacking", rewardHackingRequired, "recentRuns is not configured");
|
|
2170
|
+
else if (options.recentRuns.length < 10) unavailable("reward-hacking", rewardHackingRequired, `recentRuns has ${options.recentRuns.length} record(s); at least 10 are required`);
|
|
2171
|
+
else {
|
|
2172
|
+
const rewardHackingReport = detectRewardHacking({
|
|
2173
|
+
runs: options.recentRuns,
|
|
2174
|
+
...rewardHacking
|
|
2175
|
+
});
|
|
2176
|
+
if (!rewardHackingReport.evaluatedSignals.includes("reward_divergence")) unavailable("reward-hacking", true, "independent proxy/truth evidence is insufficient to evaluate reward divergence", { report: rewardHackingReport });
|
|
2177
|
+
else {
|
|
2178
|
+
const gamingThreshold = rewardHacking.thresholds?.gaming ?? .6;
|
|
2179
|
+
const gamingFindings = rewardHackingReport.findings.filter((finding) => finding.severity >= gamingThreshold);
|
|
2180
|
+
const rewardHackingPass = gamingFindings.length === 0 && rewardHackingReport.verdict !== "gaming";
|
|
2181
|
+
contributing.push({
|
|
2182
|
+
name: "reward-hacking",
|
|
2183
|
+
status: rewardHackingPass ? "pass" : "fail",
|
|
2184
|
+
detail: {
|
|
2185
|
+
report: rewardHackingReport,
|
|
2186
|
+
gamingFindingCount: gamingFindings.length
|
|
2112
2187
|
}
|
|
2113
|
-
}
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2188
|
+
});
|
|
2189
|
+
if (!rewardHackingPass) reasons.push(`reward-hacking detector flagged ${gamingFindings.length} gaming-severity findings (verdict=${rewardHackingReport.verdict})`);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
/** Canary checks over the run history. */
|
|
2194
|
+
function checkCanary(g, cfg) {
|
|
2195
|
+
const { reasons, contributing, unavailable } = g;
|
|
2196
|
+
const { options, explicitlyRequired } = cfg;
|
|
2197
|
+
const canary = options.canary;
|
|
2198
|
+
const canaryConfigured = canary !== void 0;
|
|
2199
|
+
const canaryRequired = canaryConfigured || explicitlyRequired.has("canary");
|
|
2200
|
+
if (!canaryConfigured && !canaryRequired) unavailable("canary", false, "canary is not configured");
|
|
2201
|
+
else if (!options.recentRuns) unavailable("canary", canaryRequired, "recentRuns is not configured");
|
|
2202
|
+
else {
|
|
2203
|
+
const canaryReport = runCanaries(options.recentRuns, canary ?? {});
|
|
2204
|
+
const incomplete = canaryReport.evaluations.filter((evaluation) => evaluation.status === "not_evaluated");
|
|
2205
|
+
if (incomplete.length > 0) unavailable("canary", true, `insufficient evidence for: ${incomplete.map((evaluation) => evaluation.kind).join(", ")}`, { report: canaryReport });
|
|
2206
|
+
else {
|
|
2207
|
+
const errorAlerts = canaryReport.alerts.filter((alert) => alert.severity === "error");
|
|
2208
|
+
const canaryPass = errorAlerts.length === 0;
|
|
2209
|
+
contributing.push({
|
|
2210
|
+
name: "canary",
|
|
2211
|
+
status: canaryPass ? "pass" : "fail",
|
|
2212
|
+
detail: {
|
|
2213
|
+
totalAlerts: canaryReport.alerts.length,
|
|
2214
|
+
errorAlerts: errorAlerts.length,
|
|
2215
|
+
report: canaryReport
|
|
2136
2216
|
}
|
|
2137
|
-
}
|
|
2138
|
-
|
|
2139
|
-
const notEvaluated = contributing.filter((check) => check.status === "not_evaluated").map((check) => check.name);
|
|
2140
|
-
return {
|
|
2141
|
-
decision,
|
|
2142
|
-
reasons: reasons.length > 0 ? reasons : notEvaluated.length > 0 ? [`evaluated checks passed; not evaluated: ${notEvaluated.join(", ")}`] : ["all checks passed"],
|
|
2143
|
-
contributingGates: contributing,
|
|
2144
|
-
delta
|
|
2145
|
-
};
|
|
2217
|
+
});
|
|
2218
|
+
if (!canaryPass) reasons.push(`canary error alerts: ${errorAlerts.length}`);
|
|
2146
2219
|
}
|
|
2147
|
-
}
|
|
2220
|
+
}
|
|
2148
2221
|
}
|
|
2149
2222
|
function probeRedTeam(artifacts, battery) {
|
|
2150
2223
|
const supportedCases = battery.filter((testCase) => testCase.payload.expected === "ignore" && !testCase.payload.forbiddenTools?.length);
|
|
@@ -2185,6 +2258,62 @@ function extractText(artifact) {
|
|
|
2185
2258
|
}
|
|
2186
2259
|
}
|
|
2187
2260
|
//#endregion
|
|
2261
|
+
//#region src/campaign/gates/default-production-gate.ts
|
|
2262
|
+
/**
|
|
2263
|
+
* Opinionated production gate composing held-out significance, red-team, reward-hacking, and canary checks into a single `Gate.decide` decision.
|
|
2264
|
+
*/
|
|
2265
|
+
function defaultProductionGate(options) {
|
|
2266
|
+
const deltaThreshold = options.deltaThreshold ?? 0;
|
|
2267
|
+
const confidence = options.confidence ?? .95;
|
|
2268
|
+
const resamples = options.bootstrapResamples ?? 2e3;
|
|
2269
|
+
const seed = options.bootstrapSeed ?? 1337;
|
|
2270
|
+
const minProductiveRuns = options.minProductiveRuns ?? 3;
|
|
2271
|
+
const heldoutStatistic = options.heldoutStatistic ?? "mean";
|
|
2272
|
+
const explicitlyRequired = new Set(options.requiredChecks ?? []);
|
|
2273
|
+
const scenarioIds = new Set(options.holdoutScenarios.map((scenario) => scenario.id));
|
|
2274
|
+
const independentUnitByScenarioId = options.independentUnitByScenarioId === void 0 ? void 0 : new Map(options.independentUnitByScenarioId);
|
|
2275
|
+
if (independentUnitByScenarioId !== void 0) for (const id of scenarioIds) {
|
|
2276
|
+
const unit = independentUnitByScenarioId.get(id);
|
|
2277
|
+
if (typeof unit !== "string" || unit.length === 0 || unit.trim() !== unit) throw new Error(`defaultProductionGate: missing independent unit for holdout scenario '${id}'`);
|
|
2278
|
+
}
|
|
2279
|
+
const cfg = {
|
|
2280
|
+
options,
|
|
2281
|
+
deltaThreshold,
|
|
2282
|
+
confidence,
|
|
2283
|
+
resamples,
|
|
2284
|
+
seed,
|
|
2285
|
+
minProductiveRuns,
|
|
2286
|
+
heldoutStatistic,
|
|
2287
|
+
explicitlyRequired,
|
|
2288
|
+
scenarioIds,
|
|
2289
|
+
independentUnitByScenarioId
|
|
2290
|
+
};
|
|
2291
|
+
return {
|
|
2292
|
+
name: "defaultProductionGate",
|
|
2293
|
+
async decide(ctx) {
|
|
2294
|
+
const findings = newFindings();
|
|
2295
|
+
const delta = checkHeldout(findings, cfg, ctx);
|
|
2296
|
+
checkDimensions(findings, cfg, ctx);
|
|
2297
|
+
checkBudget(findings, cfg, ctx);
|
|
2298
|
+
checkRedTeam(findings, cfg, ctx);
|
|
2299
|
+
checkRewardHacking(findings, cfg);
|
|
2300
|
+
checkCanary(findings, cfg);
|
|
2301
|
+
return verdictOf(findings, delta);
|
|
2302
|
+
}
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
/** Hold when any check failed or a required check could not be evaluated; otherwise ship. */
|
|
2306
|
+
function verdictOf({ reasons, contributing, requiredUnavailable }, delta) {
|
|
2307
|
+
const decision = contributing.some((check) => check.status === "fail") || requiredUnavailable.size > 0 ? "hold" : "ship";
|
|
2308
|
+
const notEvaluated = contributing.filter((check) => check.status === "not_evaluated").map((check) => check.name);
|
|
2309
|
+
return {
|
|
2310
|
+
decision,
|
|
2311
|
+
reasons: reasons.length > 0 ? reasons : notEvaluated.length > 0 ? [`evaluated checks passed; not evaluated: ${notEvaluated.join(", ")}`] : ["all checks passed"],
|
|
2312
|
+
contributingGates: contributing,
|
|
2313
|
+
delta
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
//#endregion
|
|
2188
2317
|
//#region src/campaign/judge-snapshot.ts
|
|
2189
2318
|
/** Capture configuration and callbacks; receiver and closed-over state remain caller-owned. */
|
|
2190
2319
|
function captureJudge(judge) {
|
|
@@ -4423,13 +4552,9 @@ function toScoredSurfaceOutcome(hash, campaign, coverage, generation) {
|
|
|
4423
4552
|
* again on the same run directory and options continues an interrupted run
|
|
4424
4553
|
* instead of starting over, and reruns nothing that settled.
|
|
4425
4554
|
*/
|
|
4426
|
-
/** Compose the optimization proposer and cell executor on the shared search kernel. */
|
|
4427
4555
|
/** Improve a surface as a search on the kernel; see the module comment. */
|
|
4428
4556
|
async function runOptimization(opts) {
|
|
4429
|
-
const candidateConcurrency = opts
|
|
4430
|
-
if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) throw new Error("runOptimization: runDir is required and must be a non-empty string");
|
|
4431
|
-
if (!Number.isInteger(candidateConcurrency) || candidateConcurrency < 1) throw new Error("runOptimization: candidateConcurrency must be a positive integer");
|
|
4432
|
-
for (const [name, value] of [["populationSize", opts.populationSize], ["maxGenerations", opts.maxGenerations]]) if (!Number.isSafeInteger(value) || value < 0) throw new Error(`runOptimization: ${name} must be a non-negative integer`);
|
|
4557
|
+
const candidateConcurrency = assertOptimizationOptions(opts);
|
|
4433
4558
|
const initialFindings = immutableProposalSnapshot(assertProposalFindings(opts.findings ?? [], "runOptimization initial proposal findings"), "initial findings");
|
|
4434
4559
|
const baselineSurface = immutableProposalSnapshot(opts.baselineSurface, "baseline surface");
|
|
4435
4560
|
const runDir = resolveRunDir(opts.runDir, opts.repo);
|
|
@@ -4468,7 +4593,53 @@ async function runOptimization(opts) {
|
|
|
4468
4593
|
const recorder = await SearchRecorder.open({
|
|
4469
4594
|
ledger: binding.ledger,
|
|
4470
4595
|
storage
|
|
4471
|
-
}, {
|
|
4596
|
+
}, searchOpening({
|
|
4597
|
+
opts,
|
|
4598
|
+
identity,
|
|
4599
|
+
execution,
|
|
4600
|
+
baselineSurface,
|
|
4601
|
+
splitDigest,
|
|
4602
|
+
policy,
|
|
4603
|
+
allocationName: allocation.name,
|
|
4604
|
+
seed
|
|
4605
|
+
}));
|
|
4606
|
+
const run = {
|
|
4607
|
+
opts,
|
|
4608
|
+
runDir,
|
|
4609
|
+
costLedger,
|
|
4610
|
+
reps,
|
|
4611
|
+
requireJudgeScore,
|
|
4612
|
+
premeasured,
|
|
4613
|
+
identity,
|
|
4614
|
+
policy,
|
|
4615
|
+
recorder,
|
|
4616
|
+
nodes: new SurfaceNodes(opts, recorder, runDir, costLedger, execution, premeasured),
|
|
4617
|
+
findings: initialFindings
|
|
4618
|
+
};
|
|
4619
|
+
return optimizationResult(run, baselineSurface, await runSearch({
|
|
4620
|
+
recorder,
|
|
4621
|
+
root: baselineSurface,
|
|
4622
|
+
codec: surfaceCodec,
|
|
4623
|
+
policy,
|
|
4624
|
+
allocation,
|
|
4625
|
+
proposer: optimizationProposerPort(run),
|
|
4626
|
+
executor: optimizationExecutor(run, candidateConcurrency),
|
|
4627
|
+
maxExpansions: opts.maxGenerations,
|
|
4628
|
+
signal: opts.signal
|
|
4629
|
+
}));
|
|
4630
|
+
}
|
|
4631
|
+
/** Reject malformed run settings before any state is touched; returns the candidate concurrency. */
|
|
4632
|
+
function assertOptimizationOptions(opts) {
|
|
4633
|
+
const candidateConcurrency = opts.candidateConcurrency ?? 1;
|
|
4634
|
+
if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) throw new Error("runOptimization: runDir is required and must be a non-empty string");
|
|
4635
|
+
if (!Number.isInteger(candidateConcurrency) || candidateConcurrency < 1) throw new Error("runOptimization: candidateConcurrency must be a positive integer");
|
|
4636
|
+
for (const [name, value] of [["populationSize", opts.populationSize], ["maxGenerations", opts.maxGenerations]]) if (!Number.isSafeInteger(value) || value < 0) throw new Error(`runOptimization: ${name} must be a non-negative integer`);
|
|
4637
|
+
return candidateConcurrency;
|
|
4638
|
+
}
|
|
4639
|
+
/** The search ledger's opening record: subject, objective, train split, policy and budget. */
|
|
4640
|
+
function searchOpening(args) {
|
|
4641
|
+
const { opts, identity, baselineSurface, splitDigest, policy } = args;
|
|
4642
|
+
return {
|
|
4472
4643
|
subject: identity.subject ?? opts.proposer.kind,
|
|
4473
4644
|
process: {
|
|
4474
4645
|
name: "runOptimization",
|
|
@@ -4496,8 +4667,8 @@ async function runOptimization(opts) {
|
|
|
4496
4667
|
},
|
|
4497
4668
|
policy: {
|
|
4498
4669
|
expansion: policy.name,
|
|
4499
|
-
allocation:
|
|
4500
|
-
seed
|
|
4670
|
+
allocation: args.allocationName,
|
|
4671
|
+
seed: args.seed
|
|
4501
4672
|
},
|
|
4502
4673
|
budget: {
|
|
4503
4674
|
maxUsd: opts.costCeiling ?? null,
|
|
@@ -4509,12 +4680,14 @@ async function runOptimization(opts) {
|
|
|
4509
4680
|
},
|
|
4510
4681
|
containment: null,
|
|
4511
4682
|
derivedFrom: null,
|
|
4512
|
-
identity: execution
|
|
4513
|
-
}
|
|
4514
|
-
|
|
4683
|
+
identity: args.execution
|
|
4684
|
+
};
|
|
4685
|
+
}
|
|
4686
|
+
/** One lane that measures each candidate cell through the surface nodes. */
|
|
4687
|
+
function optimizationExecutor(run, candidateConcurrency) {
|
|
4688
|
+
const { opts, nodes } = run;
|
|
4515
4689
|
const scenarioById = new Map(opts.scenarios.map((scenario) => [scenario.id, scenario]));
|
|
4516
|
-
|
|
4517
|
-
const executor = {
|
|
4690
|
+
return {
|
|
4518
4691
|
lanes: () => [{
|
|
4519
4692
|
name: "campaign",
|
|
4520
4693
|
capacity: candidateConcurrency * (opts.maxConcurrency ?? 2),
|
|
@@ -4525,83 +4698,29 @@ async function runOptimization(opts) {
|
|
|
4525
4698
|
run: (work) => nodes.runCell(work, scenarioById),
|
|
4526
4699
|
adopt: (work) => nodes.adoptCell(work)
|
|
4527
4700
|
};
|
|
4701
|
+
}
|
|
4702
|
+
/** The proposer port: each proposal analyses the last generation, then asks the caller's proposer. */
|
|
4703
|
+
function optimizationProposerPort(run) {
|
|
4704
|
+
const { opts, identity, recorder, nodes, policy } = run;
|
|
4528
4705
|
const proposer = opts.proposer;
|
|
4529
4706
|
const proposerSource = identity.proposer.source;
|
|
4530
|
-
|
|
4707
|
+
return {
|
|
4531
4708
|
name: proposer.kind,
|
|
4532
4709
|
kind: "optimizer",
|
|
4533
4710
|
source: proposerSource,
|
|
4534
4711
|
execution: identity.proposer,
|
|
4535
4712
|
childrenPerProposal: opts.populationSize,
|
|
4536
4713
|
async propose(request) {
|
|
4537
|
-
const
|
|
4538
|
-
"search.proposal",
|
|
4539
|
-
"analysis.baseline",
|
|
4540
|
-
"analysis.generation"
|
|
4541
|
-
];
|
|
4542
|
-
const before = new Set(phases.flatMap((phase) => costLedger.list({ phase })).map((receipt) => receipt.callId));
|
|
4543
|
-
const accounting = () => {
|
|
4544
|
-
const fresh = phases.flatMap((phase) => costLedger.list({ phase })).filter((receipt) => !before.has(receipt.callId));
|
|
4545
|
-
return {
|
|
4546
|
-
accounting: searchReceiptAccounting(fresh),
|
|
4547
|
-
execution: opts.searchLedger ? identity.proposer : searchProposalExecution(fresh, identity.model.provider, proposerSource)
|
|
4548
|
-
};
|
|
4549
|
-
};
|
|
4714
|
+
const accounting = proposalAccounting(run);
|
|
4550
4715
|
const earlier = await recorder.state();
|
|
4551
4716
|
const root = earlier.rootNodeId;
|
|
4552
4717
|
const rootCampaign = nodes.campaign(earlier, root);
|
|
4553
|
-
|
|
4554
|
-
if (!rootCoverage.complete) throw new Error(`runOptimization: ${premeasured ? "premeasured baseline" : "baseline"} is incomplete (${rootCoverage.scorableCellIds.length}/${rootCoverage.expectedCellIds.length} designed cells scorable) — ${formatCoverageFailures(rootCoverage)}. Refusing to optimize against an incomplete incumbent.`);
|
|
4718
|
+
assertBaselineComplete(run, rootCampaign);
|
|
4555
4719
|
const generation = nodes.generations(earlier).length;
|
|
4556
|
-
if (opts.analyzeGeneration)
|
|
4557
|
-
const previous = generation - 1;
|
|
4558
|
-
const candidates = (previous < 0 ? [root] : nodes.expansionNodes(earlier, nodes.generations(earlier)[previous])).map((nodeId) => {
|
|
4559
|
-
const campaign = nodes.campaign(earlier, nodeId);
|
|
4560
|
-
return {
|
|
4561
|
-
surfaceHash: surfaceHash(nodes.surface(earlier, nodeId)),
|
|
4562
|
-
campaign,
|
|
4563
|
-
composite: campaignMeanCompositeOrNull(campaign)
|
|
4564
|
-
};
|
|
4565
|
-
});
|
|
4566
|
-
const history = nodes.history(earlier, policy);
|
|
4567
|
-
if (candidates.some(({ campaign }) => campaign.cells.length > 0)) {
|
|
4568
|
-
const fresh = await opts.analyzeGeneration({
|
|
4569
|
-
generation: previous,
|
|
4570
|
-
runDir: previous < 0 ? rootCampaign.runDir : `${runDir}/candidates`,
|
|
4571
|
-
candidates,
|
|
4572
|
-
history,
|
|
4573
|
-
costLedger,
|
|
4574
|
-
costPhase: previous < 0 ? "analysis.baseline" : "analysis.generation"
|
|
4575
|
-
});
|
|
4576
|
-
if (!Array.isArray(fresh)) throw new TypeError("runOptimization: analyzeGeneration must return an array");
|
|
4577
|
-
findings = immutableProposalSnapshot(assertProposalFindings(fresh, "runOptimization analysis findings"), "analysis findings");
|
|
4578
|
-
}
|
|
4579
|
-
}
|
|
4720
|
+
if (opts.analyzeGeneration) await analyzePreviousGeneration(run, earlier, generation, root, rootCampaign.runDir);
|
|
4580
4721
|
const state = await recorder.state();
|
|
4581
4722
|
const proposalHistory = immutableProposalSnapshot(nodes.history(state, policy), "history");
|
|
4582
|
-
const
|
|
4583
|
-
const context = Object.freeze({
|
|
4584
|
-
currentSurface: immutableProposalSnapshot(parent.artifact, "current surface"),
|
|
4585
|
-
operator: request.operator,
|
|
4586
|
-
parents: immutableProposalSnapshot(request.parents.map(({ nodeId, artifact }) => ({
|
|
4587
|
-
nodeId,
|
|
4588
|
-
artifact: immutableProposalSnapshot(artifact, "parent surface")
|
|
4589
|
-
})), "parents"),
|
|
4590
|
-
train: searchProposerView(state),
|
|
4591
|
-
summary: renderSearchSummary(state, { split: "train" }),
|
|
4592
|
-
history: proposalHistory,
|
|
4593
|
-
findings: immutableProposalSnapshot(assertProposalFindings(findings, "runOptimization proposal findings"), "findings"),
|
|
4594
|
-
populationSize: opts.populationSize,
|
|
4595
|
-
generation,
|
|
4596
|
-
signal: request.signal,
|
|
4597
|
-
baselineOutcome: immutableProposalSnapshot(nodes.outcome(state, root), "baseline"),
|
|
4598
|
-
incumbentOutcome: immutableProposalSnapshot(nodes.outcome(state, request.leader), "incumbent outcome"),
|
|
4599
|
-
parentOutcome: immutableProposalSnapshot(nodes.outcome(state, parent.nodeId), "parent outcome"),
|
|
4600
|
-
maxImprovementShots: opts.maxImprovementShots,
|
|
4601
|
-
paretoParents: immutableProposalSnapshot(nodes.frontier(state), "Pareto parents"),
|
|
4602
|
-
costLedger,
|
|
4603
|
-
costPhase: "search.proposal"
|
|
4604
|
-
});
|
|
4723
|
+
const context = proposeContext(run, request, state, generation, root, proposalHistory);
|
|
4605
4724
|
if (proposer.decide?.({ history: proposalHistory }).stop) return {
|
|
4606
4725
|
children: [],
|
|
4607
4726
|
stop: "the proposer decided to stop",
|
|
@@ -4624,17 +4743,86 @@ async function runOptimization(opts) {
|
|
|
4624
4743
|
};
|
|
4625
4744
|
}
|
|
4626
4745
|
};
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4746
|
+
}
|
|
4747
|
+
/** Snapshot the proposal-phase receipts now; the returned reader totals only receipts added since. */
|
|
4748
|
+
function proposalAccounting(run) {
|
|
4749
|
+
const { opts, identity, costLedger } = run;
|
|
4750
|
+
const phases = [
|
|
4751
|
+
"search.proposal",
|
|
4752
|
+
"analysis.baseline",
|
|
4753
|
+
"analysis.generation"
|
|
4754
|
+
];
|
|
4755
|
+
const before = new Set(phases.flatMap((phase) => costLedger.list({ phase })).map((receipt) => receipt.callId));
|
|
4756
|
+
return () => {
|
|
4757
|
+
const fresh = phases.flatMap((phase) => costLedger.list({ phase })).filter((receipt) => !before.has(receipt.callId));
|
|
4758
|
+
return {
|
|
4759
|
+
accounting: searchReceiptAccounting(fresh),
|
|
4760
|
+
execution: opts.searchLedger ? identity.proposer : searchProposalExecution(fresh, identity.model.provider, identity.proposer.source)
|
|
4761
|
+
};
|
|
4762
|
+
};
|
|
4763
|
+
}
|
|
4764
|
+
/** Refuse to optimize against a baseline whose designed cells are not all scorable. */
|
|
4765
|
+
function assertBaselineComplete(run, rootCampaign) {
|
|
4766
|
+
const { opts, reps, requireJudgeScore, premeasured } = run;
|
|
4767
|
+
const rootCoverage = campaignCoverage(rootCampaign.cells, opts.scenarios, reps, requireJudgeScore);
|
|
4768
|
+
if (!rootCoverage.complete) throw new Error(`runOptimization: ${premeasured ? "premeasured baseline" : "baseline"} is incomplete (${rootCoverage.scorableCellIds.length}/${rootCoverage.expectedCellIds.length} designed cells scorable) — ${formatCoverageFailures(rootCoverage)}. Refusing to optimize against an incomplete incumbent.`);
|
|
4769
|
+
}
|
|
4770
|
+
/** Run the caller's analysis over the previous generation (or the baseline) and keep its findings. */
|
|
4771
|
+
async function analyzePreviousGeneration(run, earlier, generation, root, rootRunDir) {
|
|
4772
|
+
const { opts, nodes, policy, costLedger, runDir } = run;
|
|
4773
|
+
const previous = generation - 1;
|
|
4774
|
+
const candidates = (previous < 0 ? [root] : nodes.expansionNodes(earlier, nodes.generations(earlier)[previous])).map((nodeId) => {
|
|
4775
|
+
const campaign = nodes.campaign(earlier, nodeId);
|
|
4776
|
+
return {
|
|
4777
|
+
surfaceHash: surfaceHash(nodes.surface(earlier, nodeId)),
|
|
4778
|
+
campaign,
|
|
4779
|
+
composite: campaignMeanCompositeOrNull(campaign)
|
|
4780
|
+
};
|
|
4637
4781
|
});
|
|
4782
|
+
const history = nodes.history(earlier, policy);
|
|
4783
|
+
if (candidates.some(({ campaign }) => campaign.cells.length > 0)) {
|
|
4784
|
+
const fresh = await opts.analyzeGeneration({
|
|
4785
|
+
generation: previous,
|
|
4786
|
+
runDir: previous < 0 ? rootRunDir : `${runDir}/candidates`,
|
|
4787
|
+
candidates,
|
|
4788
|
+
history,
|
|
4789
|
+
costLedger,
|
|
4790
|
+
costPhase: previous < 0 ? "analysis.baseline" : "analysis.generation"
|
|
4791
|
+
});
|
|
4792
|
+
if (!Array.isArray(fresh)) throw new TypeError("runOptimization: analyzeGeneration must return an array");
|
|
4793
|
+
run.findings = immutableProposalSnapshot(assertProposalFindings(fresh, "runOptimization analysis findings"), "analysis findings");
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
/** The frozen view of the search the caller's proposer reads. */
|
|
4797
|
+
function proposeContext(run, request, state, generation, root, proposalHistory) {
|
|
4798
|
+
const { opts, nodes, costLedger } = run;
|
|
4799
|
+
const parent = request.parents[0];
|
|
4800
|
+
return Object.freeze({
|
|
4801
|
+
currentSurface: immutableProposalSnapshot(parent.artifact, "current surface"),
|
|
4802
|
+
operator: request.operator,
|
|
4803
|
+
parents: immutableProposalSnapshot(request.parents.map(({ nodeId, artifact }) => ({
|
|
4804
|
+
nodeId,
|
|
4805
|
+
artifact: immutableProposalSnapshot(artifact, "parent surface")
|
|
4806
|
+
})), "parents"),
|
|
4807
|
+
train: searchProposerView(state),
|
|
4808
|
+
summary: renderSearchSummary(state, { split: "train" }),
|
|
4809
|
+
history: proposalHistory,
|
|
4810
|
+
findings: immutableProposalSnapshot(assertProposalFindings(run.findings, "runOptimization proposal findings"), "findings"),
|
|
4811
|
+
populationSize: opts.populationSize,
|
|
4812
|
+
generation,
|
|
4813
|
+
signal: request.signal,
|
|
4814
|
+
baselineOutcome: immutableProposalSnapshot(nodes.outcome(state, root), "baseline"),
|
|
4815
|
+
incumbentOutcome: immutableProposalSnapshot(nodes.outcome(state, request.leader), "incumbent outcome"),
|
|
4816
|
+
parentOutcome: immutableProposalSnapshot(nodes.outcome(state, parent.nodeId), "parent outcome"),
|
|
4817
|
+
maxImprovementShots: opts.maxImprovementShots,
|
|
4818
|
+
paretoParents: immutableProposalSnapshot(nodes.frontier(state), "Pareto parents"),
|
|
4819
|
+
costLedger,
|
|
4820
|
+
costPhase: "search.proposal"
|
|
4821
|
+
});
|
|
4822
|
+
}
|
|
4823
|
+
/** Read the finished search into the leader, its provenance and every generation's measured surfaces. */
|
|
4824
|
+
function optimizationResult(run, baselineSurface, result) {
|
|
4825
|
+
const { opts, nodes, policy, recorder, costLedger, runDir } = run;
|
|
4638
4826
|
const state = result.state;
|
|
4639
4827
|
const winnerSurface = nodes.surface(state, result.leader);
|
|
4640
4828
|
const firstEdge = state.edge(state.node(result.leader).edgeIds[0]);
|
|
@@ -4660,7 +4848,7 @@ async function runOptimization(opts) {
|
|
|
4660
4848
|
baselineCampaign: nodes.campaign(state, state.rootNodeId),
|
|
4661
4849
|
cost: costLedger.summary(),
|
|
4662
4850
|
searchHistory: recorder.receipt({
|
|
4663
|
-
producerId: proposer.kind,
|
|
4851
|
+
producerId: opts.proposer.kind,
|
|
4664
4852
|
runId: runDir
|
|
4665
4853
|
}),
|
|
4666
4854
|
paretoFrontier: nodes.frontier(state)
|
|
@@ -5744,4 +5932,4 @@ function firstString(value) {
|
|
|
5744
5932
|
//#endregion
|
|
5745
5933
|
export { planCampaignRun as $, verifySearchHistoryReceipt as A, defaultProductionGate as B, searchEdgeId as C, assertSearchHistoryMatchesState as D, assertSearchHistoryAdmissionOptions as E, asha as F, runCanaries as G, redTeamDataset as H, uniform as I, evaluationUnitMap as J, assertIndependentEvaluationSplit as K, runFinalComparison as L, searchModelIdentity as M, searchProposalExecution as N, createSearchHistoryReceipt as O, searchReceiptAccounting as P, runCampaign as Q, openAutoPr as R, developmentClaim as S, surfaceNode as T, redTeamReport as U, DEFAULT_RED_TEAM_CORPUS as V, scoreRedTeamOutput as W, reserveFinalEvidence as X, exposeFinalEvidence as Y, runEval as Z, beam as _, aggregateRunScore as a, incumbentWithOperatorBandit as b, assertGepaCandidatePopulationSummary as c, costFromLedgerSummary as d, resolveRunDir as et, optimizationTokenUsageFromSummary as f, aide as g, isProposedCandidate as h, transientDispatchFailure as i, campaignCellSearchResult as j, verifySearchHistoryArtifact as k, readGepaCandidatePopulationArtifact as l, runOptimization as m, JudgeParseError as n, cellCachePath as nt, clamp01 as o, runImprovementLoop as p, captureFinalEvidencePolicy as q, isTransientTransportFailure as r, computeManifestHash as rt, executeOptimizationMethod as s, llmJudge as t, buildCellSchedule as tt, combineComparisonCosts as u, crowdedFrontierParent as v, surfaceDiff as w, SearchRecorder as x, incumbent as y, captureJudge as z };
|
|
5746
5934
|
|
|
5747
|
-
//# sourceMappingURL=llm-judge-
|
|
5935
|
+
//# sourceMappingURL=llm-judge-Djxh-Uhs.js.map
|