@tangle-network/agent-eval 0.142.2 → 0.144.0

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +42 -8
  3. package/dist/analyst/index.d.ts +6 -6
  4. package/dist/analyst/index.d.ts.map +1 -1
  5. package/dist/analyst/index.js +3 -3
  6. package/dist/{benchmark-command-bTf4ibj-.js → benchmark-command-4c7N_rlw.js} +7 -6
  7. package/dist/benchmark-command-4c7N_rlw.js.map +1 -0
  8. package/dist/benchmarks/index.d.ts +1 -1
  9. package/dist/benchmarks/index.js +1 -1
  10. package/dist/{benchmarks-Ce8GdJbc.js → benchmarks-05UGZ8sZ.js} +4 -4
  11. package/dist/{benchmarks-Ce8GdJbc.js.map → benchmarks-05UGZ8sZ.js.map} +1 -1
  12. package/dist/campaign/index.d.ts +5 -4
  13. package/dist/campaign/index.js +4 -4
  14. package/dist/{campaign-COFTVy3Q.js → campaign-BKOtvRAB.js} +15 -11
  15. package/dist/campaign-BKOtvRAB.js.map +1 -0
  16. package/dist/cli.js +1 -1
  17. package/dist/{client-BoqGxEqx.d.ts → client-Cgl6KasJ.d.ts} +2 -2
  18. package/dist/{client-BoqGxEqx.d.ts.map → client-Cgl6KasJ.d.ts.map} +1 -1
  19. package/dist/contract/index.d.ts +5 -5
  20. package/dist/contract/index.js +4 -4
  21. package/dist/{default-registry-Ci7wAAR8.d.ts → default-registry-D3uqKbo6.d.ts} +2 -2
  22. package/dist/{default-registry-Ci7wAAR8.d.ts.map → default-registry-D3uqKbo6.d.ts.map} +1 -1
  23. package/dist/{default-registry-BupFSXSN.js → default-registry-DfHJEwYh.js} +2 -2
  24. package/dist/{default-registry-BupFSXSN.js.map → default-registry-DfHJEwYh.js.map} +1 -1
  25. package/dist/{dspy-rlm-engine-Bw8Zz9CX.js → dspy-rlm-engine-CBFwlyaY.js} +89 -7
  26. package/dist/dspy-rlm-engine-CBFwlyaY.js.map +1 -0
  27. package/dist/external-optimizer-contracts-iK0yu4AR.d.ts +128 -0
  28. package/dist/external-optimizer-contracts-iK0yu4AR.d.ts.map +1 -0
  29. package/dist/hosted/index.d.ts +2 -2
  30. package/dist/{index-BKjcUH13.d.ts → index-BZUe-ODI.d.ts} +41 -5
  31. package/dist/index-BZUe-ODI.d.ts.map +1 -0
  32. package/dist/{index-DCP4I2Qx.d.ts → index-DgbFl4cv.d.ts} +14 -11
  33. package/dist/{index-DCP4I2Qx.d.ts.map → index-DgbFl4cv.d.ts.map} +1 -1
  34. package/dist/{index-CKI1CXTL.d.ts → index-DtMpBKVF.d.ts} +4 -4
  35. package/dist/{index-CKI1CXTL.d.ts.map → index-DtMpBKVF.d.ts.map} +1 -1
  36. package/dist/index.d.ts +11 -11
  37. package/dist/index.js +9 -8
  38. package/dist/index.js.map +1 -1
  39. package/dist/{integrity-hruKe6oe.js → integrity-DY6tIbl0.js} +48 -18
  40. package/dist/integrity-DY6tIbl0.js.map +1 -0
  41. package/dist/multishot/index.d.ts +1 -1
  42. package/dist/openapi.json +1 -1
  43. package/dist/{replay-BqTgoioO.d.ts → replay-BuJM6kLh.d.ts} +2 -2
  44. package/dist/{replay-BqTgoioO.d.ts.map → replay-BuJM6kLh.d.ts.map} +1 -1
  45. package/dist/{reward-hacking-GyN0kMd8.js → reward-hacking-DjTi9HLb.js} +34 -14
  46. package/dist/reward-hacking-DjTi9HLb.js.map +1 -0
  47. package/dist/rl.d.ts +263 -2
  48. package/dist/rl.d.ts.map +1 -1
  49. package/dist/rl.js +332 -3
  50. package/dist/rl.js.map +1 -1
  51. package/dist/{single-run-lock-BcvPQY57.js → single-run-lock-t1si1ob7.js} +371 -153
  52. package/dist/single-run-lock-t1si1ob7.js.map +1 -0
  53. package/dist/{skill-usage-CNZTk_LT.d.ts → skill-usage-BiVEU0QY.d.ts} +5 -5
  54. package/dist/{skill-usage-CNZTk_LT.d.ts.map → skill-usage-BiVEU0QY.d.ts.map} +1 -1
  55. package/dist/{skillopt-optimization-method-D1dqGzzH.d.ts → skillopt-optimization-method-B7o01OdX.d.ts} +63 -13
  56. package/dist/skillopt-optimization-method-B7o01OdX.d.ts.map +1 -0
  57. package/dist/{skillopt-optimization-method-DV6c4ooy.js → skillopt-optimization-method-Ds8J1_K8.js} +440 -270
  58. package/dist/skillopt-optimization-method-Ds8J1_K8.js.map +1 -0
  59. package/dist/supervisor-run/index.d.ts +3 -3
  60. package/dist/supervisor-run/index.js +3 -3
  61. package/dist/{supervisor-run-BEns49Nx.js → supervisor-run-DiyQVczd.js} +301 -25
  62. package/dist/supervisor-run-DiyQVczd.js.map +1 -0
  63. package/dist/{tool-groups-DVQTy9lq.d.ts → tool-groups-Bqy4A3QB.d.ts} +2 -2
  64. package/dist/{tool-groups-DVQTy9lq.d.ts.map → tool-groups-Bqy4A3QB.d.ts.map} +1 -1
  65. package/dist/traces.d.ts +2 -2
  66. package/dist/{types-Dk7PB7vh.d.ts → types-KEqL1pZc.d.ts} +6 -4
  67. package/dist/{types-Dk7PB7vh.d.ts.map → types-KEqL1pZc.d.ts.map} +1 -1
  68. package/dist/{types-Dea6tiVI.d.ts → types-yLK8gXE9.d.ts} +15 -2
  69. package/dist/types-yLK8gXE9.d.ts.map +1 -0
  70. package/docs/campaign-proposers.md +11 -7
  71. package/docs/verified-labels-flywheel.md +46 -0
  72. package/package.json +1 -1
  73. package/dist/benchmark-command-bTf4ibj-.js.map +0 -1
  74. package/dist/campaign-COFTVy3Q.js.map +0 -1
  75. package/dist/dspy-rlm-engine-Bw8Zz9CX.js.map +0 -1
  76. package/dist/external-optimizer-contracts-nb7c_WAR.d.ts +0 -42
  77. package/dist/external-optimizer-contracts-nb7c_WAR.d.ts.map +0 -1
  78. package/dist/index-BKjcUH13.d.ts.map +0 -1
  79. package/dist/integrity-hruKe6oe.js.map +0 -1
  80. package/dist/reward-hacking-GyN0kMd8.js.map +0 -1
  81. package/dist/single-run-lock-BcvPQY57.js.map +0 -1
  82. package/dist/skillopt-optimization-method-D1dqGzzH.d.ts.map +0 -1
  83. package/dist/skillopt-optimization-method-DV6c4ooy.js.map +0 -1
  84. package/dist/supervisor-run-BEns49Nx.js.map +0 -1
  85. package/dist/types-Dea6tiVI.d.ts.map +0 -1
@@ -2,13 +2,13 @@ import { c as ValidationError, i as JudgeError, t as AgentEvalError } from "./er
2
2
  import { i as CostLedger, t as CostAccountingIncompleteError } from "./cost-ledger-DMFxsLKr.js";
3
3
  import { f as maximumChargeForLlmRequest, l as costReceiptFromLlm, m as stripFencedJson, u as costReceiptFromLlmError } from "./llm-client-B3WXSH5Y.js";
4
4
  import { a as clamp01, o as combineAbortSignals, t as assertProposalFindings } from "./proposal-findings-2GIUo1et.js";
5
- import { C as safePathComponent, S as removeCredentialEnvironment, _ as assertJsonValue, b as isExternalTextCandidate, d as runWithCleanup, f as startExternalOptimizerModelProxy, g as assertExternalOptimizerModelBudget, h as sendJson, l as runExternalOptimizerProcess, m as listenLocal, n as createRunCostLedger, p as closeServer, r as fsCampaignStorage, t as acquireSingleRunLock, u as closeExternalOptimizerResources, v as assertNoCredentialValues, x as isRecord, y as isCandidateText } from "./single-run-lock-BcvPQY57.js";
5
+ import { C as assertNoCredentialValues, D as removeCredentialEnvironment, E as isRecord, O as safePathComponent, S as assertJsonValue, T as isExternalTextCandidate, _ as canonicalJson, d as runWithCleanup, f as startExternalOptimizerModelProxy, h as sendJson, l as runExternalOptimizerProcess, m as listenLocal, n as createRunCostLedger, p as closeServer, r as fsCampaignStorage, t as acquireSingleRunLock, u as closeExternalOptimizerResources, v as contentHash, w as isCandidateText, x as assertExternalOptimizerModelBudget } from "./single-run-lock-t1si1ob7.js";
6
6
  import { p as mapConcurrent } from "./ledger-core-Dxz0Rkwa.js";
7
7
  import { E as pairedBootstrap, H as weightedComposite, M as pairedRiskDifferenceScore, N as pairedSignTest, O as pairedDeltaTieFraction, T as pairedBinaryScale, d as confidenceInterval, j as pairedRiskDifferenceExact } from "./statistics-ByxzSiOM.js";
