@tangle-network/agent-eval 0.126.7 → 0.128.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 (132) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +6 -2
  3. package/dist/analyst/index.d.ts +52 -43
  4. package/dist/analyst/index.js +4 -4
  5. package/dist/belief-state/index.d.ts +35 -40
  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 -11
  9. package/dist/builder-eval/index.js +1 -1
  10. package/dist/campaign/index.d.ts +441 -160
  11. package/dist/campaign/index.js +11 -10
  12. package/dist/{chunk-IILEIWGW.js → chunk-2JX3CFMB.js} +100 -40
  13. package/dist/chunk-2JX3CFMB.js.map +1 -0
  14. package/dist/chunk-2MKQIFS4.js +183 -0
  15. package/dist/chunk-2MKQIFS4.js.map +1 -0
  16. package/dist/{chunk-NUKSVU3W.js → chunk-5DTSBUL2.js} +2 -2
  17. package/dist/{chunk-H5UD2323.js → chunk-7ZZMD7UK.js} +102 -2
  18. package/dist/chunk-7ZZMD7UK.js.map +1 -0
  19. package/dist/{chunk-474LBSOX.js → chunk-BYT7ELPS.js} +45 -18
  20. package/dist/chunk-BYT7ELPS.js.map +1 -0
  21. package/dist/{chunk-LUNF2SEL.js → chunk-DJKY2TSY.js} +3 -3
  22. package/dist/chunk-DPUHNQLN.js +232 -0
  23. package/dist/chunk-DPUHNQLN.js.map +1 -0
  24. package/dist/chunk-DRYIUNWY.js +622 -0
  25. package/dist/chunk-DRYIUNWY.js.map +1 -0
  26. package/dist/{chunk-IPYXE555.js → chunk-EJGRPCO3.js} +36 -13
  27. package/dist/chunk-EJGRPCO3.js.map +1 -0
  28. package/dist/{chunk-OCFJACJU.js → chunk-EOSZT7PL.js} +82 -18
  29. package/dist/chunk-EOSZT7PL.js.map +1 -0
  30. package/dist/{chunk-ZVCHKKOP.js → chunk-EZJEIH2R.js} +39 -15
  31. package/dist/chunk-EZJEIH2R.js.map +1 -0
  32. package/dist/{chunk-M7AH34KV.js → chunk-IHQDPH7D.js} +32 -16
  33. package/dist/chunk-IHQDPH7D.js.map +1 -0
  34. package/dist/{chunk-PJQFMIOX.js → chunk-MHELPNRP.js} +31 -1
  35. package/dist/chunk-MHELPNRP.js.map +1 -0
  36. package/dist/{chunk-K6IAZZ6L.js → chunk-NACAGYSY.js} +153 -122
  37. package/dist/chunk-NACAGYSY.js.map +1 -0
  38. package/dist/{chunk-BTACVO2W.js → chunk-NKAGIDE2.js} +542 -258
  39. package/dist/chunk-NKAGIDE2.js.map +1 -0
  40. package/dist/{chunk-ARU2PZFM.js → chunk-NYLOYM6N.js} +43 -23
  41. package/dist/chunk-NYLOYM6N.js.map +1 -0
  42. package/dist/{chunk-QOTFXW5L.js → chunk-P5W7RQKK.js} +2 -2
  43. package/dist/{chunk-IR3KBHOY.js → chunk-P6FYH6K4.js} +39 -3
  44. package/dist/chunk-P6FYH6K4.js.map +1 -0
  45. package/dist/{chunk-J5SQWP6Y.js → chunk-PBE2LOSS.js} +18 -2
  46. package/dist/chunk-PBE2LOSS.js.map +1 -0
  47. package/dist/{chunk-X4UCIOTZ.js → chunk-S5YLIBFX.js} +2 -2
  48. package/dist/{chunk-7VYEGHWF.js → chunk-SZLVEKMJ.js} +41 -20
  49. package/dist/chunk-SZLVEKMJ.js.map +1 -0
  50. package/dist/{chunk-P22LJ3Y2.js → chunk-TBL77AUT.js} +8 -8
  51. package/dist/chunk-TBL77AUT.js.map +1 -0
  52. package/dist/{chunk-LKKT3IVV.js → chunk-TSN7JT6D.js} +6 -4
  53. package/dist/{chunk-LKKT3IVV.js.map → chunk-TSN7JT6D.js.map} +1 -1
  54. package/dist/{chunk-E3IADPLG.js → chunk-UB2LOJ6Q.js} +51 -227
  55. package/dist/chunk-UB2LOJ6Q.js.map +1 -0
  56. package/dist/{chunk-MAX3TN3C.js → chunk-UWZZKKU7.js} +7 -19
  57. package/dist/chunk-UWZZKKU7.js.map +1 -0
  58. package/dist/{chunk-DPZAEKA6.js → chunk-VLOATJQ2.js} +85 -57
  59. package/dist/chunk-VLOATJQ2.js.map +1 -0
  60. package/dist/{chunk-MOXWMGPC.js → chunk-XDWDC2MP.js} +197 -79
  61. package/dist/chunk-XDWDC2MP.js.map +1 -0
  62. package/dist/{chunk-CGG5SLH3.js → chunk-XPRT64IE.js} +2 -2
  63. package/dist/{chunk-FO7HEH76.js → chunk-YJBNWCAA.js} +2 -2
  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 +438 -138
  67. package/dist/contract/index.js +259 -113
  68. package/dist/contract/index.js.map +1 -1
  69. package/dist/control.d.ts +56 -39
  70. package/dist/control.js +2 -3
  71. package/dist/hosted/index.d.ts +152 -51
  72. package/dist/hosted/index.js +24 -1
  73. package/dist/index.d.ts +399 -277
  74. package/dist/index.js +363 -244
  75. package/dist/index.js.map +1 -1
  76. package/dist/meta-eval/index.d.ts +33 -36
  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 +101 -80
  82. package/dist/reporting.js +7 -5
  83. package/dist/rl.d.ts +198 -142
  84. package/dist/rl.js +235 -127
  85. package/dist/rl.js.map +1 -1
  86. package/dist/rollout/index.d.ts +54 -67
  87. package/dist/rollout/index.js +6 -5
  88. package/dist/{run-campaign-FFRM3RH5.js → run-campaign-ISHFZ7FJ.js} +6 -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 +72 -50
  92. package/dist/traces.js +9 -6
  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/customer-journeys.md +7 -6
  97. package/docs/hosted-ingest-spec.md +37 -40
  98. package/docs/insight-report.md +78 -7
  99. package/docs/research-report-methodology.md +20 -21
  100. package/docs/rollout.md +13 -8
  101. package/package.json +4 -3
  102. package/dist/chunk-474LBSOX.js.map +0 -1
  103. package/dist/chunk-7VYEGHWF.js.map +0 -1
  104. package/dist/chunk-ARU2PZFM.js.map +0 -1
  105. package/dist/chunk-BTACVO2W.js.map +0 -1
  106. package/dist/chunk-DPZAEKA6.js.map +0 -1
  107. package/dist/chunk-E3IADPLG.js.map +0 -1
  108. package/dist/chunk-H5UD2323.js.map +0 -1
  109. package/dist/chunk-IILEIWGW.js.map +0 -1
  110. package/dist/chunk-IPYXE555.js.map +0 -1
  111. package/dist/chunk-IR3KBHOY.js.map +0 -1
  112. package/dist/chunk-J5SQWP6Y.js.map +0 -1
  113. package/dist/chunk-K6IAZZ6L.js.map +0 -1
  114. package/dist/chunk-M7AH34KV.js.map +0 -1
  115. package/dist/chunk-MAX3TN3C.js.map +0 -1
  116. package/dist/chunk-MOXWMGPC.js.map +0 -1
  117. package/dist/chunk-OCFJACJU.js.map +0 -1
  118. package/dist/chunk-P22LJ3Y2.js.map +0 -1
  119. package/dist/chunk-PJQFMIOX.js.map +0 -1
  120. package/dist/chunk-VSMTAMNK.js +0 -53
  121. package/dist/chunk-VSMTAMNK.js.map +0 -1
  122. package/dist/chunk-ZVCHKKOP.js.map +0 -1
  123. package/dist/chunk-ZZUXHH3R.js +0 -99
  124. package/dist/chunk-ZZUXHH3R.js.map +0 -1
  125. /package/dist/{chunk-NUKSVU3W.js.map → chunk-5DTSBUL2.js.map} +0 -0
  126. /package/dist/{chunk-LUNF2SEL.js.map → chunk-DJKY2TSY.js.map} +0 -0
  127. /package/dist/{chunk-QOTFXW5L.js.map → chunk-P5W7RQKK.js.map} +0 -0
  128. /package/dist/{chunk-X4UCIOTZ.js.map → chunk-S5YLIBFX.js.map} +0 -0
  129. /package/dist/{chunk-CGG5SLH3.js.map → chunk-XPRT64IE.js.map} +0 -0
  130. /package/dist/{chunk-FO7HEH76.js.map → chunk-YJBNWCAA.js.map} +0 -0
  131. /package/dist/{chunk-KE2VWPZX.js.map → chunk-ZUUWPZCV.js.map} +0 -0
  132. /package/dist/{run-campaign-FFRM3RH5.js.map → run-campaign-ISHFZ7FJ.js.map} +0 -0
