@tangle-network/agent-eval 0.126.7 → 0.127.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 (129) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +2 -2
  3. package/dist/analyst/index.d.ts +51 -39
  4. package/dist/analyst/index.js +4 -4
  5. package/dist/belief-state/index.d.ts +34 -36
  6. package/dist/belief-state/index.js +2 -2
  7. package/dist/benchmarks/index.d.ts +30 -12
  8. package/dist/benchmarks/index.js +12 -10
  9. package/dist/builder-eval/index.js +1 -1
  10. package/dist/campaign/index.d.ts +432 -146
  11. package/dist/campaign/index.js +11 -9
  12. package/dist/{chunk-ARU2PZFM.js → chunk-424XHVKV.js} +43 -23
  13. package/dist/chunk-424XHVKV.js.map +1 -0
  14. package/dist/{chunk-NUKSVU3W.js → chunk-5DTSBUL2.js} +2 -2
  15. package/dist/{chunk-BTACVO2W.js → chunk-65QETEKG.js} +542 -258
  16. package/dist/chunk-65QETEKG.js.map +1 -0
  17. package/dist/{chunk-CGG5SLH3.js → chunk-ARCFIY7U.js} +2 -2
  18. package/dist/{chunk-P22LJ3Y2.js → chunk-CLELFRQG.js} +6 -4
  19. package/dist/chunk-CLELFRQG.js.map +1 -0
  20. package/dist/{chunk-LUNF2SEL.js → chunk-DJKY2TSY.js} +3 -3
  21. package/dist/chunk-DPUHNQLN.js +232 -0
  22. package/dist/chunk-DPUHNQLN.js.map +1 -0
  23. package/dist/{chunk-IPYXE555.js → chunk-EJGRPCO3.js} +36 -13
  24. package/dist/chunk-EJGRPCO3.js.map +1 -0
  25. package/dist/{chunk-K6IAZZ6L.js → chunk-FA3MFYNA.js} +132 -110
  26. package/dist/chunk-FA3MFYNA.js.map +1 -0
  27. package/dist/chunk-IG35YDN3.js +614 -0
  28. package/dist/chunk-IG35YDN3.js.map +1 -0
  29. package/dist/{chunk-DPZAEKA6.js → chunk-IMGJZBFG.js} +84 -56
  30. package/dist/chunk-IMGJZBFG.js.map +1 -0
  31. package/dist/{chunk-H5UD2323.js → chunk-IN455XKS.js} +53 -1
  32. package/dist/chunk-IN455XKS.js.map +1 -0
  33. package/dist/{chunk-PJQFMIOX.js → chunk-MHELPNRP.js} +31 -1
  34. package/dist/chunk-MHELPNRP.js.map +1 -0
  35. package/dist/{chunk-IILEIWGW.js → chunk-NL33OXEP.js} +41 -36
  36. package/dist/chunk-NL33OXEP.js.map +1 -0
  37. package/dist/{chunk-474LBSOX.js → chunk-OD5NQ2CS.js} +41 -16
  38. package/dist/chunk-OD5NQ2CS.js.map +1 -0
  39. package/dist/{chunk-QOTFXW5L.js → chunk-P5W7RQKK.js} +2 -2
  40. package/dist/{chunk-IR3KBHOY.js → chunk-P6FYH6K4.js} +39 -3
  41. package/dist/chunk-P6FYH6K4.js.map +1 -0
  42. package/dist/{chunk-J5SQWP6Y.js → chunk-PBE2LOSS.js} +18 -2
  43. package/dist/chunk-PBE2LOSS.js.map +1 -0
  44. package/dist/{chunk-E3IADPLG.js → chunk-PRB53E3J.js} +50 -224
  45. package/dist/chunk-PRB53E3J.js.map +1 -0
  46. package/dist/{chunk-X4UCIOTZ.js → chunk-S5YLIBFX.js} +2 -2
  47. package/dist/{chunk-7VYEGHWF.js → chunk-SZLVEKMJ.js} +41 -20
  48. package/dist/chunk-SZLVEKMJ.js.map +1 -0
  49. package/dist/{chunk-LKKT3IVV.js → chunk-TSN7JT6D.js} +6 -4
  50. package/dist/{chunk-LKKT3IVV.js.map → chunk-TSN7JT6D.js.map} +1 -1
  51. package/dist/{chunk-M7AH34KV.js → chunk-UTA2TGC4.js} +32 -16
  52. package/dist/chunk-UTA2TGC4.js.map +1 -0
  53. package/dist/{chunk-MAX3TN3C.js → chunk-UWZZKKU7.js} +7 -19
  54. package/dist/chunk-UWZZKKU7.js.map +1 -0
  55. package/dist/{chunk-ZVCHKKOP.js → chunk-WED5KLZQ.js} +39 -15
  56. package/dist/chunk-WED5KLZQ.js.map +1 -0
  57. package/dist/{chunk-OCFJACJU.js → chunk-X6VOPMLD.js} +74 -14
  58. package/dist/chunk-X6VOPMLD.js.map +1 -0
  59. package/dist/{chunk-MOXWMGPC.js → chunk-Y5CYOL42.js} +159 -70
  60. package/dist/chunk-Y5CYOL42.js.map +1 -0
  61. package/dist/{chunk-FO7HEH76.js → chunk-YJBNWCAA.js} +2 -2
  62. package/dist/chunk-ZPUEEM5U.js +179 -0
  63. package/dist/chunk-ZPUEEM5U.js.map +1 -0
  64. package/dist/{chunk-KE2VWPZX.js → chunk-ZUUWPZCV.js} +3 -3
  65. package/dist/cli.js +4 -4
  66. package/dist/contract/index.d.ts +421 -124
  67. package/dist/contract/index.js +242 -115
  68. package/dist/contract/index.js.map +1 -1
  69. package/dist/control.d.ts +34 -32
  70. package/dist/control.js +2 -2
  71. package/dist/hosted/index.d.ts +142 -41
  72. package/dist/hosted/index.js +23 -1
  73. package/dist/index.d.ts +364 -255
  74. package/dist/index.js +315 -226
  75. package/dist/index.js.map +1 -1
  76. package/dist/meta-eval/index.d.ts +32 -32
  77. package/dist/meta-eval/index.js +2 -2
  78. package/dist/multishot/index.d.ts +1 -0
  79. package/dist/openapi.json +1 -1
  80. package/dist/pipelines/index.js +2 -2
  81. package/dist/reporting.d.ts +97 -74
  82. package/dist/reporting.js +5 -4
  83. package/dist/rl.d.ts +177 -131
  84. package/dist/rl.js +232 -126
  85. package/dist/rl.js.map +1 -1
  86. package/dist/rollout/index.d.ts +53 -63
  87. package/dist/rollout/index.js +7 -5
  88. package/dist/{run-campaign-FFRM3RH5.js → run-campaign-3A2EBYBE.js} +4 -3
  89. package/dist/supervisor-run/index.d.ts +7 -15
  90. package/dist/supervisor-run/index.js +2 -2
  91. package/dist/traces.d.ts +66 -41
  92. package/dist/traces.js +9 -5
  93. package/dist/wire/index.d.ts +1 -0
  94. package/dist/wire/index.js +2 -2
  95. package/docs/concepts.md +18 -1
  96. package/docs/hosted-ingest-spec.md +37 -40
  97. package/docs/insight-report.md +57 -7
  98. package/docs/research-report-methodology.md +20 -21
  99. package/docs/rollout.md +13 -8
  100. package/package.json +4 -3
  101. package/dist/chunk-474LBSOX.js.map +0 -1
  102. package/dist/chunk-7VYEGHWF.js.map +0 -1
  103. package/dist/chunk-ARU2PZFM.js.map +0 -1
  104. package/dist/chunk-BTACVO2W.js.map +0 -1
  105. package/dist/chunk-DPZAEKA6.js.map +0 -1
  106. package/dist/chunk-E3IADPLG.js.map +0 -1
  107. package/dist/chunk-H5UD2323.js.map +0 -1
  108. package/dist/chunk-IILEIWGW.js.map +0 -1
  109. package/dist/chunk-IPYXE555.js.map +0 -1
  110. package/dist/chunk-IR3KBHOY.js.map +0 -1
  111. package/dist/chunk-J5SQWP6Y.js.map +0 -1
  112. package/dist/chunk-K6IAZZ6L.js.map +0 -1
  113. package/dist/chunk-M7AH34KV.js.map +0 -1
  114. package/dist/chunk-MAX3TN3C.js.map +0 -1
  115. package/dist/chunk-MOXWMGPC.js.map +0 -1
  116. package/dist/chunk-OCFJACJU.js.map +0 -1
  117. package/dist/chunk-P22LJ3Y2.js.map +0 -1
  118. package/dist/chunk-PJQFMIOX.js.map +0 -1
  119. package/dist/chunk-ZVCHKKOP.js.map +0 -1
  120. package/dist/chunk-ZZUXHH3R.js +0 -99
  121. package/dist/chunk-ZZUXHH3R.js.map +0 -1
  122. /package/dist/{chunk-NUKSVU3W.js.map → chunk-5DTSBUL2.js.map} +0 -0
  123. /package/dist/{chunk-CGG5SLH3.js.map → chunk-ARCFIY7U.js.map} +0 -0
  124. /package/dist/{chunk-LUNF2SEL.js.map → chunk-DJKY2TSY.js.map} +0 -0
  125. /package/dist/{chunk-QOTFXW5L.js.map → chunk-P5W7RQKK.js.map} +0 -0
  126. /package/dist/{chunk-X4UCIOTZ.js.map → chunk-S5YLIBFX.js.map} +0 -0
  127. /package/dist/{chunk-FO7HEH76.js.map → chunk-YJBNWCAA.js.map} +0 -0
  128. /package/dist/{chunk-KE2VWPZX.js.map → chunk-ZUUWPZCV.js.map} +0 -0
  129. /package/dist/{run-campaign-FFRM3RH5.js.map → run-campaign-3A2EBYBE.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,50 @@ All notable changes to `@tangle-network/agent-eval` and its sibling `agent-eval-
4
4
 
5
5
  ---
6
6
 
7
+ ## [0.127.0] - 2026-07-25 - explicit run evidence and truthful release checks
8
+
9
+ ### Changed
10
+
11
+ - Execution reports now separate runs with execution errors from explicit terminal outcomes.
12
+ - `RunRecord` now requires `scenarioId`, `terminalOutcome`, and `costProvenance`.
13
+ - Uncaptured cost is represented as `costUsd: null` with `{ kind: 'uncaptured', usd: null }`; it is never converted to zero.
14
+ - `ExecutionInsight.failures` is replaced by `executionErrors` and `terminalOutcomes`; report renderers must label these independently.
15
+ - `RunRecord.terminalOutcome` records `succeeded`, `failed`, `cancelled`, `incomplete`, or `unknown` only from root-run or process evidence.
16
+ - `executionErrors.byTerminalOutcome` cross-tabulates reported errors, reported zeroes, and missing error telemetry without asserting recovery causality.
17
+ - `executionErrors.fraction` is `null` when no run supplies error telemetry instead of reporting a false zero rate.
18
+ - OTel and code-agent intake count tool, model, and child-agent failures as execution errors while keeping process, guardrail, evaluator, propagated parent, and unknown errors in separate raw counters.
19
+ - OTel trace analysis preserves `EVALUATOR` as a distinct span kind instead of reducing it to `UNKNOWN`.
20
+ - Execution-only `RunRecord` rows may omit both task scores; OTel and code-agent intake no longer derive task quality from internal errors or process telemetry.
21
+ - Rollout, RL corpus, product-benchmark, and release-confidence paths no longer convert missing task scores into zero-quality labels.
22
+ - Held-out promotion now rejects missing search or holdout evidence explicitly, and public statistics use `null` instead of fake zero or `NaN` values when no measurement exists.
23
+ - Run comparisons now pair only on `(experimentId, scenarioId, seed)`, reject missing or duplicate identities, report unmatched rows, and never fall back to input order.
24
+ - Trace ranking ignores unlabeled execution rows without dropping them from storage.
25
+ - `MultiLayerVerifier.taskScore` is present only for a complete scoring panel; partial blends remain diagnostic, and errored or timed-out layers cannot become task or training labels.
26
+ - RL exports require trainable rows: SFT is the safe default, GRPO must be requested and needs at least two rewarded completions per group, unscored trajectories require explicit SFT opt-in, and requested empty formats fail loudly.
27
+ - RL and rollout training exports use only the `search` split by default.
28
+ - `dev` remains evaluation-only, and held-out training requires `allowHeldOutTrainingData: true`.
29
+ - Minted rollout terminal fields now reflect `RunRecord.terminalOutcome`, and SFT excludes failed, cancelled, incomplete, and unknown-terminal runs.
30
+ - Release confidence reports quality and reliability separately; terminal process failure no longer becomes a low task-quality score, and missing measurements remain `null`.
31
+ - Cost-bounded held-out and release decisions reject incomplete cost evidence instead of treating uncaptured cost as zero.
32
+ - Release confidence uses run rows as the primary source for cost, latency, and pass rate, avoiding duplicate aggregation from trace summaries.
33
+ - Campaign, profile-matrix, and self-improvement projections now share one mapper that records explicit terminal outcomes, execution-error counts, actual token usage, and unlabeled error cells.
34
+ - Hosted campaign snapshots omit failed judge dimensions rather than publishing invalid values.
35
+ - Hosted clients and the reference receiver validate complete request payloads, reject header/body version disagreement, scope retry keys by endpoint, and merge incremental generation snapshots without losing earlier generations.
36
+ - Hosted trace timestamps are exact base-10 strings so JSON cannot truncate OTLP nanoseconds.
37
+ - Rollout rows require experiment and candidate keys plus `outcome.realness_gated`; the obsolete `train` split and `ROLLOUT_FORMAT` alias were removed.
38
+ - Paired reports use within-pair Cohen's dz and paired sample-size calculations.
39
+ - Hosted ingest now emits wire version `2026-07-24.v1`; cells carry terminal outcomes and execution-error counts, missing task scores are `null`, and old aggregate reports must be recomputed from their original run rows because the former mixed failure count cannot be migrated losslessly.
40
+ - `GateResult.contributingGates` now records `pass`, `fail`, or `not_evaluated` instead of a boolean that could not distinguish missing evidence from failure.
41
+ - `defaultProductionGate` enables reward-hacking and canary monitoring independently through `rewardHacking` and `canary`.
42
+ - Canary reports identify which enabled detectors had enough observations to run.
43
+ - Loop provenance rejects obsolete boolean contributions instead of accepting a record whose runtime shape contradicts its TypeScript type.
44
+
45
+ ### Fixed
46
+
47
+ - Missing or insufficient evidence remains `not_evaluated`; required unevaluated checks hold the release decision separately.
48
+ - Valid run histories without independent truth observations or usable canary metadata cannot produce successful monitoring checks.
49
+ - Empty critical-dimension configuration, incomplete cost accounting, unsupported red-team cases, and missing held-out evidence hold without being mislabeled as evaluated failures.
50
+
7
51
  ## [0.126.7] - 2026-07-24 - dependency security refresh
8
52
 
9
53
  ### Changed
package/README.md CHANGED
@@ -349,8 +349,8 @@ See [concepts](./docs/concepts.md), [customer paths](./docs/customer-journeys.md
349
349
  | `@tangle-network/agent-eval/rl` | Export rewards, preferences, and training rows. |
350
350
  | `@tangle-network/agent-eval/wire` | HTTP and RPC schemas for other languages. |
351
351
 
352
- Prefer these subpaths for new code.
353
- The root export remains broad for compatibility.
352
+ Use subpaths when you want an explicit capability boundary.
353
+ Use the root import for common primitives.
354
354
 
355
355
  ## Examples
356
356
 
@@ -78,6 +78,8 @@ interface Finding {
78
78
  interface LayerResult {
79
79
  layer: string;
80
80
  status: LayerStatus;
81
+ /** Origin of an `error` or `timeout`. Defaults to `execution`. */
82
+ errorSource?: 'execution' | 'judge';
81
83
  /** 0..1 score, optional — layers that don't produce a numeric score omit. */
82
84
  score?: number;
83
85
  durationMs: number;
@@ -106,6 +108,8 @@ interface VerifyContext<Env = unknown> {
106
108
  }
107
109
  interface Layer<Env = unknown> {
108
110
  name: string;
111
+ /** Origin assigned when this layer errors or times out. Defaults to `execution`. */
112
+ errorSource?: 'execution' | 'judge';
109
113
  /** Stages that must have `status: 'pass'` before this layer runs. */
110
114
  dependsOn?: string[];
111
115
  /**
@@ -133,22 +137,29 @@ interface VerifyOptions<Env = unknown> {
133
137
  /** Called with each layer result as it completes. */
134
138
  onLayer?: (result: LayerResult) => void;
135
139
  }
136
- /** Extends the substrate verdict spine: `valid` = `allPass` and `score` =
137
- * `blendedScore` derived where the report is aggregated, so spine
138
- * consumers (drivers, gates) read this report without an adapter. */
140
+ /** Extends the substrate verdict spine: `valid` = `allPass`; `score` is the
141
+ * complete task score or 0 when the configured scoring panel was incomplete. */
139
142
  interface VerificationReport extends DefaultVerdict {
140
143
  layers: LayerResult[];
141
144
  passCount: number;
142
145
  failCount: number;
143
146
  skippedCount: number;
144
147
  errorCount: number;
145
- /** True iff at least one scored layer ran AND every scored layer passed. */
148
+ /** True iff the configured scoring panel completed and every layer passed. */
146
149
  allPass: boolean;
147
150
  /**
148
- * Weighted mean of `score` across contributing layers. 0 when no layers
149
- * contributed. See {@link Layer.failContributesToScore} for fail semantics.
151
+ * Diagnostic weighted mean across contributing layers. This may represent a
152
+ * partial panel. It is 0 when no layer contributed.
150
153
  */
151
154
  blendedScore: number;
155
+ /**
156
+ * Complete task-quality measurement.
157
+ * Present when at least one layer produced a valid score, every other layer
158
+ * completed successfully or contributed an explicit scored failure, and no
159
+ * result is missing because of a failure, skip, error, or timeout.
160
+ * Use this field, not `blendedScore`, when creating task labels.
161
+ */
162
+ taskScore?: number;
152
163
  durationMs: number;
153
164
  startedAt: string;
154
165
  finishedAt: string;
@@ -406,7 +417,8 @@ type FailureClass = 'success' | 'reasoning_error' | 'tool_selection_error' | 'to
406
417
  * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory
407
418
  * fields are exactly those the paper "Two Loops, Three Roles" requires
408
419
  * for reproducibility: who/what/when/cost/seed/hash, plus the search vs
409
- * holdout split tag and either a `searchScore` or a `holdoutScore`.
420
+ * holdout split tag. A task score is optional because execution-only records
421
+ * must preserve missing labels instead of converting errors into zero quality.
410
422
  *
411
423
  * This is intentionally NOT a replacement for the rich `Run` /
412
424
  * `ProposeReviewReport` / `ScenarioResult` types already in the
@@ -427,6 +439,13 @@ type FailureClass = 'success' | 'reasoning_error' | 'tool_selection_error' | 'to
427
439
  /** Search/dev/holdout split tag. 'search' is the paper-grade alias for the
428
440
  * combined train+test pool that the optimizer is allowed to read. */
429
441
  type RunSplitTag = 'search' | 'dev' | 'holdout';
442
+ /**
443
+ * Explicit execution-lifecycle result for a run.
444
+ *
445
+ * This is separate from task quality (`outcome`) and failure classification.
446
+ * Producers set it only from root-run or process evidence.
447
+ */
448
+ type RunTerminalOutcome = 'succeeded' | 'failed' | 'cancelled' | 'incomplete' | 'unknown';
430
449
  interface RunTokenUsage {
431
450
  input: number;
432
451
  /** All generated tokens charged as output, including reasoning tokens. */
@@ -440,11 +459,6 @@ interface RunTokenUsage {
440
459
  }
441
460
  /**
442
461
  * How a run's USD amount was obtained.
443
- *
444
- * `costUsd` remains mandatory for wire compatibility. New producers should
445
- * always populate this discriminated union so a missing bill is never
446
- * mistaken for an observed zero-dollar run. For `uncaptured`, `costUsd` uses
447
- * the legacy `0` sentinel while this field carries the truthful null.
448
462
  */
449
463
  type RunCostProvenance = {
450
464
  kind: 'observed';
@@ -490,8 +504,8 @@ interface JudgeScoresRecord {
490
504
  perJudge: Record<string, Record<string, number>>;
491
505
  /** Per-dim mean across judges. Convenience — derivable from `perJudge`. */
492
506
  perDimMean: Record<string, number>;
493
- /** Composite mean across all dims and judges. Mirrors the score
494
- * the gate sees on `outcome.searchScore` / `holdoutScore`. */
507
+ /** Composite mean across successful judges. Mirrors the task score only
508
+ * when `failedJudges` is empty. */
495
509
  composite: number;
496
510
  /** Judges that errored or returned an unparseable verdict. Recorded
497
511
  * by id (e.g. `['glm-5.1']`) so a partial-failure case is explicit,
@@ -502,11 +516,11 @@ interface JudgeScoresRecord {
502
516
  notes?: string;
503
517
  }
504
518
  interface RunOutcome {
505
- /** Score on the search/optimization split. Optional because a
506
- * holdout-only evaluation only fills `holdoutScore`. */
519
+ /** Score on the search/optimization split. Optional for holdout-only and
520
+ * execution-only records. */
507
521
  searchScore?: number;
508
- /** Score on the held-out split. Optional because a search-only run
509
- * only fills `searchScore`. At least one must be present. */
522
+ /** Score on the held-out split. Optional for search-only and execution-only
523
+ * records. When both scores are absent, the run is explicitly unlabeled. */
510
524
  holdoutScore?: number;
511
525
  /** Bag of any other metric the run produced — judge dimensions,
512
526
  * pass/fail counters, latency stats, etc. Numeric only — keeps
@@ -570,42 +584,39 @@ interface RunRecord {
570
584
  wallMs: number;
571
585
  /** Time spent queued before execution started, if known. */
572
586
  queueMs?: number;
573
- /** Total USD cost. Mandatory runs without a cost number are
574
- * unbounded by definition and must not be admitted into the gate.
575
- * `0` is retained as the compatibility sentinel for an uncaptured amount;
576
- * inspect `costProvenance` before treating it as observed. */
577
- costUsd: number;
578
- /** Observed, model-priced estimate, or genuinely uncaptured USD amount.
579
- * Optional only so existing serialized RunRecords remain valid. */
580
- costProvenance?: RunCostProvenance;
587
+ /** Total USD cost, or null when the producer could not capture one. */
588
+ costUsd: number | null;
589
+ /** Whether `costUsd` came from billing data, a price calculation, or is unavailable. */
590
+ costProvenance: RunCostProvenance;
581
591
  /** Token usage breakdown. */
582
592
  tokenUsage: RunTokenUsage;
593
+ /** Root-run or process terminal result. Never inferred from a child span. */
594
+ terminalOutcome: RunTerminalOutcome;
595
+ /** Root-run or process failure reason. Valid only for a failed, cancelled,
596
+ * or incomplete terminal result; never populated from a child span. */
597
+ terminalFailureReason?: string;
583
598
  /** Judge-side metadata, if a judge was used. */
584
599
  judgeMetadata?: RunJudgeMetadata;
585
600
  /** Per-split scores + raw bag. */
586
601
  outcome: RunOutcome;
587
- /** Canonical, cross-agent failure class drawn from the shared
602
+ /** Canonical task-failure class drawn from the shared
588
603
  * `FAILURE_CLASSES` taxonomy. This is the aggregation key that makes
589
604
  * "which failure dominates across the whole fleet" answerable in ONE
590
605
  * vocabulary — every agent classifies against the same enum. Producers
591
- * set it via the substrate classifier; leave unset only when the failure
592
- * genuinely can't be classified. */
606
+ * set it only from task-result evidence. Execution errors belong in
607
+ * `outcome.raw.execution_error_count`, even when the run later fails. */
593
608
  failureClass?: FailureClass;
594
- /** Free-form domain-specific failure detail, scoped UNDER `failureClass`
609
+ /** Free-form task-failure detail, scoped UNDER `failureClass`
595
610
  * (e.g. failureClass='tool_recovery_failure', failureMode='forge_build_unsatisfied').
596
- * The within-agent drill-down; `failureClass` is the cross-agent key. */
611
+ * Do not populate this from a child execution error alone. */
597
612
  failureMode?: string;
598
613
  /** Which split this run was drawn from. */
599
614
  splitTag: RunSplitTag;
600
615
  /**
601
- * Stable scenario identifier the run was scored against. Optional for
602
- * backwards compatibility, but **strongly recommended**: every primitive
603
- * that pairs runs by scenario (preferences, paired stats, BT tournament)
604
- * keys on this. The campaign artifact populates it canonically; legacy
605
- * runs without it fall back to inference from `outcome.raw.scenario_id`
606
- * or `experimentId`.
616
+ * Stable scenario identifier the run observed or was scored against.
617
+ * Comparison primitives match this identity rather than input order.
607
618
  */
608
- scenarioId?: string;
619
+ scenarioId: string;
609
620
  /**
610
621
  * Canonical identity for the agent profile cell that produced this row:
611
622
  * profile artifact hash plus optional harness/model/prompt/reporting
@@ -963,6 +974,7 @@ type CostLedgerHandle = Pick<CostLedger, Exclude<keyof CostLedger, 'listPending'
963
974
  * OpenAI-compatible `/v1/chat/completions` client with:
964
975
  * - Exponential-backoff retry on 429 + 5xx gateway errors (502/503/504).
965
976
  * - Retry on transient network errors (fetch failed, AbortError, ECONNRESET).
977
+ * - One retry at temperature 1 when a model explicitly requires it.
966
978
  * - Graceful json_schema → json_object degrade on 400 with schema-reject body.
967
979
  * - Fenced-JSON stripping (```json ... ```) for models that wrap structured output.
968
980
  * - Configurable base URL + api key / bearer, works with LiteLLM proxies, OpenAI
@@ -1320,7 +1332,7 @@ type JudgeFn = (tc: TCloud, input: JudgeInput) => Promise<JudgeScore[]>;
1320
1332
  * `ViewTraceOversized`.
1321
1333
  */
1322
1334
  /** OTLP span kind (subset we actually use). */
1323
- type TraceAnalystSpanKind = 'AGENT' | 'LLM' | 'TOOL' | 'CHAIN' | 'GUARDRAIL' | 'SPAN' | 'UNKNOWN';
1335
+ type TraceAnalystSpanKind = 'AGENT' | 'LLM' | 'TOOL' | 'CHAIN' | 'EVALUATOR' | 'GUARDRAIL' | 'SPAN' | 'UNKNOWN';
1324
1336
  type TraceAnalystSpanStatus = 'OK' | 'ERROR' | 'UNSET';
1325
1337
  /** Subset of OTLP span fields the analyst exposes to the agent. The
1326
1338
  * store's job is to project upstream's full span shape down to this
@@ -9,7 +9,7 @@ import {
9
9
  diffFindings,
10
10
  emitSkillUsageFindings,
11
11
  runSemanticConceptJudge
12
- } from "../chunk-KE2VWPZX.js";
12
+ } from "../chunk-ZUUWPZCV.js";
13
13
  import {
14
14
  ANALYST_SEVERITIES,
15
15
  AnalystRegistry,
@@ -50,15 +50,15 @@ import {
50
50
  stripCodeFences,
51
51
  structureFindings,
52
52
  validateUsageSettlementTimeout
53
- } from "../chunk-LUNF2SEL.js";
53
+ } from "../chunk-DJKY2TSY.js";
54
54
  import "../chunk-HHWE3POT.js";
55
55
  import "../chunk-WGXIEX7P.js";
56
- import "../chunk-J5SQWP6Y.js";
56
+ import "../chunk-PBE2LOSS.js";
57
57
  import {
58
58
  CostLedger
59
59
  } from "../chunk-WS3NZZQQ.js";
60
60
  import "../chunk-VI2UW6B6.js";
61
- import "../chunk-IR3KBHOY.js";
61
+ import "../chunk-P6FYH6K4.js";
62
62
  import "../chunk-PC4UYEBM.js";
63
63
  import "../chunk-ONWEPEDO.js";
64
64
  import "../chunk-K4DBDHLK.js";
@@ -617,7 +617,8 @@ interface AgentProfileCell {
617
617
  * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory
618
618
  * fields are exactly those the paper "Two Loops, Three Roles" requires
619
619
  * for reproducibility: who/what/when/cost/seed/hash, plus the search vs
620
- * holdout split tag and either a `searchScore` or a `holdoutScore`.
620
+ * holdout split tag. A task score is optional because execution-only records
621
+ * must preserve missing labels instead of converting errors into zero quality.
621
622
  *
622
623
  * This is intentionally NOT a replacement for the rich `Run` /
623
624
  * `ProposeReviewReport` / `ScenarioResult` types already in the
@@ -638,6 +639,13 @@ interface AgentProfileCell {
638
639
  /** Search/dev/holdout split tag. 'search' is the paper-grade alias for the
639
640
  * combined train+test pool that the optimizer is allowed to read. */
640
641
  type RunSplitTag = 'search' | 'dev' | 'holdout';
642
+ /**
643
+ * Explicit execution-lifecycle result for a run.
644
+ *
645
+ * This is separate from task quality (`outcome`) and failure classification.
646
+ * Producers set it only from root-run or process evidence.
647
+ */
648
+ type RunTerminalOutcome = 'succeeded' | 'failed' | 'cancelled' | 'incomplete' | 'unknown';
641
649
  interface RunTokenUsage {
642
650
  input: number;
643
651
  /** All generated tokens charged as output, including reasoning tokens. */
@@ -651,11 +659,6 @@ interface RunTokenUsage {
651
659
  }
652
660
  /**
653
661
  * How a run's USD amount was obtained.
654
- *
655
- * `costUsd` remains mandatory for wire compatibility. New producers should
656
- * always populate this discriminated union so a missing bill is never
657
- * mistaken for an observed zero-dollar run. For `uncaptured`, `costUsd` uses
658
- * the legacy `0` sentinel while this field carries the truthful null.
659
662
  */
660
663
  type RunCostProvenance = {
661
664
  kind: 'observed';
@@ -701,8 +704,8 @@ interface JudgeScoresRecord {
701
704
  perJudge: Record<string, Record<string, number>>;
702
705
  /** Per-dim mean across judges. Convenience — derivable from `perJudge`. */
703
706
  perDimMean: Record<string, number>;
704
- /** Composite mean across all dims and judges. Mirrors the score
705
- * the gate sees on `outcome.searchScore` / `holdoutScore`. */
707
+ /** Composite mean across successful judges. Mirrors the task score only
708
+ * when `failedJudges` is empty. */
706
709
  composite: number;
707
710
  /** Judges that errored or returned an unparseable verdict. Recorded
708
711
  * by id (e.g. `['glm-5.1']`) so a partial-failure case is explicit,
@@ -713,11 +716,11 @@ interface JudgeScoresRecord {
713
716
  notes?: string;
714
717
  }
715
718
  interface RunOutcome {
716
- /** Score on the search/optimization split. Optional because a
717
- * holdout-only evaluation only fills `holdoutScore`. */
719
+ /** Score on the search/optimization split. Optional for holdout-only and
720
+ * execution-only records. */
718
721
  searchScore?: number;
719
- /** Score on the held-out split. Optional because a search-only run
720
- * only fills `searchScore`. At least one must be present. */
722
+ /** Score on the held-out split. Optional for search-only and execution-only
723
+ * records. When both scores are absent, the run is explicitly unlabeled. */
721
724
  holdoutScore?: number;
722
725
  /** Bag of any other metric the run produced — judge dimensions,
723
726
  * pass/fail counters, latency stats, etc. Numeric only — keeps
@@ -781,42 +784,39 @@ interface RunRecord {
781
784
  wallMs: number;
782
785
  /** Time spent queued before execution started, if known. */
783
786
  queueMs?: number;
784
- /** Total USD cost. Mandatory runs without a cost number are
785
- * unbounded by definition and must not be admitted into the gate.
786
- * `0` is retained as the compatibility sentinel for an uncaptured amount;
787
- * inspect `costProvenance` before treating it as observed. */
788
- costUsd: number;
789
- /** Observed, model-priced estimate, or genuinely uncaptured USD amount.
790
- * Optional only so existing serialized RunRecords remain valid. */
791
- costProvenance?: RunCostProvenance;
787
+ /** Total USD cost, or null when the producer could not capture one. */
788
+ costUsd: number | null;
789
+ /** Whether `costUsd` came from billing data, a price calculation, or is unavailable. */
790
+ costProvenance: RunCostProvenance;
792
791
  /** Token usage breakdown. */
793
792
  tokenUsage: RunTokenUsage;
793
+ /** Root-run or process terminal result. Never inferred from a child span. */
794
+ terminalOutcome: RunTerminalOutcome;
795
+ /** Root-run or process failure reason. Valid only for a failed, cancelled,
796
+ * or incomplete terminal result; never populated from a child span. */
797
+ terminalFailureReason?: string;
794
798
  /** Judge-side metadata, if a judge was used. */
795
799
  judgeMetadata?: RunJudgeMetadata;
796
800
  /** Per-split scores + raw bag. */
797
801
  outcome: RunOutcome;
798
- /** Canonical, cross-agent failure class drawn from the shared
802
+ /** Canonical task-failure class drawn from the shared
799
803
  * `FAILURE_CLASSES` taxonomy. This is the aggregation key that makes
800
804
  * "which failure dominates across the whole fleet" answerable in ONE
801
805
  * vocabulary — every agent classifies against the same enum. Producers
802
- * set it via the substrate classifier; leave unset only when the failure
803
- * genuinely can't be classified. */
806
+ * set it only from task-result evidence. Execution errors belong in
807
+ * `outcome.raw.execution_error_count`, even when the run later fails. */
804
808
  failureClass?: FailureClass;
805
- /** Free-form domain-specific failure detail, scoped UNDER `failureClass`
809
+ /** Free-form task-failure detail, scoped UNDER `failureClass`
806
810
  * (e.g. failureClass='tool_recovery_failure', failureMode='forge_build_unsatisfied').
807
- * The within-agent drill-down; `failureClass` is the cross-agent key. */
811
+ * Do not populate this from a child execution error alone. */
808
812
  failureMode?: string;
809
813
  /** Which split this run was drawn from. */
810
814
  splitTag: RunSplitTag;
811
815
  /**
812
- * Stable scenario identifier the run was scored against. Optional for
813
- * backwards compatibility, but **strongly recommended**: every primitive
814
- * that pairs runs by scenario (preferences, paired stats, BT tournament)
815
- * keys on this. The campaign artifact populates it canonically; legacy
816
- * runs without it fall back to inference from `outcome.raw.scenario_id`
817
- * or `experimentId`.
816
+ * Stable scenario identifier the run observed or was scored against.
817
+ * Comparison primitives match this identity rather than input order.
818
818
  */
819
- scenarioId?: string;
819
+ scenarioId: string;
820
820
  /**
821
821
  * Canonical identity for the agent profile cell that produced this row:
822
822
  * profile artifact hash plus optional harness/model/prompt/reporting
@@ -867,6 +867,7 @@ interface CodeAgentSessionMetrics {
867
867
  toolCalls: number;
868
868
  toolOutputs: number;
869
869
  toolErrors: number;
870
+ unclassifiedErrors: number;
870
871
  patchAttempts: number;
871
872
  patchSuccesses: number;
872
873
  patchFailures: number;
@@ -905,7 +906,6 @@ interface CodeAgentSessionDiagnostic {
905
906
  sourcePath?: string;
906
907
  entries: number;
907
908
  malformedLines: number;
908
- inferredScore: boolean;
909
909
  hasExplicitTerminalSignal: boolean;
910
910
  hasFinalOutput: boolean;
911
911
  hasQualityLabel: boolean;
@@ -928,9 +928,7 @@ interface CodeAgentSessionIntakeOptions {
928
928
  configHash?: string;
929
929
  commitSha?: string;
930
930
  score?: number;
931
- /** Explicit cost receipt. Use `uncaptured` when the source says dollars
932
- * were not captured; the adapter will not relabel its compatibility $0
933
- * sentinel as observed. When omitted, source-reported cost wins, then a
931
+ /** Explicit cost receipt. When omitted, source-reported cost wins, then a
934
932
  * token-priced estimate, then uncaptured. */
935
933
  costProvenance?: RunCostProvenance;
936
934
  /** Exact executor-owned process result. This is required when a provider's
@@ -5,7 +5,7 @@ import {
5
5
  fromOpenCodeSession,
6
6
  fromPiSession,
7
7
  observeCodeAgentSession
8
- } from "../chunk-7VYEGHWF.js";
8
+ } from "../chunk-SZLVEKMJ.js";
9
9
  import {
10
10
  calibrationFromPairs
11
11
  } from "../chunk-NPCTHQIO.js";
@@ -17,7 +17,7 @@ import {
17
17
  } from "../chunk-VGRCHJON.js";
18
18
  import {
19
19
  confidenceInterval
20
- } from "../chunk-PJQFMIOX.js";
20
+ } from "../chunk-MHELPNRP.js";
21
21
  import "../chunk-VI2UW6B6.js";
22
22
  import "../chunk-PXE2VKMX.js";
23
23
  import {
@@ -125,6 +125,7 @@ interface CostLedgerSummary {
125
125
  * OpenAI-compatible `/v1/chat/completions` client with:
126
126
  * - Exponential-backoff retry on 429 + 5xx gateway errors (502/503/504).
127
127
  * - Retry on transient network errors (fetch failed, AbortError, ECONNRESET).
128
+ * - One retry at temperature 1 when a model explicitly requires it.
128
129
  * - Graceful json_schema → json_object degrade on 400 with schema-reject body.
129
130
  * - Fenced-JSON stripping (```json ... ```) for models that wrap structured output.
130
131
  * - Configurable base URL + api key / bearer, works with LiteLLM proxies, OpenAI
@@ -193,7 +194,8 @@ type LlmCallMetadata = Pick<LlmCallResult, 'usage' | 'costUsd' | 'model' | 'dura
193
194
  * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory
194
195
  * fields are exactly those the paper "Two Loops, Three Roles" requires
195
196
  * for reproducibility: who/what/when/cost/seed/hash, plus the search vs
196
- * holdout split tag and either a `searchScore` or a `holdoutScore`.
197
+ * holdout split tag. A task score is optional because execution-only records
198
+ * must preserve missing labels instead of converting errors into zero quality.
197
199
  *
198
200
  * This is intentionally NOT a replacement for the rich `Run` /
199
201
  * `ProposeReviewReport` / `ScenarioResult` types already in the
@@ -314,14 +316,17 @@ interface JudgeScore {
314
316
  }
315
317
  /** Five-valued verdict taxonomy (MOSS-paper alignment). */
316
318
  type GateDecision = 'ship' | 'hold' | 'need_more_work' | 'model_ceiling' | 'arch_ceiling';
319
+ /** Outcome of one check that contributed to a release decision. */
320
+ type GateCheckStatus = 'pass' | 'fail' | 'not_evaluated';
321
+ interface GateContribution {
322
+ name: string;
323
+ status: GateCheckStatus;
324
+ detail: unknown;
325
+ }
317
326
  interface GateResult {
318
327
  decision: GateDecision;
319
328
  reasons: string[];
320
- contributingGates: Array<{
321
- name: string;
322
- passed: boolean;
323
- detail: unknown;
324
- }>;
329
+ contributingGates: GateContribution[];
325
330
  delta?: number;
326
331
  }
327
332
  /** Scoped trace writer handed to each dispatch — every span
@@ -380,6 +385,10 @@ interface CampaignCellResult<TArtifact> {
380
385
  durationMs: number;
381
386
  seed: number;
382
387
  cached: boolean;
388
+ /** Stage that produced `error`. Missing on successful cells. */
389
+ errorStage?: 'dispatch' | 'judge';
390
+ /** Judge that threw when `errorStage` is `judge`. */
391
+ errorJudge?: string;
383
392
  error?: string;
384
393
  }
385
394
  interface JudgeAggregate {
@@ -404,8 +413,10 @@ interface GenerationRecord {
404
413
  * handled — the evidence a blind `Mutator` cannot see. */
405
414
  interface GenerationCandidate {
406
415
  surfaceHash: string;
407
- composite: number;
408
- ci95: [number, number];
416
+ /** Mean over complete task-quality scores, or null when none were produced. */
417
+ composite: number | null;
418
+ /** Descriptive interval for `composite`, or null when no score exists. */
419
+ ci95: [number, number] | null;
409
420
  /** Exact surface this candidate mutated. */
410
421
  parentSurfaceHash?: string;
411
422
  /** Measured search-split composite of the exact parent surface. */
@@ -415,13 +426,12 @@ interface GenerationCandidate {
415
426
  observedDeltaFromParent?: number;
416
427
  /** Whether this candidate had a scorable result for every designed campaign
417
428
  * cell and was therefore eligible for ranking, promotion, and Pareto
418
- * selection. Older externally-authored records may omit this field; loop
419
- * records always populate it. */
420
- eligibleForPromotion?: boolean;
429
+ * selection. */
430
+ eligibleForPromotion: boolean;
421
431
  /** Exact denominator receipt for selection eligibility. Scores stay
422
432
  * descriptive: an incomplete candidate is retained with its observed score
423
433
  * and errors instead of receiving an invented penalty. */
424
- coverage?: {
434
+ coverage: {
425
435
  expectedCells: number;
426
436
  scorableCells: number;
427
437
  unscorableCells: Array<{
@@ -462,10 +472,18 @@ interface CampaignAggregates {
462
472
  cost: CostLedgerSummary;
463
473
  /** Compatibility alias of `cost.totalCostUsd`. */
464
474
  totalCostUsd: number;
475
+ /** Cells whose dispatch completed, including cells whose later judge failed. */
465
476
  cellsExecuted: number;
466
477
  cellsSkipped: number;
467
478
  cellsCached: number;
479
+ /** All non-skipped dispatch, judge, and unclassified cell failures. */
468
480
  cellsFailed: number;
481
+ /** Present on results that record failure stages. */
482
+ cellsDispatchFailed?: number;
483
+ /** Present on results that record failure stages. */
484
+ cellsJudgeFailed?: number;
485
+ /** Legacy failures whose stage was not recorded. */
486
+ cellsUnclassifiedFailed?: number;
469
487
  }
470
488
  interface CampaignResult<TArtifact = unknown, TScenario extends Scenario = Scenario> {
471
489
  /** sha256(scenarios, judges, dispatch source ref, optimizer config, seed). Stable identity for reruns. */
@@ -16,21 +16,23 @@ import {
16
16
  routing_exports,
17
17
  runBenchmarkAdapter,
18
18
  summarizeBenchmarkCampaign
19
- } from "../chunk-CGG5SLH3.js";
20
- import "../chunk-E3IADPLG.js";
21
- import "../chunk-BTACVO2W.js";
22
- import "../chunk-ZVCHKKOP.js";
19
+ } from "../chunk-ARCFIY7U.js";
20
+ import "../chunk-PRB53E3J.js";
21
+ import "../chunk-65QETEKG.js";
22
+ import "../chunk-WED5KLZQ.js";
23
23
  import "../chunk-WGXIEX7P.js";
24
- import "../chunk-ARU2PZFM.js";
25
- import "../chunk-J5SQWP6Y.js";
26
- import "../chunk-PJQFMIOX.js";
24
+ import "../chunk-424XHVKV.js";
25
+ import "../chunk-ZPUEEM5U.js";
26
+ import "../chunk-PBE2LOSS.js";
27
+ import "../chunk-DPUHNQLN.js";
28
+ import "../chunk-MHELPNRP.js";
27
29
  import "../chunk-WS3NZZQQ.js";
28
30
  import "../chunk-VI2UW6B6.js";
29
- import "../chunk-NUKSVU3W.js";
31
+ import "../chunk-5DTSBUL2.js";
30
32
  import "../chunk-GGE4NNQT.js";
31
- import "../chunk-IR3KBHOY.js";
33
+ import "../chunk-P6FYH6K4.js";
32
34
  import "../chunk-PC4UYEBM.js";
33
- import "../chunk-IILEIWGW.js";
35
+ import "../chunk-NL33OXEP.js";
34
36
  import "../chunk-MA6HLL3S.js";
35
37
  import "../chunk-VSMTAMNK.js";
36
38
  import "../chunk-ONWEPEDO.js";
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  pearsonR,
7
7
  spearmanR
8
- } from "../chunk-PJQFMIOX.js";
8
+ } from "../chunk-MHELPNRP.js";
9
9
  import {
10
10
  judgeSpans
11
11
  } from "../chunk-ZET2UAYW.js";