8
8
  import { t as DEFAULT_REDACTION_RULES } from "./redact-7Aq1ukl-.js";
9
- import { a as campaignCellExecutionEvidence, l as projectCampaignCellQuality, t as detectRewardHacking } from "./reward-hacking-GyN0kMd8.js";
9
+ import { a as campaignCellCostProvenance, o as campaignCellExecutionEvidence, t as detectRewardHacking, u as projectCampaignCellQuality } from "./reward-hacking-DjTi9HLb.js";
10
10
  import { z } from "zod";
11
- import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
11
+ import { writeFileSync } from "node:fs";
12
12
  import { basename, isAbsolute, join } from "node:path";
13
13
  import { createHash, randomBytes } from "node:crypto";
14
14
  import { createServer } from "node:http";
@@ -656,160 +656,6 @@ function paretoFrontierWithCrowding(candidates, objectives) {
656
656
  return crowdingDistance(frontier, objectives).sort((a, b) => b.distance - a.distance);
657
657
  }
658
658
  //#endregion
659
- //#region src/verdict-cache.ts
660
- /**
661
- * Content-addressed judge-verdict caching.
662
- *
663
- * LAW: cache JUDGE VERDICTS only — judging the same artifact with the same
664
- * judge+rubric is pure. NEVER cache agent rollouts. (A router that cached
665
- * identical fanout prompts silently destroyed best-of-N diversity; rollout
666
- * caching reintroduces that failure class. Judging has no diversity to
667
- * destroy — same artifact + same rubric ⇒ same verdict is the desired
668
- * property, not a bug.)
669
- *
670
- * The cache key is a sha-256 over the canonical JSON of everything that can
671
- * change a verdict: the artifact content, the scenario id, the judge name,
672
- * the full dimension list (key + description — the description IS the rubric
673
- * text shown to the judge), and a caller-supplied `judgeVersion`.
674
- * `judgeVersion` is REQUIRED: a judge whose prompt/model/ensemble changes
675
- * without a version bump would otherwise silently serve stale verdicts.
676
- *
677
- * Strict canonicalization (`canonicalJson`) throws on undefined / function /
678
- * symbol / non-finite numbers — an artifact that cannot be unambiguously
679
- * serialized cannot be content-addressed, and coercing it would let two
680
- * different artifacts collide on one key.
681
- */
682
- function canonicalizeAt(value, path) {
683
- if (value === null) return "null";
684
- switch (typeof value) {
685
- case "boolean": return value ? "true" : "false";
686
- case "number":
687
- if (!Number.isFinite(value)) throw new Error(`canonicalJson: non-finite number (${value}) at ${path} — ambiguity is an error, not a coercion`);
688
- return JSON.stringify(value);
689
- case "string": return JSON.stringify(value);
690
- case "undefined":
691
- case "function":
692
- case "symbol": throw new Error(`canonicalJson: ${typeof value} at ${path} — ambiguity is an error, not a coercion`);
693
- case "bigint": throw new Error(`canonicalJson: bigint at ${path} — not representable in JSON`);
694
- case "object": break;
695
- }
696
- const obj = value;
697
- if (typeof obj.toJSON === "function") return canonicalizeAt(obj.toJSON(), path);
698
- if (Array.isArray(obj)) return `[${obj.map((item, i) => canonicalizeAt(item, `${path}[${i}]`)).join(",")}]`;
699
- if (obj instanceof Map || obj instanceof Set) throw new Error(`canonicalJson: ${obj instanceof Map ? "Map" : "Set"} at ${path} — would serialize as '{}'; convert to a plain object/array first`);
700
- return `{${Object.keys(obj).sort().map((k) => `${JSON.stringify(k)}:${canonicalizeAt(obj[k], `${path}.${k}`)}`).join(",")}}`;
701
- }
702
- /**
703
- * Stable JSON stringify: object keys sorted recursively, so two semantically
704
- * equal values produce byte-identical output regardless of key insertion
705
- * order. Throws on undefined / function / symbol / NaN / ±Infinity / bigint /
706
- * Map / Set — anything JSON.stringify would coerce or drop silently.
707
- *
708
- * Distinct from `pre-registration.ts`'s `canonicalize`/`hashJson`, which are
709
- * permissive (coercion allowed) and async (web-crypto). Use THIS pair when a
710
- * hash collision or silent coercion would corrupt a cache key or attestation.
711
- */
712
- function canonicalJson(value) {
713
- return canonicalizeAt(value, "$");
714
- }
715
- /** Hex sha-256 over `canonicalJson(value)`. The content address used by the
716
- * verdict cache and report attestation. */
717
- function contentHash(value) {
718
- return createHash("sha256").update(canonicalJson(value)).digest("hex");
719
- }
720
- /** Process-local Map-backed store. */
721
- function inMemoryVerdictCache() {
722
- const entries = /* @__PURE__ */ new Map();
723
- return {
724
- get: (key) => entries.get(key),
725
- set: (key, score) => {
726
- entries.set(key, score);
727
- }
728
- };
729
- }
730
- function parseCacheLine(line, path, lineNo) {
731
- let parsed;
732
- try {
733
- parsed = JSON.parse(line);
734
- } catch (err) {
735
- throw new Error(`fileVerdictCache: corrupt JSONL at ${path}:${lineNo} — ${err instanceof Error ? err.message : String(err)}`);
736
- }
737
- const rec = parsed;
738
- if (typeof rec !== "object" || rec === null || typeof rec.key !== "string" || typeof rec.score !== "object" || rec.score === null || typeof rec.score.composite !== "number" || typeof rec.score.dimensions !== "object") throw new Error(`fileVerdictCache: invalid record shape at ${path}:${lineNo} — expected {key, score:{dimensions, composite, notes}}`);
739
- return rec;
740
- }
741
- /**
742
- * JSONL-file-backed store: the full file is loaded into an in-memory index at
743
- * construction; every `set` appends one line synchronously (durable before
744
- * the verdict is returned). A corrupt or malformed line throws at load with
745
- * file:line — a skipped line would silently re-judge (cost) or, worse, mask
746
- * a half-written file that needs operator attention.
747
- */
748
- function fileVerdictCache(path) {
749
- const entries = /* @__PURE__ */ new Map();
750
- if (existsSync(path)) {
751
- const lines = readFileSync(path, "utf8").split("\n");
752
- for (let i = 0; i < lines.length; i++) {
753
- const line = lines[i];
754
- if (line === void 0 || line.trim() === "") continue;
755
- const rec = parseCacheLine(line, path, i + 1);
756
- entries.set(rec.key, rec.score);
757
- }
758
- }
759
- return {
760
- get: (key) => entries.get(key),
761
- set: (key, score) => {
762
- appendFileSync(path, `${JSON.stringify({
763
- key,
764
- score
765
- })}\n`, "utf8");
766
- entries.set(key, score);
767
- }
768
- };
769
- }
770
- /**
771
- * Wrap a `JudgeConfig` so repeat judgments of the same artifact are served
772
- * from the store instead of re-invoking `score()`. The wrapper is generic
773
- * over the judge's own type parameters and preserves `appliesTo` — it is a
774
- * drop-in replacement anywhere a `JudgeConfig` is accepted.
775
- *
776
- * A judge that throws is NOT cached: the error propagates and the next
777
- * attempt re-judges (caching a failure would pin a transient outage forever).
778
- */
779
- function cachedJudge(judge, store, options) {
780
- if (typeof options.judgeVersion !== "string" || options.judgeVersion.trim() === "") throw new Error("cachedJudge: judgeVersion is required and must be a non-empty string");
781
- const stats = {
782
- hits: 0,
783
- misses: 0
784
- };
785
- const wrapped = {
786
- name: judge.name,
787
- dimensions: judge.dimensions,
788
- judgeVersion: options.judgeVersion,
789
- async score(input) {
790
- const key = contentHash({
791
- artifact: canonicalJson(input.artifact),
792
- scenarioId: input.scenario.id,
793
- judgeName: judge.name,
794
- dimensions: judge.dimensions,
795
- judgeVersion: options.judgeVersion
796
- });
797
- const cached = await store.get(key);
798
- if (cached !== void 0) {
799
- stats.hits += 1;
800
- return cached;
801
- }
802
- const score = await judge.score(input);
803
- await store.set(key, score);
804
- stats.misses += 1;
805
- return score;
806
- },
807
- stats: () => ({ ...stats })
808
- };
809
- if (judge.appliesTo) wrapped.appliesTo = judge.appliesTo;
810
- return wrapped;
811
- }
812
- //#endregion
813
659
  //#region src/llm-judge.ts
814
660
  /**
815
661
  * `llmJudge` — the single-LLM-call bridge that turns a rubric prompt into a
@@ -1813,6 +1659,8 @@ async function startExternalOptimizerCallback(args) {
1813
1659
  let closePromise;
1814
1660
  const activeControllers = /* @__PURE__ */ new Set();
1815
1661
  const activeHandlers = /* @__PURE__ */ new Set();