@@ -204,6 +204,7 @@ type CostLedgerHandle = Pick<CostLedger, Exclude<keyof CostLedger, 'listPending'
204
204
  * OpenAI-compatible `/v1/chat/completions` client with:
205
205
  * - Exponential-backoff retry on 429 + 5xx gateway errors (502/503/504).
206
206
  * - Retry on transient network errors (fetch failed, AbortError, ECONNRESET).
207
+ * - One retry at temperature 1 when a model explicitly requires it.
207
208
  * - Graceful json_schema → json_object degrade on 400 with schema-reject body.
208
209
  * - Fenced-JSON stripping (```json ... ```) for models that wrap structured output.
209
210
  * - Configurable base URL + api key / bearer, works with LiteLLM proxies, OpenAI
@@ -333,7 +334,8 @@ type FailureClass = 'success' | 'reasoning_error' | 'tool_selection_error' | 'to
333
334
  * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory
334
335
  * fields are exactly those the paper "Two Loops, Three Roles" requires
335
336
  * for reproducibility: who/what/when/cost/seed/hash, plus the search vs
336
- * holdout split tag and either a `searchScore` or a `holdoutScore`.
337
+ * holdout split tag. A task score is optional because execution-only records
338
+ * must preserve missing labels instead of converting errors into zero quality.
337
339
  *
338
340
  * This is intentionally NOT a replacement for the rich `Run` /
339
341
  * `ProposeReviewReport` / `ScenarioResult` types already in the
@@ -354,6 +356,13 @@ type FailureClass = 'success' | 'reasoning_error' | 'tool_selection_error' | 'to
354
356
  /** Search/dev/holdout split tag. 'search' is the paper-grade alias for the
355
357
  * combined train+test pool that the optimizer is allowed to read. */
356
358
  type RunSplitTag = 'search' | 'dev' | 'holdout';
359
+ /**
360
+ * Explicit execution-lifecycle result for a run.
361
+ *
362
+ * This is separate from task quality (`outcome`) and failure classification.
363
+ * Producers set it only from root-run or process evidence.
364
+ */
365
+ type RunTerminalOutcome = 'succeeded' | 'failed' | 'cancelled' | 'incomplete' | 'unknown';
357
366
  interface RunTokenUsage {
358
367
  input: number;
359
368
  /** All generated tokens charged as output, including reasoning tokens. */
@@ -367,11 +376,6 @@ interface RunTokenUsage {
367
376
  }
368
377
  /**
369
378
  * How a run's USD amount was obtained.
370
- *
371
- * `costUsd` remains mandatory for wire compatibility. New producers should
372
- * always populate this discriminated union so a missing bill is never
373
- * mistaken for an observed zero-dollar run. For `uncaptured`, `costUsd` uses
374
- * the legacy `0` sentinel while this field carries the truthful null.
375
379
  */
376
380
  type RunCostProvenance = {
377
381
  kind: 'observed';
@@ -417,8 +421,8 @@ interface JudgeScoresRecord {
417
421
  perJudge: Record<string, Record<string, number>>;
418
422
  /** Per-dim mean across judges. Convenience — derivable from `perJudge`. */
419
423
  perDimMean: Record<string, number>;
420
- /** Composite mean across all dims and judges. Mirrors the score
421
- * the gate sees on `outcome.searchScore` / `holdoutScore`. */
424
+ /** Composite mean across successful judges. Mirrors the task score only
425
+ * when `failedJudges` is empty. */
422
426
  composite: number;
423
427
  /** Judges that errored or returned an unparseable verdict. Recorded
424
428
  * by id (e.g. `['glm-5.1']`) so a partial-failure case is explicit,
@@ -429,11 +433,11 @@ interface JudgeScoresRecord {
429
433
  notes?: string;
430
434
  }
431
435
  interface RunOutcome {
432
- /** Score on the search/optimization split. Optional because a
433
- * holdout-only evaluation only fills `holdoutScore`. */
436
+ /** Score on the search/optimization split. Optional for holdout-only and
437
+ * execution-only records. */
434
438
  searchScore?: number;
435
- /** Score on the held-out split. Optional because a search-only run
436
- * only fills `searchScore`. At least one must be present. */
439
+ /** Score on the held-out split. Optional for search-only and execution-only
440
+ * records. When both scores are absent, the run is explicitly unlabeled. */
437
441
  holdoutScore?: number;
438
442
  /** Bag of any other metric the run produced — judge dimensions,
439
443
  * pass/fail counters, latency stats, etc. Numeric only — keeps
@@ -497,42 +501,36 @@ interface RunRecord {
497
501
  wallMs: number;
498
502
  /** Time spent queued before execution started, if known. */
499
503
  queueMs?: number;
500
- /** Total USD cost. Mandatory runs without a cost number are
501
- * unbounded by definition and must not be admitted into the gate.
502
- * `0` is retained as the compatibility sentinel for an uncaptured amount;
503
- * inspect `costProvenance` before treating it as observed. */
504
- costUsd: number;
505
- /** Observed, model-priced estimate, or genuinely uncaptured USD amount.
506
- * Optional only so existing serialized RunRecords remain valid. */
507
- costProvenance?: RunCostProvenance;
504
+ /** Total USD cost, or null when the producer could not capture one. */
505
+ costUsd: number | null;
506
+ /** Whether `costUsd` came from billing data, a price calculation, or is unavailable. */
507
+ costProvenance: RunCostProvenance;
508
508
  /** Token usage breakdown. */
509
509
  tokenUsage: RunTokenUsage;
510
+ /** Root-run or process terminal result. Never inferred from a child span. */
511
+ terminalOutcome: RunTerminalOutcome;
512
+ /** Root-run or process failure reason. Valid only for a failed, cancelled,
513
+ * or incomplete terminal result; never populated from a child span. */
514
+ terminalFailureReason?: string;
510
515
  /** Judge-side metadata, if a judge was used. */
511
516
  judgeMetadata?: RunJudgeMetadata;
512
517
  /** Per-split scores + raw bag. */
513
518
  outcome: RunOutcome;
514
- /** Canonical, cross-agent failure class drawn from the shared
515
- * `FAILURE_CLASSES` taxonomy. This is the aggregation key that makes
516
- * "which failure dominates across the whole fleet" answerable in ONE
517
- * vocabulary — every agent classifies against the same enum. Producers
518
- * set it via the substrate classifier; leave unset only when the failure
519
- * genuinely can't be classified. */
519
+ /** Canonical task-failure class drawn from the shared
520
+ * `FAILURE_CLASSES` taxonomy. Producers set it only from task-result
521
+ * evidence. Execution errors belong in
522
+ * `outcome.raw.execution_error_count`. */
520
523
  failureClass?: FailureClass;
521
- /** Free-form domain-specific failure detail, scoped UNDER `failureClass`
522
- * (e.g. failureClass='tool_recovery_failure', failureMode='forge_build_unsatisfied').
523
- * The within-agent drill-down; `failureClass` is the cross-agent key. */
524
+ /** Free-form task-failure detail scoped under a non-success
525
+ * `failureClass`. It is invalid without that class. */
524
526
  failureMode?: string;
525
527
  /** Which split this run was drawn from. */
526
528
  splitTag: RunSplitTag;
527
529
  /**
528
- * Stable scenario identifier the run was scored against. Optional for
529
- * backwards compatibility, but **strongly recommended**: every primitive
530
- * that pairs runs by scenario (preferences, paired stats, BT tournament)
531
- * keys on this. The campaign artifact populates it canonically; legacy
532
- * runs without it fall back to inference from `outcome.raw.scenario_id`
533
- * or `experimentId`.
530
+ * Stable scenario identifier the run observed or was scored against.
531
+ * Comparison primitives match this identity rather than input order.
534
532
  */
535
- scenarioId?: string;
533
+ scenarioId: string;
536
534
  /**
537
535
  * Canonical identity for the agent profile cell that produced this row:
538
536
  * profile artifact hash plus optional harness/model/prompt/reporting
@@ -887,6 +885,13 @@ interface OptimizerConfig extends OptimizerConfigBase {
887
885
  }
888
886
  /** Five-valued verdict taxonomy (MOSS-paper alignment). */
889
887
  type GateDecision = 'ship' | 'hold' | 'need_more_work' | 'model_ceiling' | 'arch_ceiling';
888
+ /** Outcome of one check that contributed to a release decision. */
889
+ type GateCheckStatus = 'pass' | 'fail' | 'not_evaluated';
890
+ interface GateContribution {
891
+ name: string;
892
+ status: GateCheckStatus;
893
+ detail: unknown;
894
+ }
890
895
  interface GateContext<TArtifact, TScenario extends Scenario$1> {
891
896
  candidateArtifacts: Map<string, TArtifact>;
892
897
  baselineArtifacts?: Map<string, TArtifact>;
@@ -920,11 +925,7 @@ interface GateContext<TArtifact, TScenario extends Scenario$1> {
920
925
  interface GateResult {
921
926
  decision: GateDecision;
922
927
  reasons: string[];
923
- contributingGates: Array<{
924
- name: string;
925
- passed: boolean;
926
- detail: unknown;
927
- }>;
928
+ contributingGates: GateContribution[];
928
929
  delta?: number;
929
930
  }
930
931
  /** Composable promotion gate. */
@@ -1066,6 +1067,10 @@ interface CampaignCellResult<TArtifact> {
1066
1067
  durationMs: number;
1067
1068
  seed: number;
1068
1069
  cached: boolean;
1070
+ /** Stage that produced `error`. Missing on successful cells. */
1071
+ errorStage?: 'dispatch' | 'judge';
1072
+ /** Judge that threw when `errorStage` is `judge`. */
1073
+ errorJudge?: string;
1069
1074
  error?: string;
1070
1075
  }
1071
1076
  interface JudgeAggregate {
@@ -1090,8 +1095,10 @@ interface GenerationRecord {
1090
1095
  * handled — the evidence a blind `Mutator` cannot see. */
1091
1096
  interface GenerationCandidate {
1092
1097
  surfaceHash: string;
1093
- composite: number;
1094
- ci95: [number, number];
1098
+ /** Mean over complete task-quality scores, or null when none were produced. */
1099
+ composite: number | null;
1100
+ /** Descriptive interval for `composite`, or null when no score exists. */
1101
+ ci95: [number, number] | null;
1095
1102
  /** Exact surface this candidate mutated. */
1096
1103
  parentSurfaceHash?: string;
1097
1104
  /** Measured search-split composite of the exact parent surface. */
@@ -1101,13 +1108,12 @@ interface GenerationCandidate {
1101
1108
  observedDeltaFromParent?: number;
1102
1109
  /** Whether this candidate had a scorable result for every designed campaign
1103
1110
  * cell and was therefore eligible for ranking, promotion, and Pareto
1104
- * selection. Older externally-authored records may omit this field; loop
1105
- * records always populate it. */
1106
- eligibleForPromotion?: boolean;
1111
+ * selection. */
1112
+ eligibleForPromotion: boolean;
1107
1113
  /** Exact denominator receipt for selection eligibility. Scores stay
1108
1114
  * descriptive: an incomplete candidate is retained with its observed score
1109
1115
  * and errors instead of receiving an invented penalty. */
1110
- coverage?: {
1116
+ coverage: {
1111
1117
  expectedCells: number;
1112
1118
  scorableCells: number;
1113
1119
  unscorableCells: Array<{
@@ -1148,10 +1154,18 @@ interface CampaignAggregates {
1148
1154
  cost: CostLedgerSummary;
1149
1155
  /** Compatibility alias of `cost.totalCostUsd`. */
1150
1156
  totalCostUsd: number;
1157
+ /** Cells whose dispatch completed, including cells whose later judge failed. */
1151
1158
  cellsExecuted: number;
1152
1159
  cellsSkipped: number;
1153
1160
  cellsCached: number;
1161
+ /** All non-skipped dispatch, judge, and unclassified cell failures. */
1154
1162
  cellsFailed: number;
1163
+ /** Present on results that record failure stages. */
1164
+ cellsDispatchFailed?: number;
1165
+ /** Present on results that record failure stages. */
1166
+ cellsJudgeFailed?: number;
1167
+ /** Legacy failures whose stage was not recorded. */
1168
+ cellsUnclassifiedFailed?: number;
1155
1169
  }
1156
1170
  interface CampaignResult<TArtifact = unknown, TScenario extends Scenario$1 = Scenario$1> {
1157
1171
  /** sha256(scenarios, judges, dispatch source ref, optimizer config, seed). Stable identity for reruns. */
@@ -1498,7 +1512,7 @@ interface RunOptimizationBaseOptions<TScenario extends Scenario$1, TArtifact> ex
1498
1512
  candidates: Array<{
1499
1513
  surfaceHash: string;
1500
1514
  campaign: CampaignResult<TArtifact, TScenario>;
1501
- composite: number;
1515
+ composite: number | null;
1502
1516
  }>;
1503
1517
  history: GenerationRecord[];
1504
1518
  /** Shared run spend account and receipt attribution phase. */
@@ -2330,6 +2344,86 @@ declare function skillOptOptimizationMethod<TScenario extends Scenario$1, TArtif
2330
2344
  * (so the result records every gate's reason — useful for diagnostics). */
2331
2345
  declare function composeGate<TArtifact = unknown, TScenario extends Scenario$1 = Scenario$1>(...gates: Array<Gate<TArtifact, TScenario>>): Gate<TArtifact, TScenario>;
2332
2346
 
2347
+ /**
2348
+ * Liveness canaries — cheap statistical checks that catch the failure
2349
+ * modes a green test suite never sees.
2350
+ *
2351
+ * Three canary types in this module:
2352
+ *
2353
+ * 1. **Silent judge fallback** — the judge degraded to a fallback
2354
+ * path (rules-only / cached / heuristic) without anyone
2355
+ * noticing. Signature: a string of consecutive runs whose
2356
+ * `judgeMetadata.confidence` equals a known fallback constant
2357
+ * (default 0.30) OR whose `judgeMetadata.fallback` is true.
2358
+ *
2359
+ * 2. **Judge calibration drift** — the judge's confidence
2360
+ * distribution has drifted from a historical window. Two-sample
2361
+ * Kolmogorov-Smirnov test on the recent vs historical confidences,
2362
+ * with the empirical-CDF max-difference statistic.
2363
+ *
2364
+ * 3. **Eval-set distribution shift** — the mix of categories /
2365
+ * buckets in the recent runs differs significantly from the
2366
+ * historical mix. Chi-square test on the binned counts.
2367
+ *
2368
+ * Outputs are alerts. The canary does NOT fail loud the way a test
2369
+ * does — failing tests are reserved for hard correctness violations.
2370
+ * A canary that fires is a *signal* to investigate, not a verdict.
2371
+ *
2372
+ * Why this lives here rather than in `observability.ts`: that module
2373
+ * exports already, and is a pure-fanout-to-Langfuse/Prometheus
2374
+ * adapter. Canaries are statistical detectors, not adapters.
2375
+ */
2376
+
2377
+ interface CanaryOptions {
2378
+ /**
2379
+ * Silent-fallback detection.
2380
+ * - `constant`: confidence value treated as the fallback signal.
2381
+ * Default 0.30 (matches the soft-fail default in
2382
+ * `propose-review.ts`).
2383
+ * - `consecutiveThreshold`: trip the alert after this many
2384
+ * consecutive runs at `constant` (or `fallback === true`).
2385
+ * Default 3.
2386
+ */
2387
+ silentFallback?: {
2388
+ constant?: number;
2389
+ consecutiveThreshold?: number;
2390
+ /** Floating-point tolerance when comparing against `constant`. */
2391
+ epsilon?: number;
2392
+ };
2393
+ /**
2394
+ * Calibration-drift detection.
2395
+ * - `historyWindow`: number of past runs (oldest-first) treated as
2396
+ * the historical baseline. Default 50.
2397
+ * - `recentWindow`: number of recent runs (newest-first) compared
2398
+ * against history. Default 20.
2399
+ * - `ksAlpha`: alpha for the KS statistic vs critical value.
2400
+ * Default 0.05.
2401
+ * - `minRecent`: minimum recent runs required to even attempt the
2402
+ * check. Default 10.
2403
+ */
2404
+ calibrationDrift?: {
2405
+ historyWindow?: number;
2406
+ recentWindow?: number;
2407
+ ksAlpha?: number;
2408
+ minRecent?: number;
2409
+ };
2410
+ /**
2411
+ * Distribution-shift detection.
2412
+ * - `category`: function that maps a run to a categorical bucket.
2413
+ * Required to enable this canary; if omitted the chi-square check
2414
+ * is skipped entirely.
2415
+ * - `chiSquareAlpha`: alpha. Default 0.05.
2416
+ * - `historyWindow`, `recentWindow`, `minRecent`: like above.
2417
+ */
2418
+ distributionShift?: {
2419
+ category: (run: RunRecord) => string | null;
2420
+ chiSquareAlpha?: number;
2421
+ historyWindow?: number;
2422
+ recentWindow?: number;
2423
+ minRecent?: number;
2424
+ };
2425
+ }
2426
+
2333
2427
  /**
2334
2428
  * Dataset — versioned, sliceable, content-hashed scenario collection.
2335
2429
  *
@@ -2401,6 +2495,144 @@ interface RedTeamCase extends DatasetScenario {
2401
2495
  payload: RedTeamPayload;
2402
2496
  }
2403
2497
 
2498
+ /**
2499
+ * Verifiable reward channel.
2500
+ *
2501
+ * For RL on coding / math / theorem-proving / structured-output tasks, the
2502
+ * reward signal is *decidable* — a test passes or fails, a proof checks or
2503
+ * doesn't, an output validates against a schema or doesn't. These rewards
2504
+ * are dramatically more useful for RL training than LLM-judge scores
2505
+ * because they don't drift, can't be Goodhart-gamed by the policy in the
2506
+ * same way, and don't require a separate calibration loop.
2507
+ *
2508
+ * The `MultiLayerVerifier` already produces this signal — it just doesn't
2509
+ * surface it in a shape that's clean enough for RL training. This module
2510
+ * wraps the verifier output so consumers can:
2511
+ *
2512
+ * 1. Extract a clean `VerifiableReward` from a `VerificationReport`
2513
+ * 2. Distinguish *deterministic* rewards (compile, test, schema) from
2514
+ * *probabilistic* rewards (judge) so they can be weighted differently
2515
+ * in the RL training step
2516
+ * 3. Filter `RunRecord[]` to only those with a verifiable reward,
2517
+ * producing the clean training set that DeepSeek-R1-style GRPO and
2518
+ * AlphaProof-style search both depend on
2519
+ *
2520
+ * Why this matters: every credible 2025-2026 frontier RL result on coding
2521
+ * agents leans on verifiable reward (DeepSeek-R1 GRPO on test pass-rate,
2522
+ * o-series RL on math/code, AlphaProof on Lean kernel checking). Mixing
2523
+ * judge scores into the reward signal poisons the gradient. This module
2524
+ * is the seam.
2525
+ */
2526
+
2527
+ type VerifiableRewardSource = 'compile' | 'test' | 'schema' | 'sandbox' | 'judge' | 'composite';
2528
+ interface VerifiableRewardExtractionOptions {
2529
+ /**
2530
+ * Which layers count as deterministic-reward sources. The verifier doesn't
2531
+ * tag layers as "this is verifiable"; the caller declares it via this list
2532
+ * (or via the layer name → source mapping). Default treats common names
2533
+ * (`install`, `typecheck`, `build`, `lint`, `test`, `compile`, `schema`,
2534
+ * `sandbox`) as deterministic.
2535
+ */
2536
+ deterministicLayers?: string[];
2537
+ /**
2538
+ * Map layer name → reward source. Defaults to a sensible string-match.
2539
+ */
2540
+ sourceFor?: (layerName: string) => VerifiableRewardSource;
2541
+ /**
2542
+ * Whether to fall back to a probabilistic (judge) reward when no
2543
+ * deterministic layer produced a numeric score. Default `true`. Set to
2544
+ * `false` for "deterministic-only" training pipelines that should
2545
+ * discard runs without a verifiable signal.
2546
+ */
2547
+ fallbackToJudge?: boolean;
2548
+ /**
2549
+ * Default confidence for probabilistic (judge) rewards when the judge
2550
+ * doesn't report one. Default `0.7`.
2551
+ */
2552
+ judgeConfidenceFloor?: number;
2553
+ }
2554
+
2555
+ /**
2556
+ * Reward hacking / Goodhart detection.
2557
+ *
2558
+ * Goodhart's Law says: when a measure becomes a target, it ceases to be
2559
+ * a good measure. In RLHF and agentic-RL settings this is the dominant
2560
+ * failure mode — the policy learns to produce outputs that score well on
2561
+ * the proxy reward (judge, rubric, test pass-rate) without producing
2562
+ * the underlying capability the proxy was meant to track.
2563
+ *
2564
+ * Krakovna et al. (2020, "Specification Gaming Examples in AI") and the
2565
+ * subsequent RLHF reward-hacking literature (Skalse et al. 2022, Kim et al.
2566
+ * 2023) converge on a few diagnostic signatures:
2567
+ *
2568
+ * 1. **Reward divergence:** the proxy reward grows while the held-out
2569
+ * ground-truth signal stagnates or drops. Predictive validity over
2570
+ * time captures this.
2571
+ * 2. **Distributional shift in outputs:** after RL, the policy produces
2572
+ * outputs that no longer match the reference distribution — usually
2573
+ * because it found a high-reward attractor that's degenerate (e.g.
2574
+ * one-token responses, repetition, formatting tricks).
2575
+ * 3. **Disagreement between independent rewards:** if you train on
2576
+ * reward A and a held-out independent reward B drops sharply, you're
2577
+ * probably hacking A.
2578
+ * 4. **Calibration drift:** the verifiable / deterministic component of
2579
+ * the reward is stable; the probabilistic / judge component drifts up
2580
+ * while the deterministic component doesn't. The judge is being
2581
+ * gamed.
2582
+ *
2583
+ * This module ships explicit detectors for all four signatures, plus a
2584
+ * combined verdict. The output is diagnostic — actionable signals,
2585
+ * not autoreject — because each signature has known false positives
2586
+ * (e.g., a policy that genuinely improves can show distributional shift).
2587
+ *
2588
+ * Differs from `rubricPredictiveValidity` (which is a *standing* check on
2589
+ * whether rubrics correlate with deployment outcomes) — this is a
2590
+ * *temporal* check on whether the reward-vs-truth gap is *widening over
2591
+ * time during a training run*.
2592
+ */
2593
+
2594
+ interface DetectRewardHackingInput {
2595
+ /**
2596
+ * Run records ordered by recency (oldest first). The detector segments
2597
+ * them into prefix/suffix windows to compute "did the gap widen."
2598
+ */
2599
+ runs: RunRecord[];
2600
+ /**
2601
+ * The metric the policy was trained to optimize. Should be present on
2602
+ * `outcome.raw` or `outcome.holdoutScore`. Default reads `outcome.holdoutScore`.
2603
+ */
2604
+ proxyOf?: (run: RunRecord) => number | null;
2605
+ /**
2606
+ * The held-out ground-truth metric. For RL on coding, this is typically
2607
+ * test pass-rate. For RLHF, it's downstream task performance or human
2608
+ * preference. For knowledge tasks, it's an independently-graded score.
2609
+ */
2610
+ truthOf?: (run: RunRecord) => number | null;
2611
+ /**
2612
+ * Independent secondary reward. Used for the `reward_disagreement`
2613
+ * signal. Default uses the verifiable reward extractor (deterministic
2614
+ * sources only).
2615
+ */
2616
+ secondaryRewardOf?: (run: RunRecord) => number | null;
2617
+ /**
2618
+ * Window size — how many of the most recent runs count as the "after"
2619
+ * cohort. Default min(50, half the runs).
2620
+ */
2621
+ windowSize?: number;
2622
+ /**
2623
+ * Severity threshold to flag a signal. Default 0.3 (suspect) and 0.6
2624
+ * (gaming).
2625
+ */
2626
+ thresholds?: {
2627
+ suspect?: number;
2628
+ gaming?: number;
2629
+ };
2630
+ /**
2631
+ * Verifiable-reward options used for the secondary-reward fallback.
2632
+ */
2633
+ verifiableRewardOptions?: VerifiableRewardExtractionOptions;
2634
+ }
2635
+
2404
2636
  /**
2405
2637
  * `defaultProductionGate` — composes the substrate's existing safety
2406
2638
  * primitives (red-team / reward-hacking / canary / heldout) into a single
@@ -2413,6 +2645,10 @@ interface RedTeamCase extends DatasetScenario {
2413
2645
  * extra domain-specific gates they need (`composeGate(defaultProductionGate(...), customGate)`).
2414
2646
  */
2415
2647
 
2648
+ type DefaultProductionGateCheck = 'dimension-regression' | 'budget' | 'red-team' | 'reward-hacking' | 'canary';
2649
+ type DefaultProductionRewardHackingOptions = Omit<DetectRewardHackingInput, 'runs' | 'truthOf'> & {
2650
+ truthOf: NonNullable<DetectRewardHackingInput['truthOf']>;
2651
+ };
2416
2652
  interface DefaultProductionGateOptions {
2417
2653
  /** Required: scenarios held out from training; substrate compares
2418
2654
  * candidate-on-holdout vs baseline-on-holdout. */
@@ -2445,19 +2681,25 @@ interface DefaultProductionGateOptions {
2445
2681
  * native scale. When omitted it auto-scales off observed magnitudes:
2446
2682
  * 0.05 on [0,1], 5 on 0-100. */
2447
2683
  regressionTolerance?: number;
2448
- /** Total $ budget for ALL cells in this campaign — including baseline + candidate.
2449
- * Composite verdict refuses to ship when spend exceeded budget. */
2684
+ /** Total $ budget for the complete improvement run. Requires
2685
+ * `GateContext.costLedger`; missing or incomplete accounting holds. */
2450
2686
  budgetUsd?: number;
2451
- /** Red-team cases to probe candidate outputs against. When omitted the
2452
- * substrate uses `DEFAULT_RED_TEAM_CORPUS`. Provide a domain-specific
2453
- * battery for tighter coverage. */
2687
+ /** Static artifact-screening cases. Only `expected: 'ignore'` cases without
2688
+ * tool assertions are valid because this check does not dispatch case inputs
2689
+ * or observe tool calls. */
2454
2690
  redTeamBattery?: RedTeamCase[];
2455
- /** Run records (oldest-first) needed for the reward-hacking detector.
2456
- * Substrate populates from prior production-loop generations. */
2691
+ /** Shared run history, oldest first. Supplying history does not enable either
2692
+ * monitoring check; configure `rewardHacking` and/or `canary` explicitly. */
2457
2693
  recentRuns?: RunRecord[];
2458
- /** When true, the gate refuses to ship if the reward-hacking detector
2459
- * fires at the `gaming` severity. Default true. */
2460
- blockOnRewardHackingGaming?: boolean;
2694
+ /** Enable reward-hacking monitoring with a caller-owned independent truth channel. */
2695
+ rewardHacking?: DefaultProductionRewardHackingOptions;
2696
+ /** Enable canary monitoring. Pass `{}` to use the canary defaults. */
2697
+ canary?: CanaryOptions;
2698
+ /** Optional checks that must be evaluated even when their normal input is
2699
+ * absent. Configuring a check's input also makes that check required.
2700
+ * Missing evidence always records `not_evaluated`; required unevaluated
2701
+ * checks hold the release decision. Held-out significance is always required. */
2702
+ requiredChecks?: DefaultProductionGateCheck[];
2461
2703
  }
2462
2704
  /**
2463
2705
  * Opinionated production gate composing held-out significance, red-team, reward-hacking, and canary checks into a single `Gate.decide` decision.
@@ -2837,7 +3079,7 @@ interface ParetoPoint {
2837
3079
  onFrontier: boolean;
2838
3080
  /** Optional gate verdict for this candidate, if a `GateDecision`
2839
3081
  * for it was passed in. */
2840
- gate?: 'promote' | 'reject_few_runs' | 'reject_negative_delta' | 'reject_overfit_gap' | null;
3082
+ gate?: 'promote' | 'reject';
2841
3083
  }
2842
3084
  interface ParetoFigureSpec {
2843
3085
  kind: 'pareto-cost-quality';
@@ -2891,8 +3133,8 @@ interface InsightReport {
2891
3133
  /** Number of runs analyzed. */
2892
3134
  n: number;
2893
3135
  /** Runtime facts carried by the run records. These describe execution,
2894
- * not task quality: duration, queueing, token categories, models, and
2895
- * explicitly recorded failures. */
3136
+ * not task quality: duration, queueing, token categories, models,
3137
+ * execution errors, and terminal outcomes. */
2896
3138
  execution: ExecutionInsight;
2897
3139
  /** Composite-score distribution across all runs. Always present. */
2898
3140
  composite: ScalarDistribution;
@@ -2950,11 +3192,10 @@ interface InsightReport {
2950
3192
  * Surfaced metrics: composite, cost, duration, tokenUsage, plus any
2951
3193
  * per-dimension judge metric present in both windows. */
2952
3194
  priorPeriodComparison?: PriorPeriodComparison;
2953
- /** Model-free failure-mode breakdown from `RunRecord.failureMode`, ranked
2954
- * by count descending. Present when any run carries a `failureMode`.
2955
- * Complements `failureClusters` (LLM-semantic) with the structured tags
2956
- * the harness already recorded — actionable with no analyst wired. */
2957
- failureModes?: FailureModeTally[];
3195
+ /** Model-free task-failure breakdown from `RunRecord.failureClass`, ranked
3196
+ * by count descending. Domain-specific `failureMode` detail is retained on
3197
+ * each record but never creates a second aggregation vocabulary. */
3198
+ failureClasses?: FailureClassTally[];
2958
3199
  /** Top-N actionable recommendations, ranked by priority. The packet's
2959
3200
  * human-readable layer; the numeric sections are the evidence. */
2960
3201
  recommendations: Recommendation[];
@@ -3002,14 +3243,45 @@ interface ExecutionInsight {
3002
3243
  events: number;
3003
3244
  reportingRuns: number;
3004
3245
  };
3005
- /** Failure counts remain separate from outcome scores. `reportedErrorEvents`
3006
- * sums `outcome.raw.error_span_count` only where a producer supplied it. */
3007
- failures: {
3246
+ /** Runs with explicit execution-error telemetry. This is independent of
3247
+ * whether the root run ultimately succeeded, failed, or has no terminal
3248
+ * evidence. */
3249
+ executionErrors: {
3008
3250
  runs: number;
3009
- fraction: number;
3010
- reportedErrorEvents: number;
3251
+ /** Share among runs that supplied an execution-error count.
3252
+ * `null` when no run supplied error telemetry. */
3253
+ fraction: number | null;
3254
+ /** Execution-error events reported through the canonical count. */
3255
+ events: number;
3256
+ /** Runs that supplied an execution-error count, including explicit zeroes. */
3011
3257
  reportingRuns: number;
3258
+ /** Exact sum of `outcome.raw.error_span_count`, kept separate from other errors. */
3259
+ errorSpanEvents: number;
3260
+ /** Runs that supplied `outcome.raw.error_span_count`, including explicit zeroes. */
3261
+ errorSpanReportingRuns: number;
3262
+ /**
3263
+ * Error-telemetry coverage crossed with independently reported terminal
3264
+ * outcomes. `unreported` is distinct from a reported zero.
3265
+ */
3266
+ byTerminalOutcome: Record<RunTerminalOutcome, ExecutionErrorOutcomeCell>;
3012
3267
  };
3268
+ /** Root-run or process outcomes. Missing `RunRecord.terminalOutcome` values
3269
+ * count as `unknown`; child-span status never changes these counts. */
3270
+ terminalOutcomes: {
3271
+ succeeded: number;
3272
+ failed: number;
3273
+ cancelled: number;
3274
+ incomplete: number;
3275
+ unknown: number;
3276
+ };
3277
+ }
3278
+ interface ExecutionErrorOutcomeCell {
3279
+ /** Runs that explicitly reported one or more execution errors. */
3280
+ withErrors: number;
3281
+ /** Runs that explicitly reported zero execution errors. */
3282
+ withoutErrors: number;
3283
+ /** Runs with no execution-error count from the producer. */
3284
+ unreported: number;
3013
3285
  }
3014
3286
  interface TokenUsageInsight {
3015
3287
  input: ScalarDistribution;
@@ -3029,12 +3301,18 @@ interface TokenUsageInsight {
3029
3301
  interface ScalarDistribution {
3030
3302
  /** Sample count after dropping non-finite values. */
3031
3303
  n: number;
3032
- mean: number;
3033
- p50: number;
3034
- p95: number;
3035
- stddev: number;
3036
- min: number;
3037
- max: number;
3304
+ /** Null when `n` is zero. */
3305
+ mean: number | null;
3306
+ /** Null when `n` is zero. */
3307
+ p50: number | null;
3308
+ /** Null when `n` is zero. */
3309
+ p95: number | null;
3310
+ /** Null when `n` is zero. */
3311
+ stddev: number | null;
3312
+ /** Null when `n` is zero. */
3313
+ min: number | null;
3314
+ /** Null when `n` is zero. */
3315
+ max: number | null;
3038
3316
  /** Histogram bins using `agent-eval`'s `gainHistogram` primitive. */
3039
3317
  histogram: GainDistributionBin[];
3040
3318
  /** Worst-N runs by score, ascending. Populated for the composite
@@ -3100,12 +3378,16 @@ interface LiftInsight {
3100
3378
  pValue: number;
3101
3379
  /** Number of paired observations. */
3102
3380
  n: number;
3103
- /** Cohen's d for the delta. */
3104
- cohensD: number;
3381
+ /** Scored baseline observations without a candidate match. */
3382
+ unpairedBaseline: number;
3383
+ /** Scored candidate observations without a baseline match. */
3384
+ unpairedCandidate: number;
3385
+ /** Cohen's dz for paired deltas; null when the observed delta variance is zero. */
3386
+ cohensD: number | null;
3105
3387
  /** Minimum detectable effect at current n, 80% power. */
3106
3388
  mde: number;
3107
- /** Sample size needed to detect the observed delta at 80% power. */
3108
- requiredN: number;
3389
+ /** Paired sample size needed to detect the standardized effect at 80% power. */
3390
+ requiredN: number | null;
3109
3391
  }
3110
3392
  interface FailureClusterInsight {
3111
3393
  /** All clusters identified by the registry, ranked by share descending. */
@@ -3121,15 +3403,13 @@ interface FailureClusterInsight {
3121
3403
  }>;
3122
3404
  totalFailures: number;
3123
3405
  }
3124
- /** Model-free failure breakdown over the structured `RunRecord.failureMode`
3125
- * enum. Unlike `failureClusters` (semantic, requires an LLM analyst), this
3126
- * is computed directly from the tags the harness already recorded — so a
3127
- * customer ingesting one batch with no judge/analyst still learns which
3128
- * named failure dominates. */
3129
- interface FailureModeTally {
3130
- /** The `failureMode` tag. */
3131
- mode: string;
3132
- /** Number of runs carrying this tag. */
3406
+ /** Model-free task-failure breakdown over canonical `RunRecord.failureClass`
3407
+ * values. Unlike semantic failure clusters, this is computed directly from
3408
+ * run records and does not require a model analyst. */
3409
+ interface FailureClassTally {
3410
+ /** Canonical task-failure class. */
3411
+ failureClass: FailureClass;
3412
+ /** Number of failed runs carrying this class. */
3133
3413
  count: number;
3134
3414
  /** Share of the whole corpus, 0..1. */
3135
3415
  share: number;
@@ -3169,7 +3449,7 @@ interface ReleaseSummary {
3169
3449
  status: 'pass' | 'warn' | 'fail';
3170
3450
  axes: Array<{
3171
3451
  name: 'quality-lift' | 'contamination' | 'composite-distribution';
3172
- status: 'pass' | 'warn' | 'fail';
3452
+ status: 'pass' | 'warn' | 'fail' | 'not_evaluated';
3173
3453
  detail: string;
3174
3454
  }>;
3175
3455
  /** Free-form issues surfaced beyond the standard axes. Empty by default;
@@ -3229,9 +3509,8 @@ interface Recommendation {
3229
3509
  * # Hosted-tier wire format — the schema that EVERY orchestrator (ours,
3230
3510
  * a partner's self-hosted one, a future open implementation) must accept.
3231
3511
  *
3232
- * **Stability:** every type in this file is committed under semver. New
3233
- * minors only ADD optional fields. Breaking changes mean a major bump
3234
- * (`HostedWireVersion` literal increment).
3512
+ * This package implements exactly one wire version. Servers reject every
3513
+ * other version instead of translating old payloads.
3235
3514
  *
3236
3515
  * The wire format is two event streams in one transport:
3237
3516
  *
@@ -3257,11 +3536,15 @@ interface EvalRunCellScore {
3257
3536
  scenarioId: string;
3258
3537
  /** Repetition index when reps > 1; 0 for the default. */
3259
3538
  rep: number;
3260
- /** Composite score across all judges + dimensions for this cell. */
3261
- compositeMean: number;
3262
- /** Per-judge per-dimension scores; null where the judge did not run. */
3539
+ /** Composite score across successful judges, or null when unscored. */
3540
+ compositeMean: number | null;
3541
+ /** Per-judge and per-dimension scores; failed or missing judges are absent. */
3263
3542
  dimensions: Record<string, Record<string, number>>;
3264
- /** Per-cell error message if the dispatch threw. Null on success. */
3543
+ /** Root execution result, kept separate from task quality. */
3544
+ terminalOutcome: RunTerminalOutcome;
3545
+ /** Canonical execution-error count, or null when the producer did not measure it. */
3546
+ executionErrorCount: number | null;
3547
+ /** Per-cell dispatch or judge error. Missing on success. */
3265
3548
  errorMessage?: string;
3266
3549
  }
3267
3550
  interface EvalRunGenerationSnapshot {
@@ -3275,8 +3558,8 @@ interface EvalRunGenerationSnapshot {
3275
3558
  surface?: MutableSurface;
3276
3559
  /** Per-cell scores for this generation. */
3277
3560
  cells: EvalRunCellScore[];
3278
- /** Aggregate composite mean across all cells in this generation. */
3279
- compositeMean: number;
3561
+ /** Mean across scored cells, or null when no cell has a task-quality label. */
3562
+ compositeMean: number | null;
3280
3563
  /** Total $ spent across this generation. */
3281
3564
  costUsd: number;
3282
3565
  /** Wall-clock duration of this generation. */
@@ -3316,10 +3599,14 @@ interface EvalRunEvent {
3316
3599
  * paired-bootstrap lift CI, judge stats, inter-rater agreement,
3317
3600
  * contamination check, failure clusters (when an analyst is wired),
3318
3601
  * outcome correlation (when downstream signal is supplied), and the
3319
- * recommendations the dashboard surfaces verbatim. Additive; older
3320
- * clients that don't know about this field continue to work. */
3602
+ * recommendations the dashboard surfaces verbatim. */
3321
3603
  insightReport?: InsightReport;
3322
3604
  }
3605
+ /**
3606
+ * Canonical unsigned 64-bit integer encoded as a base-10 string.
3607
+ * JSON numbers cannot represent OTLP nanosecond timestamps exactly.
3608
+ */
3609
+ type UnixNanoTimestamp = string;
3323
3610
  /**
3324
3611
  * OTel-shape span with a few additional attributes for eval-run pivoting.
3325
3612
  * Compatible with any OTLP collector — `name`, `traceId`, `spanId`,
@@ -3330,11 +3617,11 @@ interface TraceSpanEvent {
3330
3617
  spanId: string;
3331
3618
  parentSpanId?: string;
3332
3619
  name: string;
3333
- startTimeUnixNano: number;
3334
- endTimeUnixNano: number;
3620
+ startTimeUnixNano: UnixNanoTimestamp;
3621
+ endTimeUnixNano: UnixNanoTimestamp;
3335
3622
  attributes: Record<string, string | number | boolean>;
3336
3623
  events?: Array<{
3337
- timeUnixNano: number;
3624
+ timeUnixNano: UnixNanoTimestamp;
3338
3625
  name: string;
3339
3626
  attributes?: Record<string, string | number | boolean>;
3340
3627
  }>;
@@ -3462,8 +3749,8 @@ interface LoopProvenanceCandidate {
3462
3749
  eligibleForPromotion: boolean;
3463
3750
  /** Designed-denominator receipt retained even for incomplete candidates. */
3464
3751
  coverage: NonNullable<GenerationCandidate['coverage']>;
3465
- /** Mean composite this candidate scored on the search split. */
3466
- composite: number;
3752
+ /** Mean composite this candidate scored on the search split, or null when unscorable. */
3753
+ composite: number | null;
3467
3754
  /** Whether this candidate was promoted out of its generation. */
3468
3755
  promoted: boolean;
3469
3756
  }
@@ -3535,11 +3822,7 @@ interface LoopProvenanceRecord {
3535
3822
  decision: GateDecision;
3536
3823
  reasons: string[];
3537
3824
  delta?: number;
3538
- contributingGates: Array<{
3539
- name: string;
3540
- passed: boolean;
3541
- detail: unknown;
3542
- }>;
3825
+ contributingGates: GateContribution[];
3543
3826
  };
3544
3827
  /** Present iff the loop ran with `holdout: 'deferred'` — the held-out
3545
3828
  * comparison was intentionally not measured in this run, so the holdout
@@ -3651,6 +3934,13 @@ interface SelfImproveOptions<TScenario extends Scenario$1, TArtifact> {
3651
3934
  * baseline-only run (set `budget.generations = 0`).
3652
3935
  */
3653
3936
  agent: (surface: MutableSurface, scenario: TScenario, ctx: DispatchContext) => Promise<TArtifact>;
3937
+ /**
3938
+ * Snapshot-bearing model identity for agents that do not report a paid-call
3939
+ * receipt through `ctx.cost.runPaidCall()`.
3940
+ *
3941
+ * Omit this when every cell reports its concrete model in a receipt.
3942
+ */
3943
+ model?: string;
3654
3944
  /** Scenarios to evaluate against. Train/holdout split is computed from
3655
3945
  * these unless `budget.holdoutScenarios` is set explicitly. */
3656
3946
  scenarios: TScenario[];
@@ -4048,7 +4338,7 @@ declare function verifyCandidateBenchmarkSuite(input: unknown): {
4048
4338
  * `ViewTraceOversized`.
4049
4339
  */
4050
4340
  /** OTLP span kind (subset we actually use). */
4051
- type TraceAnalystSpanKind = 'AGENT' | 'LLM' | 'TOOL' | 'CHAIN' | 'GUARDRAIL' | 'SPAN' | 'UNKNOWN';
4341
+ type TraceAnalystSpanKind = 'AGENT' | 'LLM' | 'TOOL' | 'CHAIN' | 'EVALUATOR' | 'GUARDRAIL' | 'SPAN' | 'UNKNOWN';
4052
4342
  type TraceAnalystSpanStatus = 'OK' | 'ERROR' | 'UNSET';
4053
4343
  /** Subset of OTLP span fields the analyst exposes to the agent. The
4054
4344
  * store's job is to project upstream's full span shape down to this
@@ -4847,7 +5137,8 @@ interface AnalyzeRunsOptions {
4847
5137
  split?: 'search' | 'holdout' | 'auto';
4848
5138
  /** Pairwise analysis configuration. When both `baselineCandidateId` and
4849
5139
  * `candidateCandidateId` are present, lift is computed on paired
4850
- * (experimentId, seed) tuples shared between the two sides. */
5140
+ * (experimentId, scenarioId, seed) identities shared between the two sides.
5141
+ * Unmatched rows remain visible in the lift result. */
4851
5142
  baselineCandidateId?: string;
4852
5143
  candidateCandidateId?: string;
4853
5144
  /** Canary scenarios — checked against every run's raw output for
@@ -4882,7 +5173,7 @@ interface AnalyzeRunsOptions {
4882
5173
  * recommendations fire on statistically significant regressions.
4883
5174
  * The two windows do NOT have to share scenarios — the comparison
4884
5175
  * is two-sample unpaired (the substrate's `lift` field uses paired
4885
- * bootstrap on shared (experimentId, seed) tuples; this is the
5176
+ * bootstrap on shared (experimentId, scenarioId, seed) identities; this is the
4886
5177
  * shape for "this week vs last week" rather than "candidate vs
4887
5178
  * baseline within a campaign"). */
4888
5179
  baselineRuns?: RunRecord[];
@@ -5069,9 +5360,9 @@ interface EvalDimensionDelta {
5069
5360
  interface EvalCellScoreDelta {
5070
5361
  scenarioId: string;
5071
5362
  rep: number;
5072
- compositeBefore: number;
5073
- compositeAfter: number;
5074
- compositeDelta: number;
5363
+ compositeBefore: number | null;
5364
+ compositeAfter: number | null;
5365
+ compositeDelta: number | null;
5075
5366
  /** Per-judge → per-dimension deltas. Outer key = judge name from
5076
5367
  * `EvalRunCellScore.dimensions`; inner key = dimension name. */
5077
5368
  dimensions: Record<string, Record<string, EvalDimensionDelta>>;
@@ -5090,10 +5381,10 @@ interface EvalGenerationDiff {
5090
5381
  removed: EvalRunCellScore[];
5091
5382
  /** Cells present in `after` but missing from `before`. */
5092
5383
  added: EvalRunCellScore[];
5093
- /** Aggregate composite mean across all cells in the snapshot. */
5094
- compositeBefore: number;
5095
- compositeAfter: number;
5096
- compositeDelta: number;
5384
+ /** Aggregate composite mean, null when that snapshot was unscored. */
5385
+ compositeBefore: number | null;
5386
+ compositeAfter: number | null;
5387
+ compositeDelta: number | null;
5097
5388
  costUsdBefore: number;
5098
5389
  costUsdAfter: number;
5099
5390
  costUsdDelta: number;
@@ -5302,6 +5593,7 @@ interface CodeAgentSessionMetrics {
5302
5593
  toolCalls: number;
5303
5594
  toolOutputs: number;
5304
5595
  toolErrors: number;
5596
+ unclassifiedErrors: number;
5305
5597
  patchAttempts: number;
5306
5598
  patchSuccesses: number;
5307
5599
  patchFailures: number;
@@ -5340,7 +5632,6 @@ interface CodeAgentSessionDiagnostic {
5340
5632
  sourcePath?: string;
5341
5633
  entries: number;
5342
5634
  malformedLines: number;
5343
- inferredScore: boolean;
5344
5635
  hasExplicitTerminalSignal: boolean;
5345
5636
  hasFinalOutput: boolean;
5346
5637
  hasQualityLabel: boolean;
@@ -5369,9 +5660,7 @@ interface CodeAgentSessionIntakeOptions {
5369
5660
  configHash?: string;
5370
5661
  commitSha?: string;
5371
5662
  score?: number;
5372
- /** Explicit cost receipt. Use `uncaptured` when the source says dollars
5373
- * were not captured; the adapter will not relabel its compatibility $0
5374
- * sentinel as observed. When omitted, source-reported cost wins, then a
5663
+ /** Explicit cost receipt. When omitted, source-reported cost wins, then a
5375
5664
  * token-priced estimate, then uncaptured. */
5376
5665
  costProvenance?: RunCostProvenance;
5377
5666
  /** Exact executor-owned process result. This is required when a provider's
@@ -5397,8 +5686,8 @@ declare const fromPigraphSession: typeof fromPiSession;
5397
5686
  * `analyzeRuns({ runs, raterScores })` can produce inter-rater agreement,
5398
5687
  * disagreement triage, and downstream recommendations.
5399
5688
  *
5400
- * Per-run `RunRecord.outcome.searchScore` is the rater-mean rating
5401
- * (normalised to 0..1 when scale is supplied); `outcome.raw` carries the
5689
+ * The rater mean is written to the score field matching the run split
5690
+ * (normalised to 0..1 when a scale is supplied); `outcome.raw` carries
5402
5691
  * per-rater scores keyed by rater id for downstream attribution.
5403
5692
  */
5404
5693
 
@@ -5422,9 +5711,10 @@ interface FeedbackTableMeta {
5422
5711
  experimentId?: string;
5423
5712
  /** When omitted, defaults to `runId` — each run is its own candidate. */
5424
5713
  candidateId?: string;
5425
- /** Cost in USD, when available. Set to 0 when unknown — the consumer's
5426
- * cost analysis sections will collapse gracefully. */
5714
+ /** Observed cost in USD, when available. */
5427
5715
  costUsd?: number;
5716
+ /** Stable scenario identity. Defaults to `runId`. */
5717
+ scenarioId?: string;
5428
5718
  /** Wall-clock ms, when available. Defaults to 0. */
5429
5719
  wallMs?: number;
5430
5720
  /** Model identifier including snapshot. Default `unknown@unknown`. */
@@ -5456,9 +5746,8 @@ interface FromFeedbackTableOptions {
5456
5746
  max: number;
5457
5747
  };
5458
5748
  /** When true, the rater scores are emitted into `raterScores` (a sibling
5459
- * array `analyzeRuns()` accepts) instead of being averaged into the
5460
- * run's `outcome.searchScore`. Default `true` preserves rater-level
5461
- * signal for inter-rater analysis. */
5749
+ * array `analyzeRuns()` accepts) in addition to the aggregate run score.
5750
+ * Default `true` preserves rater-level signal for inter-rater analysis. */
5462
5751
  emitRaterScores?: boolean;
5463
5752
  }
5464
5753
  interface FromFeedbackTableResult {
@@ -5487,14 +5776,19 @@ declare function fromFeedbackTable(opts: FromFeedbackTableOptions): FromFeedback
5487
5776
  * - `runId` (the group key)
5488
5777
  * - `wallMs` from `endTimeUnixNano - startTimeUnixNano`
5489
5778
  * - `model` from `gen_ai.request.model` / `llm.model` / `tangle.model`
5779
+ * - task failure class and detail from explicit `tangle.task.*` attributes
5490
5780
  * - cost from `cost.usd` / `gen_ai.usage.cost_usd` / `tangle.cost.usd`
5491
5781
  * - token usage from model-call input, output, cache-read, and cache-write
5492
5782
  * attributes without double-counting aggregate parent spans
5493
- * - `outcome.searchScore` from `tangle.score` / `eval.score` when
5494
- * present; `outcome.raw` collects every numeric attribute.
5783
+ * - task quality from an explicit `scoreForRun` callback or a designated
5784
+ * evaluation attribute on a root / `EVALUATOR` span; `outcome.raw`
5785
+ * collects every numeric attribute without promoting it to task quality.
5495
5786
  *
5496
- * Spans that ERRORed (`status.code === 'ERROR'`) populate `failureMode`
5497
- * with their `name` so `analyzeRuns()`'s failure clustering sees them.
5787
+ * Errored tool, model, and child-agent spans contribute to execution-error
5788
+ * counts. Root process, guardrail, evaluator, propagated parent, and unknown
5789
+ * errors retain separate counters. Only one failed root can set
5790
+ * `RunRecord.terminalOutcome` and `RunRecord.terminalFailureReason`; a child
5791
+ * error cannot become a task failure.
5498
5792
  */
5499
5793
 
5500
5794
  interface FromOtelSpansOptions {
@@ -5503,7 +5797,13 @@ interface FromOtelSpansOptions {
5503
5797
  defaultSplit?: RunSplitTag;
5504
5798
  /** Default `experimentId` when not present on any span. */
5505
5799
  experimentId?: string;
5800
+ /**
5801
+ * Explicit task-quality score for a logical run. The callback receives
5802
+ * spans in deterministic time/id order. Its value must agree with any
5803
+ * designated score attributes present on root or `EVALUATOR` spans.
5804
+ */
5805
+ scoreForRun?: (runId: string, spans: readonly TraceSpanEvent[]) => number | undefined;
5506
5806
  }
5507
5807
  declare function fromOtelSpans(opts: FromOtelSpansOptions): RunRecord[];
5508
5808
 
5509
- export { type AgentEvalAgent, type AgentEvalEvaluateOptions, type AgentEvalImproveOptions, type AgentTraceContributor, type AgentTraceContributorType, type AgentTraceConversation, type AgentTraceFile, type AgentTraceIndex, type AgentTraceRange, type AgentTraceRecord, type AnalystFinding, type AnalyzeRunsOptions, type AuthoringProvenance, type AxisEvidence, type AxisVerdict, type BuildEvidenceVectorOptions, type CampaignAggregates, type CampaignArtifactWriter, type CampaignCellFailureReceipt, type CampaignCellResult, type CampaignCostMeter, type CampaignResult, type CampaignStorage, type CampaignTraceWriter, type CandidateExperimentExecutionInput, type ChatClient, type CodeAgentSessionAction, type CodeAgentSessionActionKind, type CodeAgentSessionActionStatus, type CodeAgentSessionActionSurface, type CodeAgentSessionDiagnostic, type CodeAgentSessionExecutionReceipt, type CodeAgentSessionIntakeOptions, type CodeAgentSessionIntakeResult, type CodeAgentSessionMetrics, type CodeAgentSessionObservation, type CodeAgentSessionSource, type CodeAgentSessionTerminalStatus, type CodeSurface, type CompareCandidateExperimentOptions, type CompareOptimizationMethodsOptions, type ComparisonCost, type CostLedgerHandle, type CostProvenanceSummary, type CreateChatClientOpts, type DefaultAnalystRegistryOptions, type DefaultProductionGateOptions, type DefineAgentEvalOptions, type DefinedAgentEval, type DeploymentOutcome, type DispatchFn as Dispatch, type DispatchContext, type EvalCellScoreDelta, type EvalDimensionDelta, type EvalGenerationDiff, type EvalReportingSuiteInput, type EvalReportingSuiteOptions, type EvalReportingSuiteResult, type EvalRunDiff, type EvaluatePairedMeasurementsOptions, type EvidenceVector, type ExecutionInsight, type ExecutionReport, type ExternalOptimizationExample, type ExternalTextEvaluationResponse, type ExternalTextOptimizationMethodConfig, type ExternalTextOptimizerContext, type ExternalTextOptimizerResult, type FailureClusterInsight, type FeedbackTableMeta, type FeedbackTableRow, FileSystemOutcomeStore, type FileSystemOutcomeStoreOptions, type FromFeedbackTableOptions, type FromFeedbackTableResult, type FromOtelSpansOptions, type FromRunRecordDirOptions, type FromRunRecordDirResult, type Gate, type GateContext, type GateDecision, type GateResult, type GenerationCandidate, type GenerationRecord, type GepaAdaptiveEngineRun, type GepaEngineOptions, type GepaEngineRun, type GepaOptimizationMethodConfig, type GepaOptimizationRecipe, type GepaRunnerCommand, type HeldOutGateOptions, type HostedTenant, InMemoryOutcomeStore, type InsightReport, type InterRaterInsight, type JudgeConfig, type JudgeDimension, type JudgeInsight, type JudgeScore, type LiftInsight, type LlmJudgeDimension, type LlmJudgeOptions, type MutableSurface, type ObjectiveSource, type OpenAICompatibleOptimizerModel, type OptimizationMethod, type OptimizationMethodComparison, type OptimizationMethodInput, type OptimizationMethodProvenance, type OptimizationMethodResult, type OptimizationPackageSource, type OptimizationProposer, type OptimizationTokenUsage, type OptimizerConfig, type OptimizerModelBudget, type OutcomeCorrelationInsight, type OutcomeStore, type PairedMeasurement, type PairedMeasurementAdapter, type PairedMeasurementEvaluation, type ParetoSignificanceGateOptions, type ParsedCodeAgentJsonl, type PartitionByAuthoringModelResult, type PromotionObjective, type PromotionPolicy, REFERENCE_EQUIVALENCE_INPUT_LIMITS, REFERENCE_EQUIVALENCE_JUDGE_VERSION, type Recommendation, type ReferenceEquivalenceJudgeInput, type ReferenceEquivalenceJudgeOptions, type ReferenceEquivalenceJudgeResult, type ReferenceEquivalenceScenario, type ReleaseSummary, type RunCampaignOptions, type RunCandidateExperimentOptions, type RunEvalOptions, type RunImprovementLoopOptions, type RunImprovementLoopResult, type RunRecordRejection, type ScalarDistribution, type Scenario$1 as Scenario, type SealCandidateBenchmarkSuiteOptions, type SelfImproveBudget, type SelfImproveOptions, type SelfImproveProgressEvent, type SelfImproveResult, SelfImproveRunError, type SessionScript, type SkillOptOptimizationMethodConfig, type SkillOptRunnerCommand, type SkillOptTrainerConfig, type SummarizeExecutionOptions, type SurfaceProposer, type TokenUsageInsight, analyzeRuns, buildDefaultAnalystRegistry, buildEvidenceVector, campaignSplitDigest, compareOptimizationMethods, composeGate, createChatClient, createReferenceEquivalenceJudge, defaultProductionGate, defineAgentEval, diffGenerations, diffRunBaselineToWinner, diffRuns, evalReportingSuite, evaluatePairedMeasurements, externalTextOptimizationMethod, fromClaudeCodeSession, fromCodexSession, fromFeedbackTable, fromKimiCodeSession, fromOpenCodeSession, fromOtelSpans, fromPiSession, fromPigraphSession, fromRunRecordDir, fsCampaignStorage, gepaOptimizationMethod, heldOutGate, inMemoryCampaignStorage, llmJudge, measuredComparisonFromCandidateExperiment, observeCodeAgentSession, paretoPolicy, paretoSignificanceGate, parseAgentTrace, parseCodeAgentJsonl, partitionRunsByAuthoringModel, runCampaign, runCandidateExperiment, runEval, runImprovementLoop, runReferenceEquivalenceJudge, sealCandidateBenchmarkSuite, sealCandidateBenchmarkTask, sealCandidateExperiment, selfImprove, skillOptOptimizationMethod, summarizeExecution, verifyCandidateBenchmarkSuite, verifyCandidateBenchmarkSuiteInputs, verifyCandidateBenchmarkTask, verifyCandidateExperiment, verifyCandidateExperimentComparison };
5809
+ export { type AgentEvalAgent, type AgentEvalEvaluateOptions, type AgentEvalImproveOptions, type AgentTraceContributor, type AgentTraceContributorType, type AgentTraceConversation, type AgentTraceFile, type AgentTraceIndex, type AgentTraceRange, type AgentTraceRecord, type AnalystFinding, type AnalyzeRunsOptions, type AuthoringProvenance, type AxisEvidence, type AxisVerdict, type BuildEvidenceVectorOptions, type CampaignAggregates, type CampaignArtifactWriter, type CampaignCellFailureReceipt, type CampaignCellResult, type CampaignCostMeter, type CampaignResult, type CampaignStorage, type CampaignTraceWriter, type CandidateExperimentExecutionInput, type ChatClient, type CodeAgentSessionAction, type CodeAgentSessionActionKind, type CodeAgentSessionActionStatus, type CodeAgentSessionActionSurface, type CodeAgentSessionDiagnostic, type CodeAgentSessionExecutionReceipt, type CodeAgentSessionIntakeOptions, type CodeAgentSessionIntakeResult, type CodeAgentSessionMetrics, type CodeAgentSessionObservation, type CodeAgentSessionSource, type CodeAgentSessionTerminalStatus, type CodeSurface, type CompareCandidateExperimentOptions, type CompareOptimizationMethodsOptions, type ComparisonCost, type CostLedgerHandle, type CostProvenanceSummary, type CreateChatClientOpts, type DefaultAnalystRegistryOptions, type DefaultProductionGateCheck, type DefaultProductionGateOptions, type DefaultProductionRewardHackingOptions, type DefineAgentEvalOptions, type DefinedAgentEval, type DeploymentOutcome, type DispatchFn as Dispatch, type DispatchContext, type EvalCellScoreDelta, type EvalDimensionDelta, type EvalGenerationDiff, type EvalReportingSuiteInput, type EvalReportingSuiteOptions, type EvalReportingSuiteResult, type EvalRunDiff, type EvaluatePairedMeasurementsOptions, type EvidenceVector, type ExecutionErrorOutcomeCell, type ExecutionInsight, type ExecutionReport, type ExternalOptimizationExample, type ExternalTextEvaluationResponse, type ExternalTextOptimizationMethodConfig, type ExternalTextOptimizerContext, type ExternalTextOptimizerResult, type FailureClassTally, type FailureClusterInsight, type FeedbackTableMeta, type FeedbackTableRow, FileSystemOutcomeStore, type FileSystemOutcomeStoreOptions, type FromFeedbackTableOptions, type FromFeedbackTableResult, type FromOtelSpansOptions, type FromRunRecordDirOptions, type FromRunRecordDirResult, type Gate, type GateCheckStatus, type GateContext, type GateContribution, type GateDecision, type GateResult, type GenerationCandidate, type GenerationRecord, type GepaAdaptiveEngineRun, type GepaEngineOptions, type GepaEngineRun, type GepaOptimizationMethodConfig, type GepaOptimizationRecipe, type GepaRunnerCommand, type HeldOutGateOptions, type HostedTenant, InMemoryOutcomeStore, type InsightReport, type InterRaterInsight, type JudgeConfig, type JudgeDimension, type JudgeInsight, type JudgeScore, type LiftInsight, type LlmJudgeDimension, type LlmJudgeOptions, type MutableSurface, type ObjectiveSource, type OpenAICompatibleOptimizerModel, type OptimizationMethod, type OptimizationMethodComparison, type OptimizationMethodInput, type OptimizationMethodProvenance, type OptimizationMethodResult, type OptimizationPackageSource, type OptimizationProposer, type OptimizationTokenUsage, type OptimizerConfig, type OptimizerModelBudget, type OutcomeCorrelationInsight, type OutcomeStore, type PairedMeasurement, type PairedMeasurementAdapter, type PairedMeasurementEvaluation, type ParetoSignificanceGateOptions, type ParsedCodeAgentJsonl, type PartitionByAuthoringModelResult, type PromotionObjective, type PromotionPolicy, REFERENCE_EQUIVALENCE_INPUT_LIMITS, REFERENCE_EQUIVALENCE_JUDGE_VERSION, type Recommendation, type ReferenceEquivalenceJudgeInput, type ReferenceEquivalenceJudgeOptions, type ReferenceEquivalenceJudgeResult, type ReferenceEquivalenceScenario, type ReleaseSummary, type RunCampaignOptions, type RunCandidateExperimentOptions, type RunEvalOptions, type RunImprovementLoopOptions, type RunImprovementLoopResult, type RunRecordRejection, type ScalarDistribution, type Scenario$1 as Scenario, type SealCandidateBenchmarkSuiteOptions, type SelfImproveBudget, type SelfImproveOptions, type SelfImproveProgressEvent, type SelfImproveResult, SelfImproveRunError, type SessionScript, type SkillOptOptimizationMethodConfig, type SkillOptRunnerCommand, type SkillOptTrainerConfig, type SummarizeExecutionOptions, type SurfaceProposer, type TokenUsageInsight, analyzeRuns, buildDefaultAnalystRegistry, buildEvidenceVector, campaignSplitDigest, compareOptimizationMethods, composeGate, createChatClient, createReferenceEquivalenceJudge, defaultProductionGate, defineAgentEval, diffGenerations, diffRunBaselineToWinner, diffRuns, evalReportingSuite, evaluatePairedMeasurements, externalTextOptimizationMethod, fromClaudeCodeSession, fromCodexSession, fromFeedbackTable, fromKimiCodeSession, fromOpenCodeSession, fromOtelSpans, fromPiSession, fromPigraphSession, fromRunRecordDir, fsCampaignStorage, gepaOptimizationMethod, heldOutGate, inMemoryCampaignStorage, llmJudge, measuredComparisonFromCandidateExperiment, observeCodeAgentSession, paretoPolicy, paretoSignificanceGate, parseAgentTrace, parseCodeAgentJsonl, partitionRunsByAuthoringModel, runCampaign, runCandidateExperiment, runEval, runImprovementLoop, runReferenceEquivalenceJudge, sealCandidateBenchmarkSuite, sealCandidateBenchmarkTask, sealCandidateExperiment, selfImprove, skillOptOptimizationMethod, summarizeExecution, verifyCandidateBenchmarkSuite, verifyCandidateBenchmarkSuiteInputs, verifyCandidateBenchmarkTask, verifyCandidateExperiment, verifyCandidateExperimentComparison };