1662
+ const proposedCandidateHashes = /* @__PURE__ */ new Set();
1663
+ let observationSequence = 0;
1816
1664
  const server = createServer((request, response) => {
1817
1665
  if (!accepting) {
1818
1666
  sendJsonIfOpen(response, 503, { error: "external optimizer callback is closing" });
@@ -1833,7 +1681,13 @@ async function startExternalOptimizerCallback(args) {
1833
1681
  if (accepted > args.maxEvaluations) return void 0;
1834
1682
  evaluations += 1;
1835
1683
  return accepted;
1836
- }).finally(() => {
1684
+ }, (observation) => {
1685
+ if (!args.observe) return;
1686
+ args.observe({
1687
+ ...observation,
1688
+ sequence: ++observationSequence
1689
+ });
1690
+ }, proposedCandidateHashes).finally(() => {
1837
1691
  controller.signal.removeEventListener("abort", abortRequest);
1838
1692
  activeControllers.delete(controller);
1839
1693
  activeHandlers.delete(handler);
@@ -1868,7 +1722,7 @@ async function startExternalOptimizerCallback(args) {
1868
1722
  if (serverResult?.status === "rejected") throw serverResult.reason;
1869
1723
  }
1870
1724
  }
1871
- async function handleCallback(request, response, signal, args, nextEvaluation) {
1725
+ async function handleCallback(request, response, signal, args, nextEvaluation, observe, proposedCandidateHashes) {
1872
1726
  try {
1873
1727
  if (request.method !== "POST" || request.url !== "/evaluate") {
1874
1728
  sendJsonIfOpen(response, 404, { error: "not found" });
@@ -1878,19 +1732,76 @@ async function handleCallback(request, response, signal, args, nextEvaluation) {
1878
1732
  sendJsonIfOpen(response, 401, { error: "unauthorized" });
1879
1733
  return;
1880
1734
  }
1881
- const body = await readJson(request);
1735
+ let body;
1736
+ try {
1737
+ body = await readJson(request);
1738
+ } catch {
1739
+ observe({
1740
+ kind: "refusal",
1741
+ reason: "invalid-request"
1742
+ });
1743
+ sendJsonIfOpen(response, 400, { error: "request body must be bounded valid JSON" });
1744
+ return;
1745
+ }
1882
1746
  if (!isRecord(body) || !isExternalTextCandidate(body.candidate) || typeof body.exampleId !== "string") {
1747
+ observe({
1748
+ kind: "refusal",
1749
+ reason: "invalid-request"
1750
+ });
1883
1751
  sendJsonIfOpen(response, 400, { error: "candidate and exampleId are required strings" });
1884
1752
  return;
1885
1753
  }
1886
- if (nextEvaluation() === void 0) {
1754
+ const candidate = cloneCandidate(body.candidate);
1755
+ const candidateHash = contentHash({
1756
+ kind: "external-text-candidate",
1757
+ candidate
1758
+ });
1759
+ if (!proposedCandidateHashes.has(candidateHash)) {
1760
+ observe({
1761
+ kind: "proposal",
1762
+ candidate,
1763
+ candidateHash
1764
+ });
1765
+ proposedCandidateHashes.add(candidateHash);
1766
+ }
1767
+ const count = nextEvaluation();
1768
+ if (count === void 0) {
1769
+ observe({
1770
+ kind: "refusal",
1771
+ reason: "evaluation-limit",
1772
+ candidate,
1773
+ candidateHash,
1774
+ exampleId: body.exampleId
1775
+ });
1887
1776
  sendJsonIfOpen(response, 429, { error: "evaluation limit reached" });
1888
1777
  return;
1889
1778
  }
1890
- sendJsonIfOpen(response, 200, await args.evaluate({
1891
- candidate: body.candidate,
1892
- exampleId: body.exampleId
1893
- }, signal));
1779
+ let result;
1780
+ try {
1781
+ result = await args.evaluate({
1782
+ candidate,
1783
+ exampleId: body.exampleId
1784
+ }, signal);
1785
+ } catch {
1786
+ observe({
1787
+ kind: "refusal",
1788
+ reason: "evaluation-failed",
1789
+ candidate,
1790
+ candidateHash,
1791
+ exampleId: body.exampleId
1792
+ });
1793
+ sendJsonIfOpen(response, 500, { error: "evaluation failed" });
1794
+ return;
1795
+ }
1796
+ observe({
1797
+ kind: "evaluation",
1798
+ candidate,
1799
+ candidateHash,
1800
+ exampleId: body.exampleId,
1801
+ evaluationNumber: count,
1802
+ response: structuredClone(result)
1803
+ });
1804
+ sendJsonIfOpen(response, 200, result);
1894
1805
  } catch {
1895
1806
  sendJsonIfOpen(response, 500, { error: "evaluation failed" });
1896
1807
  }
@@ -1930,6 +1841,10 @@ function assertCallbackConfig(args) {
1930
1841
  if (!Number.isSafeInteger(args.maxEvaluations) || args.maxEvaluations <= 0) throw new Error("external optimizer callback: maxEvaluations must be a positive safe integer");
1931
1842
  if (args.acceptEvaluation !== void 0 && typeof args.acceptEvaluation !== "function") throw new Error("external optimizer callback: acceptEvaluation must be a function");
1932
1843
  if (typeof args.evaluate !== "function") throw new Error("external optimizer callback: evaluate must be a function");
1844
+ if (args.observe !== void 0 && typeof args.observe !== "function") throw new Error("external optimizer callback: observe must be a function");
1845
+ }
1846
+ function cloneCandidate(candidate) {
1847
+ return typeof candidate === "string" ? candidate : { ...candidate };
1933
1848
  }
1934
1849
  //#endregion
1935
1850
  //#region src/campaign/external-optimizer-run-budget.ts
@@ -2069,6 +1984,15 @@ async function runCampaign(opts) {
2069
1984
  const cells = [];
2070
1985
  const artifactsByPath = {};
2071
1986
  const schedule = buildCellSchedule(opts.scenarios, seed, reps);
1987
+ if (resumable) assertScheduleCachesReusable({
1988
+ schedule,
1989
+ runDir: opts.runDir,
1990
+ manifestHash,
1991
+ storage,
1992
+ costLedger,
1993
+ costTags: opts.costTags,
1994
+ rerunInvalidCachedCells: opts.rerunInvalidCachedCells ?? false
1995
+ });
2072
1996
  const campaignAbort = new AbortController();
2073
1997
  const onOwnerAbort = () => campaignAbort.abort(opts.signal?.reason);
2074
1998
  if (opts.signal?.aborted) campaignAbort.abort(opts.signal.reason);
@@ -2153,15 +2077,9 @@ async function runCampaign(opts) {
2153
2077
  }
2154
2078
  async function executeCell(args) {
2155
2079
  const storage = args.storage;
2156
- const cellDir = join(args.opts.runDir, args.slot.cellId.replace(/[^a-zA-Z0-9_-]/g, "_"));
2080
+ const cellDir = cellDirectory(args.opts.runDir, args.slot.cellId);
2157
2081
  storage.ensureDir(cellDir);
2158
- const stableCostTags = {
2159
- ...args.opts.costTags ?? {},
2160
- runDir: args.opts.runDir,
2161
- cellId: args.slot.cellId,
2162
- scenarioId: args.slot.scenario.id,
2163
- rep: String(args.slot.rep)
2164
- };
2082
+ const stableCostTags = stableCostTagsFor(args.opts, args.slot);
2165
2083
  const costTags = {
2166
2084
  ...stableCostTags,
2167
2085
  runAttemptId: args.runAttemptId
@@ -2174,24 +2092,27 @@ async function executeCell(args) {
2174
2092
  cellId: args.slot.cellId,
2175
2093
  manifestHash: args.manifestHash
2176
2094
  });
2095
+ if (cached.status === "miss" && cacheIssueRequiresExplicitRerun(cached.reason) && !args.opts.rerunInvalidCachedCells) throw invalidCachedCellsError([{
2096
+ cellId: args.slot.cellId,
2097
+ reason: cached.reason
2098
+ }]);
2177
2099
  if (cached.status === "hit") {
2178
- enforceDispatchUsage(cached.cell, args.opts.expectUsage ?? "warn");
2179
- const cachedHasUsage = cached.cell.costUsd > 0 || cached.cell.tokenUsage.input > 0 || cached.cell.tokenUsage.output > 0;
2180
- if (cached.cell.costCallIds === void 0) {
2181
- if (cachedHasUsage || Object.keys(cached.cell.judgeScores).length > 0) throw new CostAccountingIncompleteError(`runCampaign: cached cell '${args.slot.cellId}' does not identify its ledger receipts`);
2182
- } else if (!Array.isArray(cached.cell.costCallIds) || cached.cell.costCallIds.some((callId) => typeof callId !== "string" || callId.trim().length === 0) || new Set(cached.cell.costCallIds).size !== cached.cell.costCallIds.length) throw new CostAccountingIncompleteError(`runCampaign: cached cell '${args.slot.cellId}' has invalid ledger receipt IDs`);
2183
- else {
2184
- const restoredCallIds = new Set(args.costLedger.list({ tags: stableCostTags }).map((receipt) => receipt.callId));
2185
- const missingCallIds = cached.cell.costCallIds.filter((callId) => !restoredCallIds.has(callId));
2186
- if (missingCallIds.length > 0) throw new CostAccountingIncompleteError(`runCampaign: cached cell '${args.slot.cellId}' is missing ledger receipt(s): ${missingCallIds.join(", ")}`);
2100
+ const receiptProblem = cachedCellReceiptProblem(cached.cell, args.costLedger, stableCostTags);
2101
+ if (receiptProblem === void 0) {
2102
+ enforceDispatchUsage(cached.cell, args.opts.expectUsage ?? "warn");
2103
+ return {
2104
+ cell: {
2105
+ ...cached.cell,
2106
+ cached: true
2107
+ },
2108
+ artifactsByPath: {}
2109
+ };
2187
2110
  }
2188
- return {
2189
- cell: {
2190
- ...cached.cell,
2191
- cached: true
2192
- },
2193
- artifactsByPath: {}
2194
- };
2111
+ if (!args.opts.rerunInvalidCachedCells) throw invalidCachedCellsError([{
2112
+ cellId: args.slot.cellId,
2113
+ reason: "invalid-cost-receipts",
2114
+ detail: receiptProblem
2115
+ }]);
2195
2116
  }
2196
2117
  }
2197
2118
  const startMs = Date.now();
@@ -2321,7 +2242,9 @@ async function executeCell(args) {
2321
2242
  const tokenUsage = {
2322
2243
  input: agentCost.inputTokens,
2323
2244
  output: agentCost.outputTokens,
2324
- ...agentCost.cachedTokens > 0 ? { cached: agentCost.cachedTokens } : {}
2245
+ ...agentCost.reasoningTokens !== void 0 && agentCost.reasoningTokens > 0 ? { reasoning: agentCost.reasoningTokens } : {},
2246
+ ...agentCost.cachedTokens > 0 ? { cached: agentCost.cachedTokens } : {},
2247
+ ...agentCost.cacheWriteTokens !== void 0 && agentCost.cacheWriteTokens > 0 ? { cacheWrite: agentCost.cacheWriteTokens } : {}
2325
2248
  };
2326
2249
  const resolvedModel = agentReceipts.at(-1)?.model;
2327
2250
  const dispatchResult = {
@@ -2377,7 +2300,7 @@ async function executeCell(args) {
2377
2300
  artifact: artifact ?? null,
2378
2301
  judgeScores,
2379
2302
  costUsd: agentCost.totalCostUsd,
2380
- costEstimated: agentReceipts.some((receipt) => receipt.actualCostUsd === void 0 && !receipt.costUnknown),
2303
+ costProvenance: agentCost.costProvenance,
2381
2304
  costCallIds,
2382
2305
  tokenUsage,
2383
2306
  ...resolvedModel ? { resolvedModel } : {},
@@ -2467,6 +2390,11 @@ function planCampaignRun(opts) {
2467
2390
  assertCampaignDesign(opts.scenarios, reps);
2468
2391
  if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) throw new Error("planCampaignRun: runDir is required and must be a non-empty string");
2469
2392
  opts.runDir = resolveRunDir(opts.runDir, opts.repo);
2393
+ const costLedger = opts.costLedger ?? createRunCostLedger({
2394
+ storage,
2395
+ runDir: opts.runDir,
2396
+ ensureRunDir: false
2397
+ });
2470
2398
  const manifestHash = computeManifestHash({
2471
2399
  scenarios: opts.scenarios,
2472
2400
  judges: opts.judges ?? [],
@@ -2476,7 +2404,7 @@ function planCampaignRun(opts) {
2476
2404
  });
2477
2405
  const splitDigest = campaignSplitDigest(opts.scenarios, reps);
2478
2406
  const cells = buildCellSchedule(opts.scenarios, seed, reps).map((slot) => {
2479
- const cachePath = join(opts.runDir, slot.cellId.replace(/[^a-zA-Z0-9_-]/g, "_"), "cached-result.json");
2407
+ const cachePath = cellCachePath(opts.runDir, slot.cellId);
2480
2408
  if (!resumable) return {
2481
2409
  cellId: slot.cellId,
2482
2410
  scenarioId: slot.scenario.id,
@@ -2492,31 +2420,48 @@ function planCampaignRun(opts) {
2492
2420
  cellId: slot.cellId,
2493
2421
  manifestHash
2494
2422
  });
2495
- if (cached.status === "hit") return {
2496
- cellId: slot.cellId,
2497
- scenarioId: slot.scenario.id,
2498
- rep: slot.rep,
2499
- seed: slot.cellSeed,
2500
- cachePath,
2501
- status: "cached"
2502
- };
2423
+ if (cached.status === "hit") {
2424
+ if (cachedCellReceiptProblem(cached.cell, costLedger, stableCostTagsFor({
2425
+ runDir: opts.runDir,
2426
+ costTags: opts.costTags
2427
+ }, slot)) !== void 0) return {
2428
+ cellId: slot.cellId,
2429
+ scenarioId: slot.scenario.id,
2430
+ rep: slot.rep,
2431
+ seed: slot.cellSeed,
2432
+ cachePath,
2433
+ status: opts.rerunInvalidCachedCells ? "run" : "blocked",
2434
+ reason: "invalid-cost-receipts"
2435
+ };
2436
+ return {
2437
+ cellId: slot.cellId,
2438
+ scenarioId: slot.scenario.id,
2439
+ rep: slot.rep,
2440
+ seed: slot.cellSeed,
2441
+ cachePath,
2442
+ status: "cached"
2443
+ };
2444
+ }
2445
+ const blocked = cacheIssueRequiresExplicitRerun(cached.reason) && !opts.rerunInvalidCachedCells;
2503
2446
  return {
2504
2447
  cellId: slot.cellId,
2505
2448
  scenarioId: slot.scenario.id,
2506
2449
  rep: slot.rep,
2507
2450
  seed: slot.cellSeed,
2508
2451
  cachePath,
2509
- status: "run",
2452
+ status: blocked ? "blocked" : "run",
2510
2453
  reason: cached.reason
2511
2454
  };
2512
2455
  });
2513
2456
  const cellsCached = cells.filter((cell) => cell.status === "cached").length;
2457
+ const cellsBlocked = cells.filter((cell) => cell.status === "blocked").length;
2514
2458
  return {
2515
2459
  manifestHash,
2516
2460
  splitDigest,
2517
2461
  totalCells: cells.length,
2518
2462
  cellsCached,
2519
- cellsToRun: cells.length - cellsCached,
2463
+ cellsBlocked,
2464
+ cellsToRun: cells.filter((cell) => cell.status === "run").length,
2520
2465
  cells
2521
2466
  };
2522
2467
  }
@@ -2633,6 +2578,59 @@ function buildCellSchedule(scenarios, seed, reps) {
2633
2578
  }
2634
2579
  return schedule;
2635
2580
  }
2581
+ function cellDirectory(runDir, cellId) {
2582
+ return join(runDir, cellId.replace(/[^a-zA-Z0-9_-]/g, "_"));
2583
+ }
2584
+ function cellCachePath(runDir, cellId) {
2585
+ return join(cellDirectory(runDir, cellId), "cached-result.json");
2586
+ }
2587
+ function stableCostTagsFor(opts, slot) {
2588
+ return {
2589
+ ...opts.costTags ?? {},
2590
+ runDir: opts.runDir,
2591
+ cellId: slot.cellId,
2592
+ scenarioId: slot.scenario.id,
2593
+ rep: String(slot.rep)
2594
+ };
2595
+ }
2596
+ function assertScheduleCachesReusable(args) {
2597
+ const blocked = [];
2598
+ for (const slot of args.schedule) {
2599
+ const cached = readCachedCell({
2600
+ storage: args.storage,
2601
+ cachePath: cellCachePath(args.runDir, slot.cellId),
2602
+ cellId: slot.cellId,
2603
+ manifestHash: args.manifestHash
2604
+ });
2605
+ if (cached.status === "hit") {
2606
+ const receiptProblem = cachedCellReceiptProblem(cached.cell, args.costLedger, stableCostTagsFor({
2607
+ runDir: args.runDir,
2608
+ costTags: args.costTags
2609
+ }, slot));
2610
+ if (receiptProblem !== void 0 && !args.rerunInvalidCachedCells) blocked.push({
2611
+ cellId: slot.cellId,
2612
+ reason: "invalid-cost-receipts",
2613
+ detail: receiptProblem
2614
+ });
2615
+ } else if (cacheIssueRequiresExplicitRerun(cached.reason) && !args.rerunInvalidCachedCells) blocked.push({
2616
+ cellId: slot.cellId,
2617
+ reason: cached.reason
2618
+ });
2619
+ }
2620
+ if (blocked.length > 0) throw invalidCachedCellsError(blocked);
2621
+ }
2622
+ function cachedCellReceiptProblem(cached, costLedger, stableCostTags) {
2623
+ const reportsPaidActivity = cached.costProvenance.kind !== "observed" || cached.costUsd > 0 || cached.tokenUsage.input > 0 || cached.tokenUsage.output > 0;
2624
+ if (cached.costCallIds === void 0) {
2625
+ if (reportsPaidActivity || Object.keys(cached.judgeScores).length > 0) return "does not identify its ledger receipts";
2626
+ return;
2627
+ }
2628
+ if (!Array.isArray(cached.costCallIds) || cached.costCallIds.some((callId) => typeof callId !== "string" || callId.trim().length === 0) || new Set(cached.costCallIds).size !== cached.costCallIds.length) return "has invalid ledger receipt IDs";
2629
+ if (cached.costCallIds.length === 0 && reportsPaidActivity) return "does not identify its ledger receipts";
2630
+ const restoredCallIds = new Set(costLedger.list({ tags: stableCostTags }).map((receipt) => receipt.callId));
2631
+ const missingCallIds = cached.costCallIds.filter((callId) => !restoredCallIds.has(callId));
2632
+ if (missingCallIds.length > 0) return `is missing ledger receipt(s): ${missingCallIds.join(", ")}`;
2633
+ }
2636
2634
  function dispatchRefFor(dispatch, override) {
2637
2635
  const ref = override ?? dispatch?.name ?? "anonymous";
2638
2636
  if (typeof ref !== "string" || ref.trim().length === 0) throw new Error("runCampaign: dispatchRef must be a non-empty string when provided");
@@ -2642,18 +2640,32 @@ function readCachedCell(args) {
2642
2640
  const raw = args.storage.read(args.cachePath);
2643
2641
  if (raw === void 0) return {
2644
2642
  status: "miss",
2645
- reason: "missing"
2643
+ reason: args.storage.exists(args.cachePath) ? "corrupt" : "missing"
2646
2644
  };
2645
+ let parsed;
2647
2646
  try {
2648
- const cached = JSON.parse(raw);
2649
- if (cached.cellId !== args.cellId) return {
2650
- status: "miss",
2651
- reason: "cell-mismatch"
2652
- };
2653
- if (cached.manifestHash !== args.manifestHash) return {
2647
+ parsed = JSON.parse(raw);
2648
+ } catch {
2649
+ return {
2654
2650
  status: "miss",
2655
- reason: "manifest-mismatch"
2651
+ reason: "corrupt"
2656
2652
  };
2653
+ }
2654
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {
2655
+ status: "miss",
2656
+ reason: "corrupt"
2657
+ };
2658
+ const cached = parsed;
2659
+ if (cached.cellId !== args.cellId) return {
2660
+ status: "miss",
2661
+ reason: "cell-mismatch"
2662
+ };
2663
+ if (cached.manifestHash !== args.manifestHash) return {
2664
+ status: "miss",
2665
+ reason: "manifest-mismatch"
2666
+ };
2667
+ try {
2668
+ campaignCellCostProvenance(cached);
2657
2669
  return {
2658
2670
  status: "hit",
2659
2671
  cell: cached
@@ -2661,10 +2673,16 @@ function readCachedCell(args) {
2661
2673
  } catch {
2662
2674
  return {
2663
2675
  status: "miss",
2664
- reason: "corrupt"
2676
+ reason: cached.costProvenance === void 0 ? "missing-cost-provenance" : "invalid-cost-provenance"
2665
2677
  };
2666
2678
  }
2667
2679
  }
2680
+ function cacheIssueRequiresExplicitRerun(reason) {
2681
+ return reason === "cell-mismatch" || reason === "missing-cost-provenance" || reason === "invalid-cost-provenance" || reason === "invalid-cost-receipts" || reason === "corrupt";
2682
+ }
2683
+ function invalidCachedCellsError(cells) {
2684
+ return new CostAccountingIncompleteError(`runCampaign: cached cell(s) require explicit paid re-dispatch: ${cells.map((cell) => `${cell.cellId} (${cell.reason}${cell.detail ? `: ${cell.detail}` : ""})`).join(", ")}; refusing to begin campaign. Inspect planCampaignRun, then set rerunInvalidCachedCells: true to rerun only these cells while retaining valid caches, or resumable: false when a full rerun is intended.`);
2685
+ }
2668
2686
  async function captureToStore(args) {
2669
2687
  await args.store.observe({
2670
2688
  scenario: args.scenario,
@@ -3389,7 +3407,7 @@ async function compareOptimizationMethods(opts) {
3389
3407
  throw error;
3390
3408
  }
3391
3409
  });
3392
- assertReportedCostWithinCeiling(combineCosts(optimized.map((result) => ({
3410
+ assertReportedCostWithinCeiling(combineComparisonCosts(optimized.map((result) => ({
3393
3411
  label: `method '${result.name}'`,
3394
3412
  cost: result.cost
3395
3413
  }))).totalCostUsd, opts.costCeiling, "optimization");
@@ -3474,12 +3492,12 @@ async function compareOptimizationMethods(opts) {
3474
3492
  favored
3475
3493
  };
3476
3494
  });
3477
- const optimizationCost = combineCosts(scores.map((score) => ({
3495
+ const optimizationCost = combineComparisonCosts(scores.map((score) => ({
3478
3496
  label: `method '${score.name}'`,
3479
3497
  cost: score.optimizationCost
3480
3498
  })));
3481
3499
  const testCost = costFromLedgerSummary(costLedger.summary({ phase: testCostPhase }));
3482
- const totalCost = combineCosts([{
3500
+ const totalCost = combineComparisonCosts([{
3483
3501
  label: "optimization",
3484
3502
  cost: optimizationCost
3485
3503
  }, {
@@ -3542,6 +3560,7 @@ function assertOptimizationProvenance(methodName, value) {
3542
3560
  for (const [field, entry] of [["sourceUrl", value.source.sourceUrl], ["revision", value.source.revision]]) if (entry !== void 0 && (typeof entry !== "string" || !entry.trim())) fail(`source.${field}`);
3543
3561
  if (typeof value.runId !== "string" || !value.runId.trim()) fail("runId");
3544
3562
  if (value.optimizerModel !== void 0 && (typeof value.optimizerModel !== "string" || !value.optimizerModel.trim() || value.optimizerModel.trim() !== value.optimizerModel)) fail("optimizerModel");
3563
+ if (value.optimizerCallRef !== void 0 && (typeof value.optimizerCallRef !== "string" || !value.optimizerCallRef.trim() || value.optimizerCallRef.trim() !== value.optimizerCallRef)) fail("optimizerCallRef");
3545
3564
  if (typeof value.resumed !== "boolean") fail("resumed");
3546
3565
  if (!Number.isSafeInteger(value.evaluationCount) || value.evaluationCount < 0) fail("evaluationCount");
3547
3566
  if (typeof value.artifactDir !== "string" || !value.artifactDir.trim()) fail("artifactDir");
@@ -3564,6 +3583,24 @@ function assertOptimizationProvenance(methodName, value) {
3564
3583
  if (value.tokenUsage.reasoningTokens !== void 0 && value.tokenUsage.reasoningTokens > value.tokenUsage.outputTokens) fail("tokenUsage.reasoningTokens");
3565
3584
  if (value.tokenUsage.totalTokens !== value.tokenUsage.inputTokens + value.tokenUsage.outputTokens) fail("tokenUsage.totalTokens");
3566
3585
  }
3586
+ if (value.observations !== void 0) {
3587
+ if (value.observations.scope !== "callback-submitted-candidates" || typeof value.observations.path !== "string" || !value.observations.path.trim() || typeof value.observations.sha256 !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.observations.sha256)) fail("observations");
3588
+ for (const field of [
3589
+ "submittedCandidates",
3590
+ "evaluations",
3591
+ "refusals"
3592
+ ]) if (!Number.isSafeInteger(value.observations[field]) || value.observations[field] < 0) fail(`observations.${field}`);
3593
+ }
3594
+ if (value.modelExecutions !== void 0) {
3595
+ if (value.modelExecutions.scope !== "runtime-model-calls" || typeof value.modelExecutions.path !== "string" || !value.modelExecutions.path.trim() || typeof value.modelExecutions.sha256 !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.modelExecutions.sha256)) fail("modelExecutions");
3596
+ for (const field of [
3597
+ "calls",
3598
+ "succeeded",
3599
+ "failed"
3600
+ ]) if (!Number.isSafeInteger(value.modelExecutions[field]) || value.modelExecutions[field] < 0) fail(`modelExecutions.${field}`);
3601
+ if (value.modelExecutions.calls !== value.modelExecutions.succeeded + value.modelExecutions.failed) fail("modelExecutions.calls");
3602
+ }
3603
+ if (value.optimizerModel === void 0 !== (value.optimizerCallRef === void 0) || value.optimizerModel === void 0 !== (value.modelExecutions === void 0)) fail("optimizerModel execution provenance");
3567
3604
  }
3568
3605
  function assertComparisonControls(opts, seed, resamples, confidence) {
3569
3606
  if (opts.optimizationRunOptions && "costCeiling" in opts.optimizationRunOptions) throw new Error("compareOptimizationMethods: optimizationRunOptions.costCeiling is not supported; costCeiling covers optimization and final scoring");
@@ -3707,6 +3744,7 @@ function callerDispatchRef(opts) {
3707
3744
  function costFromLedgerSummary(summary) {
3708
3745
  const cost = {
3709
3746
  totalCostUsd: summary.totalCostUsd,
3747
+ costProvenance: structuredClone(summary.costProvenance),
3710
3748
  accountingComplete: summary.accountingComplete,
3711
3749
  incompleteReasons: [...summary.incompleteReasons]
3712
3750
  };
@@ -3733,19 +3771,37 @@ function optimizationTokenUsageFromSummary(summary, receipts) {
3733
3771
  calls: summary.totalCalls
3734
3772
  };
3735
3773
  }
3736
- function combineCosts(entries) {
3737
- return {
3738
- totalCostUsd: entries.reduce((total, entry) => total + entry.cost.totalCostUsd, 0),
3774
+ /** Combine method costs without turning one unknown bill into a known total. */
3775
+ function combineComparisonCosts(entries) {
3776
+ const totalCostUsd = entries.reduce((total, entry) => total + entry.cost.totalCostUsd, 0);
3777
+ const cost = {
3778
+ totalCostUsd,
3779
+ costProvenance: entries.some((entry) => entry.cost.costProvenance.kind === "uncaptured") ? {
3780
+ kind: "uncaptured",
3781
+ usd: null
3782
+ } : entries.every((entry) => entry.cost.costProvenance.kind === "observed") ? {
3783
+ kind: "observed",
3784
+ usd: totalCostUsd
3785
+ } : {
3786
+ kind: "estimated",
3787
+ usd: totalCostUsd
3788
+ },
3739
3789
  accountingComplete: entries.every((entry) => entry.cost.accountingComplete),
3740
3790
  incompleteReasons: entries.flatMap((entry) => entry.cost.incompleteReasons.map((reason) => `${entry.label}: ${reason}`))
3741
3791
  };
3792
+ assertComparisonCost(cost, "combined cost");
3793
+ return cost;
3742
3794
  }
3743
3795
  function assertComparisonCost(cost, label) {
3744
3796
  if (!cost || typeof cost !== "object") throw new Error(`compareOptimizationMethods: ${label} returned no cost`);
3745
3797
  if (!Number.isFinite(cost.totalCostUsd) || cost.totalCostUsd < 0) throw new Error(`compareOptimizationMethods: ${label} returned an invalid totalCostUsd`);
3798
+ const provenance = cost.costProvenance;
3799
+ if (!provenance || typeof provenance !== "object" || provenance.kind !== "observed" && provenance.kind !== "estimated" && provenance.kind !== "uncaptured" || (provenance.kind === "uncaptured" ? provenance.usd !== null : !Number.isFinite(provenance.usd) || provenance.usd < 0)) throw new Error(`compareOptimizationMethods: ${label} returned invalid costProvenance`);
3800
+ if (provenance.kind !== "uncaptured" && provenance.usd !== cost.totalCostUsd) throw new Error(`compareOptimizationMethods: ${label} returned costProvenance inconsistent with totalCostUsd`);
3746
3801
  if (typeof cost.accountingComplete !== "boolean") throw new Error(`compareOptimizationMethods: ${label} returned invalid accountingComplete`);
3747
3802
  if (!Array.isArray(cost.incompleteReasons) || cost.incompleteReasons.some((reason) => typeof reason !== "string" || reason.trim().length === 0)) throw new Error(`compareOptimizationMethods: ${label} returned invalid incompleteReasons`);
3748
3803
  if (cost.accountingComplete !== (cost.incompleteReasons.length === 0)) throw new Error(`compareOptimizationMethods: ${label} returned inconsistent cost completeness and reasons`);
3804
+ if (cost.accountingComplete && provenance.kind === "uncaptured") throw new Error(`compareOptimizationMethods: ${label} cannot mark uncaptured cost as complete`);
3749
3805
  }
3750
3806
  //#endregion
3751
3807
  //#region src/campaign/external-text-optimization.ts
@@ -3994,16 +4050,23 @@ function externalTextOptimizationMethod(config) {
3994
4050
  status: "completed"
3995
4051
  }
3996
4052
  });
4053
+ const measuredCost = combineComparisonCosts([{
4054
+ label: "evaluation",
4055
+ cost: evaluationCost
4056
+ }, {
4057
+ label: "optimizer",
4058
+ cost: optimizerCost
4059
+ }]);
3997
4060
  return {
3998
4061
  winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
3999
4062
  cost: {
4000
- totalCostUsd: evaluationCost.totalCostUsd + optimizerCost.totalCostUsd,
4001
- accountingComplete: evaluationCost.accountingComplete && optimizerCost.accountingComplete && externalCostReason === void 0,
4002
- incompleteReasons: [
4003
- ...evaluationCost.incompleteReasons.map((reason) => `evaluation: ${reason}`),
4004
- ...optimizerCost.incompleteReasons.map((reason) => `optimizer: ${reason}`),
4005
- ...externalCostReason ? [`optimizer: external spend is not observed: ${externalCostReason}`] : []
4006
- ]
4063
+ ...measuredCost,
4064
+ ...externalCostReason ? { costProvenance: {
4065
+ kind: "uncaptured",
4066
+ usd: null
4067
+ } } : {},
4068
+ accountingComplete: measuredCost.accountingComplete && externalCostReason === void 0,
4069
+ incompleteReasons: [...measuredCost.incompleteReasons, ...externalCostReason ? [`optimizer: external spend is not observed: ${externalCostReason}`] : []]
4007
4070
  },
4008
4071
  durationMs: Date.now() - started,
4009
4072
  provenance: {
@@ -5236,8 +5299,8 @@ const TOKEN_USAGE_FIELDS = [
5236
5299
  "calls"
5237
5300
  ];
5238
5301
  function assertPriorExternalOptimizerUsage(summary, budget, name) {
5239
- if (!summary.accountingComplete || !summary.usageComplete) throw new Error(`${name}: cannot resume optimizer-model work with incomplete prior cost or usage`);
5240
- if (summary.totalCalls > budget.maxRequests || summary.totalCostUsd > budget.maxCostUsd + Number.EPSILON) throw new Error(`${name}: prior optimizer-model usage exceeds the configured budget`);
5302
+ if (!summary.usageComplete || budget.maxCostUsd !== void 0 && !summary.accountingComplete) throw new Error(`${name}: cannot resume optimizer-model work with incomplete bounded usage`);
5303
+ if (summary.totalCalls > budget.maxRequests || budget.maxCostUsd !== void 0 && summary.totalCostUsd > budget.maxCostUsd + Number.EPSILON) throw new Error(`${name}: prior optimizer-model usage exceeds the configured budget`);
5241
5304
  }
5242
5305
  function assertExternalOptimizerTokenUsage(usage, name, optimizer) {
5243
5306
  if (usage === void 0) return;
@@ -5252,6 +5315,78 @@ function assertExternalOptimizerCompletionCount(upstream, requestAttempts, succe
5252
5315
  if (upstream.requestAttempts !== void 0 && upstream.requestAttempts !== requestAttempts) throw new Error(`${name}: ${optimizer} reported ${upstream.requestAttempts} model attempts but the proxy received ${requestAttempts}`);
5253
5316
  }
5254
5317
  //#endregion
5318
+ //#region src/campaign/external-optimizer-observations.ts
5319
+ /** Append-only observation log for one external-optimizer attempt. */
5320
+ function openExternalOptimizerObservationLog(input) {
5321
+ if (input.storage.read(input.path) !== void 0 || input.storage.exists(input.path)) throw new Error(`external optimizer observation log already exists at '${input.path}'`);
5322
+ input.storage.write(input.path, "");
5323
+ let revision = 0;
5324
+ const counts = {
5325
+ submittedCandidates: 0,
5326
+ evaluations: 0,
5327
+ refusals: 0
5328
+ };
5329
+ return {
5330
+ observe(observation) {
5331
+ const expectedSequence = counts.submittedCandidates + counts.evaluations + counts.refusals + 1;
5332
+ if (observation.sequence !== expectedSequence) throw new Error(`external optimizer observation log expected sequence ${expectedSequence}, got ${observation.sequence}`);
5333
+ const line = `${canonicalJson(observation)}\n`;
5334
+ const next = input.storage.append(input.path, line, revision);
5335
+ if (next === void 0) throw new Error(`external optimizer observation log changed concurrently at '${input.path}'`);
5336
+ revision = next;
5337
+ if (observation.kind === "proposal") counts.submittedCandidates += 1;
5338
+ else if (observation.kind === "evaluation") counts.evaluations += 1;
5339
+ else counts.refusals += 1;
5340
+ },
5341
+ summary() {
5342
+ const contents = input.storage.read(input.path) ?? "";
5343
+ const bytes = new TextEncoder().encode(contents);
5344
+ if (bytes.byteLength !== revision) throw new Error(`external optimizer observation log revision changed at '${input.path}'`);
5345
+ return {
5346
+ scope: "callback-submitted-candidates",
5347
+ path: input.path,
5348
+ sha256: `sha256:${createHash("sha256").update(bytes).digest("hex")}`,
5349
+ ...counts
5350
+ };
5351
+ }
5352
+ };
5353
+ }
5354
+ /** Append-only opaque Runtime execution records for one optimizer attempt. */
5355
+ function openExternalOptimizerExecutionLog(input) {
5356
+ if (input.storage.read(input.path) !== void 0 || input.storage.exists(input.path)) throw new Error(`external optimizer execution log already exists at '${input.path}'`);
5357
+ input.storage.write(input.path, "");
5358
+ let revision = 0;
5359
+ const counts = {
5360
+ calls: 0,
5361
+ succeeded: 0,
5362
+ failed: 0
5363
+ };
5364
+ return {
5365
+ observe(observation) {
5366
+ if (observation.sequence !== counts.calls + 1) throw new Error(`external optimizer execution log expected sequence ${counts.calls + 1}, got ${observation.sequence}`);
5367
+ const line = `${canonicalJson(observation)}\n`;
5368
+ const next = input.storage.append(input.path, line, revision);
5369
+ if (next === void 0) throw new Error(`external optimizer execution log changed concurrently at '${input.path}'`);
5370
+ revision = next;
5371
+ counts.calls += 1;
5372
+ if (observation.succeeded) counts.succeeded += 1;
5373
+ else counts.failed += 1;
5374
+ },
5375
+ summary() {
5376
+ const contents = input.storage.read(input.path) ?? "";
5377
+ const bytes = new TextEncoder().encode(contents);
5378
+ if (bytes.byteLength !== revision) throw new Error(`external optimizer execution log revision changed at '${input.path}'`);
5379
+ if (counts.calls !== counts.succeeded + counts.failed) throw new Error(`external optimizer execution log counts disagree at '${input.path}'`);
5380
+ return {
5381
+ scope: "runtime-model-calls",
5382
+ path: input.path,
5383
+ sha256: `sha256:${createHash("sha256").update(bytes).digest("hex")}`,
5384
+ ...counts
5385
+ };
5386
+ }
5387
+ };
5388
+ }
5389
+ //#endregion
5255
5390
  //#region src/campaign/external-optimizer-run-config.ts
5256
5391
  function externalOptimizerRunnerIdentity(runner, module) {
5257
5392
  return {
@@ -5343,27 +5478,16 @@ function assertExternalOptimizerRuntimeIdentity(value, expectedPackage, label) {
5343
5478
  //#region src/campaign/optimizer-model.ts
5344
5479
  function assertOptimizerModel(value, label) {
5345
5480
  if (!value || typeof value !== "object") throw new Error(`${label} is required`);
5346
- for (const field of [
5347
- "model",
5348
- "baseUrl",
5349
- "apiKey"
5350
- ]) {
5351
- const item = value[field];
5352
- if (typeof item !== "string" || !item.trim() || item.trim() !== item) throw new Error(`${label}.${field} must be trimmed and non-empty`);
5353
- }
5354
- let url;
5355
- try {
5356
- url = new URL(value.baseUrl);
5357
- } catch {
5358
- throw new Error(`${label}.baseUrl must be an absolute HTTP URL`);
5359
- }
5360
- if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new Error(`${label}.baseUrl must use HTTP or HTTPS without credentials, query, or fragment`);
5481
+ for (const [field, item] of [["model", value.model], ["callRef", value.callRef]]) if (typeof item !== "string" || !item.trim() || item.trim() !== item) throw new Error(`${label}.${field} must be trimmed and non-empty`);
5482
+ if (typeof value.call !== "function") throw new Error(`${label}.call must be a function`);
5361
5483
  assertExternalOptimizerModelBudget(value.budget, `${label}.budget`);
5362
5484
  }
5363
5485
  function snapshotOptimizerModel(value) {
5364
5486
  return {
5365
- ...value,
5366
- budget: structuredClone(value.budget)
5487
+ model: value.model,
5488
+ budget: structuredClone(value.budget),
5489
+ call: value.call,
5490
+ callRef: value.callRef
5367
5491
  };
5368
5492
  }
5369
5493
  const MAX_TIMER_DELAY_MS$1 = 2147483647;
@@ -5478,7 +5602,7 @@ function assertEngineRun(run, label) {
5478
5602
  function assertEngineOptions(run, label) {
5479
5603
  if (!run || typeof run !== "object") throw new Error(`gepaOptimizationMethod: ${label} is required`);
5480
5604
  if (typeof run.engine !== "string" || !run.engine.trim() || run.engine.trim() !== run.engine) throw new Error(`gepaOptimizationMethod: ${label}.engine must be a trimmed non-empty string`);
5481
- if (!Number.isFinite(run.maxProposerCostUsd) || run.maxProposerCostUsd <= 0) throw new Error(`gepaOptimizationMethod: ${label}.maxProposerCostUsd must be a positive finite number`);
5605
+ if (run.maxProposerCostUsd !== void 0 && (!Number.isFinite(run.maxProposerCostUsd) || run.maxProposerCostUsd <= 0)) throw new Error(`gepaOptimizationMethod: ${label}.maxProposerCostUsd must be a positive finite number when supplied`);
5482
5606
  if (run.maxConcurrency !== void 0) assertPositiveSafeInteger$1(run.maxConcurrency, `${label}.maxConcurrency`);
5483
5607
  if (run.stopAtScore !== void 0 && !Number.isFinite(run.stopAtScore)) throw new Error(`gepaOptimizationMethod: ${label}.stopAtScore must be a finite number`);
5484
5608
  if (run.sandbox !== void 0 && typeof run.sandbox !== "boolean") throw new Error(`gepaOptimizationMethod: ${label}.sandbox must be a boolean`);
@@ -5605,7 +5729,7 @@ function gepaOptimizationMethod(config) {
5605
5729
  maxEvidenceChars,
5606
5730
  optimizerModel: config.optimizer ? {
5607
5731
  model: config.optimizer.model,
5608
- baseUrl: config.optimizer.baseUrl,
5732
+ callRef: config.optimizer.callRef,
5609
5733
  budget: config.optimizer.budget
5610
5734
  } : null,
5611
5735
  runner: externalOptimizerRunnerIdentity(bridgeRunner, "agent_eval_rpc.gepa_bridge"),
@@ -5624,6 +5748,14 @@ function gepaOptimizationMethod(config) {
5624
5748
  attemptId,
5625
5749
  maxEvaluations: evaluationLimit
5626
5750
  });
5751
+ const observationLog = openExternalOptimizerObservationLog({
5752
+ storage,
5753
+ path: `${runDir}/observations-${attemptId}.jsonl`
5754
+ });
5755
+ const executionLog = config.optimizer ? openExternalOptimizerExecutionLog({
5756
+ storage,
5757
+ path: `${runDir}/model-executions-${attemptId}.jsonl`
5758
+ }) : void 0;
5627
5759
  const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "GEPA bridge");
5628
5760
  const evaluate = createExternalTextEvaluator({
5629
5761
  input,
@@ -5643,6 +5775,7 @@ function gepaOptimizationMethod(config) {
5643
5775
  maxEvaluations: evaluationLimit,
5644
5776
  acceptEvaluation: () => runBudget.acceptEvaluation(),
5645
5777
  evaluate,
5778
+ observe: observationLog.observe,
5646
5779
  ...signal ? { signal } : {}
5647
5780
  });
5648
5781
  const runnerEnv = bridgeRunner?.env ?? {};
@@ -5662,8 +5795,9 @@ function gepaOptimizationMethod(config) {
5662
5795
  });
5663
5796
  assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
5664
5797
  modelProxy = await startExternalOptimizerModelProxy({
5665
- upstreamBaseUrl: config.optimizer.baseUrl,
5666
- upstreamApiKey: config.optimizer.apiKey,
5798
+ call: config.optimizer.call,
5799
+ callRef: config.optimizer.callRef,
5800
+ recordExecution: executionLog.observe,
5667
5801
  model: config.optimizer.model,
5668
5802
  budget: config.optimizer.budget,
5669
5803
  costLedger,
@@ -5672,7 +5806,7 @@ function gepaOptimizationMethod(config) {
5672
5806
  tags: { ...runBudget.attemptTags },
5673
5807
  initialUsage: {
5674
5808
  requests: priorOptimizerUsage.totalCalls,
5675
- costUsd: priorOptimizerUsage.totalCostUsd
5809
+ ...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
5676
5810
  },
5677
5811
  ...signal ? { signal } : {}
5678
5812
  });
@@ -5751,17 +5885,31 @@ function gepaOptimizationMethod(config) {
5751
5885
  });
5752
5886
  const optimizerCost = costFromLedgerSummary(optimizerSummary);
5753
5887
  const reportedProposerCost = result.proposerCostUsd ?? 0;
5754
- if (modelProxy) assertExternalOptimizerCompletionCount(result.tokenUsage, modelProxy.requestAttempts(), modelProxy.successfulCompletions(), name, "GEPA");
5888
+ if (modelProxy) {
5889
+ modelProxy.assertExecutionComplete();
5890
+ assertExternalOptimizerCompletionCount(result.tokenUsage, modelProxy.requestAttempts(), modelProxy.successfulCompletions(), name, "GEPA");
5891
+ }
5755
5892
  const tokenUsage = modelProxy ? optimizationTokenUsageFromSummary(optimizerSummary, optimizerReceipts) : void 0;
5756
5893
  const runtime = observedExternalOptimizerRuntime(runtimeIdentity);
5894
+ const meteredCost = modelProxy ? combineComparisonCosts([{
5895
+ label: "evaluation",
5896
+ cost: evaluationCost
5897
+ }, {
5898
+ label: "optimizer model",
5899
+ cost: optimizerCost
5900
+ }]) : void 0;
5901
+ const externalTotalCostUsd = evaluationCost.totalCostUsd + reportedProposerCost;
5757
5902
  return {
5758
5903
  winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
5759
- cost: modelProxy ? {
5760
- totalCostUsd: evaluationCost.totalCostUsd + optimizerCost.totalCostUsd,
5761
- accountingComplete: evaluationCost.accountingComplete && optimizerCost.accountingComplete,
5762
- incompleteReasons: [...evaluationCost.incompleteReasons.map((reason) => `evaluation: ${reason}`), ...optimizerCost.incompleteReasons.map((reason) => `optimizer model: ${reason}`)]
5763
- } : {
5764
- totalCostUsd: evaluationCost.totalCostUsd + reportedProposerCost,
5904
+ cost: modelProxy ? meteredCost : {
5905
+ totalCostUsd: externalTotalCostUsd,
5906
+ costProvenance: result.proposerCostAccounting === "reported" && evaluationCost.costProvenance.kind !== "uncaptured" ? {
5907
+ kind: "estimated",
5908
+ usd: externalTotalCostUsd
5909
+ } : {
5910
+ kind: "uncaptured",
5911
+ usd: null
5912
+ },
5765
5913
  accountingComplete: false,
5766
5914
  incompleteReasons: [
5767
5915
  ...evaluationCost.incompleteReasons,
@@ -5772,13 +5920,18 @@ function gepaOptimizationMethod(config) {
5772
5920
  durationMs: Date.now() - started,
5773
5921
  provenance: {
5774
5922
  ...runtime,
5775
- ...config.optimizer ? { optimizerModel: config.optimizer.model } : {},
5923
+ ...config.optimizer ? {
5924
+ optimizerModel: config.optimizer.model,
5925
+ optimizerCallRef: config.optimizer.callRef
5926
+ } : {},
5776
5927
  compatibleRunId,
5777
5928
  runId,
5778
5929
  resumed: result.resumed,
5779
5930
  evaluationCount: runBudget.acceptedEvaluations(),
5780
5931
  artifactDir: outputDir,
5781
- ...tokenUsage ? { tokenUsage } : {}
5932
+ ...tokenUsage ? { tokenUsage } : {},
5933
+ observations: observationLog.summary(),
5934
+ ...executionLog ? { modelExecutions: executionLog.summary() } : {}
5782
5935
  }
5783
5936
  };
5784
5937
  }
@@ -6524,7 +6677,7 @@ function campaignMeasurementDigest(campaign) {
6524
6677
  generation: cell.generation ?? null,
6525
6678
  judgeScores: cell.judgeScores,
6526
6679
  costUsd: cell.costUsd,
6527
- costEstimated: cell.costEstimated ?? null,
6680
+ costProvenance: cell.costProvenance,
6528
6681
  costCallIds: [...cell.costCallIds ?? []].sort(),
6529
6682
  tokenUsage: cell.tokenUsage,
6530
6683
  resolvedModel: cell.resolvedModel ?? null,
@@ -6973,7 +7126,7 @@ function skillOptOptimizationMethod(config) {
6973
7126
  background: config.background ?? "",
6974
7127
  optimizerModel: {
6975
7128
  model: config.optimizer.model,
6976
- baseUrl: config.optimizer.baseUrl,
7129
+ callRef: config.optimizer.callRef,
6977
7130
  budget: config.optimizer.budget
6978
7131
  },
6979
7132
  seedCandidate: input.baselineSurface,
@@ -6998,6 +7151,14 @@ function skillOptOptimizationMethod(config) {
6998
7151
  attemptId,
6999
7152
  maxEvaluations: config.maxEvaluations
7000
7153
  });
7154
+ const observationLog = openExternalOptimizerObservationLog({
7155
+ storage,
7156
+ path: `${runDir}/observations-${attemptId}.jsonl`
7157
+ });
7158
+ const executionLog = openExternalOptimizerExecutionLog({
7159
+ storage,
7160
+ path: `${runDir}/model-executions-${attemptId}.jsonl`
7161
+ });
7001
7162
  const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "SkillOpt bridge");
7002
7163
  const evaluate = createExternalTextEvaluator({
7003
7164
  input,
@@ -7017,6 +7178,7 @@ function skillOptOptimizationMethod(config) {
7017
7178
  maxEvaluations: config.maxEvaluations,
7018
7179
  acceptEvaluation: () => runBudget.acceptEvaluation(),
7019
7180
  evaluate,
7181
+ observe: observationLog.observe,
7020
7182
  ...signal ? { signal } : {}
7021
7183
  });
7022
7184
  const runnerEnv = bridgeRunner?.env ?? {};
@@ -7035,8 +7197,9 @@ function skillOptOptimizationMethod(config) {
7035
7197
  });
7036
7198
  assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
7037
7199
  const modelProxy = await startExternalOptimizerModelProxy({
7038
- upstreamBaseUrl: config.optimizer.baseUrl,
7039
- upstreamApiKey: config.optimizer.apiKey,
7200
+ call: config.optimizer.call,
7201
+ callRef: config.optimizer.callRef,
7202
+ recordExecution: executionLog.observe,
7040
7203
  model: config.optimizer.model,
7041
7204
  budget: config.optimizer.budget,
7042
7205
  costLedger,
@@ -7045,7 +7208,7 @@ function skillOptOptimizationMethod(config) {
7045
7208
  tags: { ...runBudget.attemptTags },
7046
7209
  initialUsage: {
7047
7210
  requests: priorOptimizerUsage.totalCalls,
7048
- costUsd: priorOptimizerUsage.totalCostUsd
7211
+ ...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
7049
7212
  },
7050
7213
  ...signal ? { signal } : {}
7051
7214
  });
@@ -7134,32 +7297,39 @@ function skillOptOptimizationMethod(config) {
7134
7297
  tags: runBudget.runTags
7135
7298
  });
7136
7299
  const optimizerCost = costFromLedgerSummary(optimizerUsage);
7300
+ modelProxy.assertExecutionComplete();
7137
7301
  assertExternalOptimizerCompletionCount(result.tokenUsage, modelProxy.requestAttempts(), modelProxy.successfulCompletions(), name, "SkillOpt");
7138
7302
  const tokenUsage = optimizationTokenUsageFromSummary(optimizerUsage, optimizerReceipts);
7139
7303
  const runtime = observedExternalOptimizerRuntime(runtimeIdentity);
7304
+ const combinedCost = combineComparisonCosts([{
7305
+ label: "evaluation",
7306
+ cost: evaluationCost
7307
+ }, {
7308
+ label: "optimizer model",
7309
+ cost: optimizerCost
7310
+ }]);
7140
7311
  return {
7141
7312
  winnerSurface: result.bestCandidate,
7142
- cost: {
7143
- totalCostUsd: evaluationCost.totalCostUsd + optimizerCost.totalCostUsd,
7144
- accountingComplete: evaluationCost.accountingComplete && optimizerCost.accountingComplete,
7145
- incompleteReasons: [...evaluationCost.incompleteReasons.map((reason) => `evaluation: ${reason}`), ...optimizerCost.incompleteReasons.map((reason) => `optimizer model: ${reason}`)]
7146
- },
7313
+ cost: combinedCost,
7147
7314
  durationMs: Date.now() - started,
7148
7315
  provenance: {
7149
7316
  ...runtime,
7150
7317
  optimizerModel: config.optimizer.model,
7318
+ optimizerCallRef: config.optimizer.callRef,
7151
7319
  compatibleRunId,
7152
7320
  runId,
7153
7321
  resumed: result.resumed,
7154
7322
  evaluationCount: runBudget.acceptedEvaluations(),
7155
7323
  artifactDir: outputDir,
7156
- ...tokenUsage ? { tokenUsage } : {}
7324
+ ...tokenUsage ? { tokenUsage } : {},
7325
+ observations: observationLog.summary(),
7326
+ modelExecutions: executionLog.summary()
7157
7327
  }
7158
7328
  };
7159
7329
  }
7160
7330
  };
7161
7331
  }
7162
7332
  //#endregion
7163
- export { campaignScenarioIdentity as $, assertOptimizationResult as A, pairedDeltaTest as At, surfaceHash as B, detectScale as C, paretoFrontier as Ct, runCanaries as D, decidePairedPromotion as Dt, pairHoldout as E, recoverTruncatedJson as Et, assertComponentSurface as F, summarizeBackendIntegrity as Ft, buildReflectionPrompt as G, campaignMeanComposite as H, codeSurfaceIdentityMaterial as I, JudgeParseError as It, runCampaign as J, parseReflectionResponse as K, componentSurfaceIdentityMaterial as L, costFromLedgerSummary as M, assertRealAgentReceipts as Mt, optimizationTokenUsageFromSummary as N, assertRealBackend as Nt, composeGate as O, pairedDecisionShape as Ot, assertCodeSurfaceIdentity as P, summarizeAgentReceiptIntegrity as Pt, assertCampaignSplitIdentity as Q, renderSurfaceDiff as R, defaultProductionGate as S, dominates as St, heldoutSignificance as T, scalarScore as Tt, compareRankKeys as U, campaignBreakdown as V, DEFAULT_MUTATION_PRIMITIVES as W, tangleTracesRoot as X, resolveRunDir as Y, assertCampaignDesign as Z, buildEvidenceVector as _, canonicalJson as _t, emitLoopProvenance as a, createReferenceEquivalenceJudge as at, powerPreflight as b, inMemoryVerdictCache as bt, provenanceRecordPath as c, redTeamDataset as ct, runImprovementLoop as d, toolNamesForRun as dt, campaignSplitDigest as et, runOptimization as f, Dataset as ft, gepaOptimizationMethod as g, cachedJudge as gt, labelTrustRank as h, llmJudge as ht, canonicalDigest as i, REFERENCE_EQUIVALENCE_JUDGE_VERSION as it, compareOptimizationMethods as j, BackendIntegrityError as jt, externalTextOptimizationMethod as k, minimumPairsForPairedDeltaTest as kt, provenanceSpansPath as l, redTeamReport as lt, isProposedCandidate as m, hashScenarios as mt, buildLoopProvenanceRecord as n, openAutoPr as nt, loopProvenanceArgsFromResult as o, runReferenceEquivalenceJudge as ot, runEval as p, HoldoutLockedError as pt, planCampaignRun as q, campaignMeasurementDigest as r, REFERENCE_EQUIVALENCE_INPUT_LIMITS as rt, loopProvenanceSpans as s, DEFAULT_RED_TEAM_CORPUS as st, skillOptOptimizationMethod as t, campaignSplitDigestFromIdentities as tt, verifyLoopProvenanceRecord as u, scoreRedTeamOutput as ut, paretoPolicy as v, contentHash as vt, dimensionRegressions as w, paretoFrontierWithCrowding as wt, heldOutGate as x, crowdingDistance as xt, paretoSignificanceGate as y, fileVerdictCache as yt, surfaceContentHash as z };
7333
+ export { assertCampaignSplitIdentity as $, assertOptimizationResult as A, summarizeAgentReceiptIntegrity as At, surfaceContentHash as B, detectScale as C, decidePairedPromotion as Ct, runCanaries as D, BackendIntegrityError as Dt, pairHoldout as E, pairedDeltaTest as Et, assertCodeSurfaceIdentity as F, DEFAULT_MUTATION_PRIMITIVES as G, campaignBreakdown as H, assertComponentSurface as I, planCampaignRun as J, buildReflectionPrompt as K, codeSurfaceIdentityMaterial as L, compareOptimizationMethods as M, JudgeParseError as Mt, costFromLedgerSummary as N, composeGate as O, assertRealAgentReceipts as Ot, optimizationTokenUsageFromSummary as P, assertCampaignDesign as Q, componentSurfaceIdentityMaterial as R, defaultProductionGate as S, recoverTruncatedJson as St, heldoutSignificance as T, minimumPairsForPairedDeltaTest as Tt, campaignMeanComposite as U, surfaceHash as V, compareRankKeys as W, resolveRunDir as X, runCampaign as Y, tangleTracesRoot as Z, buildEvidenceVector as _, crowdingDistance as _t, emitLoopProvenance as a, REFERENCE_EQUIVALENCE_JUDGE_VERSION as at, powerPreflight as b, paretoFrontierWithCrowding as bt, provenanceRecordPath as c, DEFAULT_RED_TEAM_CORPUS as ct, runImprovementLoop as d, scoreRedTeamOutput as dt, campaignScenarioIdentity as et, runOptimization as f, toolNamesForRun as ft, gepaOptimizationMethod as g, llmJudge as gt, labelTrustRank as h, hashScenarios as ht, canonicalDigest as i, REFERENCE_EQUIVALENCE_INPUT_LIMITS as it, combineComparisonCosts as j, summarizeBackendIntegrity as jt, externalTextOptimizationMethod as k, assertRealBackend as kt, provenanceSpansPath as l, redTeamDataset as lt, isProposedCandidate as m, HoldoutLockedError as mt, buildLoopProvenanceRecord as n, campaignSplitDigestFromIdentities as nt, loopProvenanceArgsFromResult as o, createReferenceEquivalenceJudge as ot, runEval as p, Dataset as pt, parseReflectionResponse as q, campaignMeasurementDigest as r, openAutoPr as rt, loopProvenanceSpans as s, runReferenceEquivalenceJudge as st, skillOptOptimizationMethod as t, campaignSplitDigest as tt, verifyLoopProvenanceRecord as u, redTeamReport as ut, paretoPolicy as v, dominates as vt, dimensionRegressions as w, pairedDecisionShape as wt, heldOutGate as x, scalarScore as xt, paretoSignificanceGate as y, paretoFrontier as yt, renderSurfaceDiff as z };
7164
7334
 
7165
- //# sourceMappingURL=skillopt-optimization-method-DV6c4ooy.js.map
7335
+ //# sourceMappingURL=skillopt-optimization-method-Ds8J1_K8.js.map