@tangle-network/agent-eval 0.122.9 → 0.123.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,8 +17,8 @@ import {
17
17
  runBenchmarkAdapter,
18
18
  summarizeBenchmarkCampaign
19
19
  } from "../chunk-FHFTYX2Q.js";
20
- import "../chunk-CWF6SCBK.js";
21
- import "../chunk-4EDDIK77.js";
20
+ import "../chunk-GS3FJGUF.js";
21
+ import "../chunk-HZJF4IUO.js";
22
22
  import "../chunk-3FCG7FBV.js";
23
23
  import "../chunk-FC5NDO3E.js";
24
24
  import "../chunk-ARU2PZFM.js";
@@ -4338,6 +4338,15 @@ type RunImprovementLoopOptions<TScenario extends Scenario, TArtifact> = RunOptim
4338
4338
  /** Holdout scenarios kept OUT of the training optimization pool — used
4339
4339
  * ONLY to score baseline vs winner for the gate. */
4340
4340
  holdoutScenarios: TScenario[];
4341
+ /** Holdout policy. Default `'measured'`: baseline + winner are re-scored on
4342
+ * `holdoutScenarios` and the gate decides on that held-out comparison.
4343
+ * `'deferred'`: the improvement-set (search) campaigns run exactly as usual,
4344
+ * but ZERO holdout cells are dispatched, the gate is forced to `'hold'`, and
4345
+ * the result + provenance record carry `holdout: 'deferred'` with NO
4346
+ * held-out lift — for callers that measure the held-out comparison in a
4347
+ * separate later run instead of faking a static holdout scenario and
4348
+ * recording a meaningless lift. */
4349
+ holdout?: 'measured' | 'deferred';
4341
4350
  /** Promotion gate. Substrate strongly recommends `defaultProductionGate`
4342
4351
  * for production wiring (composes red-team / reward-hacking / canary /
4343
4352
  * heldout). */
@@ -4365,6 +4374,10 @@ interface RunImprovementLoopResult<TArtifact, TScenario extends Scenario> extend
4365
4374
  neutralizedOnHoldout?: CampaignResult<TArtifact, TScenario>;
4366
4375
  neutralizedSurface?: MutableSurface;
4367
4376
  gateResult: Awaited<ReturnType<Gate<TArtifact, TScenario>['decide']>>;
4377
+ /** Present iff the loop ran with `holdout: 'deferred'`. When set,
4378
+ * `baselineOnHoldout`/`winnerOnHoldout` are the shared EMPTY campaign (zero
4379
+ * cells dispatched) and the gate verdict is the forced `'hold'`. */
4380
+ holdout?: 'deferred';
4368
4381
  /** Unified baseline→winner surface diff. Computed UNCONDITIONALLY (not only
4369
4382
  * when `autoOnPromote === 'pr'`) so the diff that the gate decided on is
4370
4383
  * always present on the result + in the emitted provenance record. Empty
@@ -6938,12 +6951,18 @@ interface LoopProvenanceRecord {
6938
6951
  detail: unknown;
6939
6952
  }>;
6940
6953
  };
6941
- /** baseline-on-holdout composite mean. */
6942
- baselineHoldoutComposite: number;
6943
- /** winner-on-holdout composite mean. */
6944
- winnerHoldoutComposite: number;
6945
- /** winnerHoldout - baselineHoldout — RECOMPUTABLE from this record. */
6946
- heldOutLift: number;
6954
+ /** Present iff the loop ran with `holdout: 'deferred'` the held-out
6955
+ * comparison was intentionally not measured in this run, so the holdout
6956
+ * composites and `heldOutLift` are ABSENT rather than recorded as a
6957
+ * meaningless 0. */
6958
+ holdout?: 'deferred';
6959
+ /** baseline-on-holdout composite mean. Absent when `holdout === 'deferred'`. */
6960
+ baselineHoldoutComposite?: number;
6961
+ /** winner-on-holdout composite mean. Absent when `holdout === 'deferred'`. */
6962
+ winnerHoldoutComposite?: number;
6963
+ /** winnerHoldout - baselineHoldout — RECOMPUTABLE from this record. Absent
6964
+ * when `holdout === 'deferred'` (no held-out measurement ran). */
6965
+ heldOutLift?: number;
6947
6966
  /** Backend provenance: stub-vs-real verdict + worker call count + models. */
6948
6967
  backend: LoopProvenanceBackend;
6949
6968
  totalCostUsd: number;
@@ -6973,6 +6992,10 @@ interface BuildLoopProvenanceArgs<TArtifact, TScenario extends Scenario> {
6973
6992
  }>;
6974
6993
  }>;
6975
6994
  gate: GateResult;
6995
+ /** Holdout policy the loop ran with. `'deferred'` ⇒ the holdout campaigns
6996
+ * below are the shared empty campaign and the record omits the holdout
6997
+ * composites + `heldOutLift`. Default `'measured'`. */
6998
+ holdout?: 'measured' | 'deferred';
6976
6999
  baselineOnHoldout: CampaignResult<TArtifact, TScenario>;
6977
7000
  winnerOnHoldout: CampaignResult<TArtifact, TScenario>;
6978
7001
  neutralizedSurface?: MutableSurface;
@@ -68,7 +68,7 @@ import {
68
68
  userStoryScoreboard,
69
69
  validateSearchLedgerEvent,
70
70
  verifyCodeSurface
71
- } from "../chunk-CWF6SCBK.js";
71
+ } from "../chunk-GS3FJGUF.js";
72
72
  import {
73
73
  assertCodeSurfaceIdentity,
74
74
  buildEvidenceVector,
@@ -109,7 +109,7 @@ import {
109
109
  surfaceContentHash,
110
110
  surfaceHash,
111
111
  verifyLoopProvenanceRecord
112
- } from "../chunk-4EDDIK77.js";
112
+ } from "../chunk-HZJF4IUO.js";
113
113
  import {
114
114
  SearchLedgerConflictError,
115
115
  SearchLedgerError,
@@ -15,7 +15,7 @@ import {
15
15
  runImprovementLoop,
16
16
  surfaceContentHash,
17
17
  surfaceHash
18
- } from "./chunk-4EDDIK77.js";
18
+ } from "./chunk-HZJF4IUO.js";
19
19
  import {
20
20
  SearchLedgerConflictError,
21
21
  SearchLedgerError,
@@ -8279,4 +8279,4 @@ export {
8279
8279
  verifyCodeSurface,
8280
8280
  resolveWorktreePath
8281
8281
  };
8282
- //# sourceMappingURL=chunk-CWF6SCBK.js.map
8282
+ //# sourceMappingURL=chunk-GS3FJGUF.js.map
@@ -3006,7 +3006,18 @@ async function runImprovementLoop(opts) {
3006
3006
  const optimization = await runOptimization({ ...opts, dispatchTimeoutMs, costLedger });
3007
3007
  const winnerIsBaseline = optimization.winnerSurfaceHash === surfaceHash(opts.baselineSurface);
3008
3008
  const { runCampaign: runCampaign2 } = await import("./run-campaign-ZKR5MQMQ.js");
3009
- const baselineOnHoldout = await runCampaign2({
3009
+ const holdoutDeferred = (opts.holdout ?? "measured") === "deferred";
3010
+ const baselineOnHoldout = holdoutDeferred ? await runCampaign2({
3011
+ ...opts,
3012
+ costLedger,
3013
+ costPhase: "holdout.deferred",
3014
+ dispatchTimeoutMs,
3015
+ scenarios: [],
3016
+ dispatch: async () => {
3017
+ throw new Error("runImprovementLoop: unreachable dispatch \u2014 holdout is deferred");
3018
+ },
3019
+ runDir: `${opts.runDir}/holdout-deferred`
3020
+ }) : await runCampaign2({
3010
3021
  ...opts,
3011
3022
  costLedger,
3012
3023
  costPhase: "holdout.baseline",
@@ -3015,7 +3026,7 @@ async function runImprovementLoop(opts) {
3015
3026
  dispatch: (scenario, ctx) => opts.dispatchWithSurface(opts.baselineSurface, scenario, ctx),
3016
3027
  runDir: `${opts.runDir}/holdout-baseline`
3017
3028
  });
3018
- const winnerOnHoldout = winnerIsBaseline ? baselineOnHoldout : await runCampaign2({
3029
+ const winnerOnHoldout = winnerIsBaseline || holdoutDeferred ? baselineOnHoldout : await runCampaign2({
3019
3030
  ...opts,
3020
3031
  costLedger,
3021
3032
  costPhase: "holdout.winner",
@@ -3039,8 +3050,10 @@ async function runImprovementLoop(opts) {
3039
3050
  );
3040
3051
  }
3041
3052
  };
3042
- assertCompleteHoldout("baseline", baselineOnHoldout);
3043
- assertCompleteHoldout("winner", winnerOnHoldout);
3053
+ if (!holdoutDeferred) {
3054
+ assertCompleteHoldout("baseline", baselineOnHoldout);
3055
+ assertCompleteHoldout("winner", winnerOnHoldout);
3056
+ }
3044
3057
  const candidateArtifacts = /* @__PURE__ */ new Map();
3045
3058
  const baselineArtifacts = /* @__PURE__ */ new Map();
3046
3059
  const judgeScores = /* @__PURE__ */ new Map();
@@ -3057,7 +3070,7 @@ async function runImprovementLoop(opts) {
3057
3070
  let neutralizedJudgeScores;
3058
3071
  let neutralizedOnHoldout;
3059
3072
  let neutralizedSurface;
3060
- if (opts.neutralize && !winnerIsBaseline) {
3073
+ if (opts.neutralize && !winnerIsBaseline && !holdoutDeferred) {
3061
3074
  const surface = opts.neutralize(optimization.winnerSurface, opts.baselineSurface);
3062
3075
  neutralizedSurface = surface;
3063
3076
  neutralizedOnHoldout = await runCampaign2({
@@ -3077,7 +3090,15 @@ async function runImprovementLoop(opts) {
3077
3090
  neutralizedJudgeScores.set(cell.cellId, cell.judgeScores);
3078
3091
  }
3079
3092
  }
3080
- const gateResult = winnerIsBaseline ? {
3093
+ const gateResult = holdoutDeferred ? {
3094
+ decision: "hold",
3095
+ reasons: [
3096
+ "holdout deferred \u2014 improvement-set search completed without a held-out measurement; nothing to promote from this run"
3097
+ ],
3098
+ contributingGates: [
3099
+ { name: "holdout-deferred", passed: false, detail: { holdout: "deferred" } }
3100
+ ]
3101
+ } : winnerIsBaseline ? {
3081
3102
  decision: "hold",
3082
3103
  reasons: [
3083
3104
  "no candidate beat the training baseline \u2014 winner == baseline (empty diff); nothing to promote"
@@ -3118,6 +3139,7 @@ async function runImprovementLoop(opts) {
3118
3139
  baselineOnHoldout,
3119
3140
  winnerOnHoldout,
3120
3141
  ...neutralizedOnHoldout && neutralizedSurface ? { neutralizedOnHoldout, neutralizedSurface } : {},
3142
+ ...holdoutDeferred ? { holdout: "deferred" } : {},
3121
3143
  gateResult,
3122
3144
  promotedDiff,
3123
3145
  prResult,
@@ -3170,6 +3192,7 @@ function loopProvenanceArgsFromResult(input) {
3170
3192
  }))
3171
3193
  })),
3172
3194
  gate: result.gateResult,
3195
+ ...result.holdout === "deferred" ? { holdout: "deferred" } : {},
3173
3196
  baselineOnHoldout: result.baselineOnHoldout,
3174
3197
  winnerOnHoldout: result.winnerOnHoldout,
3175
3198
  ...result.neutralizedSurface && result.neutralizedOnHoldout ? {
@@ -3305,6 +3328,7 @@ function buildLoopProvenanceRecord(args) {
3305
3328
  "buildLoopProvenanceRecord: winner surface does not match the final promoted incumbent"
3306
3329
  );
3307
3330
  }
3331
+ const holdoutDeferred = args.holdout === "deferred";
3308
3332
  const baselineHoldoutComposite = meanHoldoutComposite(args.baselineOnHoldout);
3309
3333
  const winnerHoldoutComposite = meanHoldoutComposite(args.winnerOnHoldout);
3310
3334
  if (args.baselineOnHoldout.splitDigest !== args.winnerOnHoldout.splitDigest) {
@@ -3364,9 +3388,13 @@ function buildLoopProvenanceRecord(args) {
3364
3388
  detail: durableGateDetail(g.detail)
3365
3389
  }))
3366
3390
  },
3367
- baselineHoldoutComposite,
3368
- winnerHoldoutComposite,
3369
- heldOutLift: winnerHoldoutComposite - baselineHoldoutComposite,
3391
+ // Deferred holdout records the MODE, never a fabricated 0-lift: the
3392
+ // held-out comparison intentionally did not run in this loop.
3393
+ ...holdoutDeferred ? { holdout: "deferred" } : {
3394
+ baselineHoldoutComposite,
3395
+ winnerHoldoutComposite,
3396
+ heldOutLift: winnerHoldoutComposite - baselineHoldoutComposite
3397
+ },
3370
3398
  backend: {
3371
3399
  verdict: integrity.verdict,
3372
3400
  workerCallCount: integrity.totalRecords,
@@ -3537,24 +3565,26 @@ function loopProvenanceSpans(record, opts = {}) {
3537
3565
  const endNano = baseNano + Math.max(1, record.totalDurationMs) * 1e6;
3538
3566
  const spans = [];
3539
3567
  const rootSpanId = hashId(["root", record.runId]).slice(0, 16);
3568
+ const rootAttributes = {
3569
+ "tangle.runId": record.runId,
3570
+ "tangle.runDir": record.runDir,
3571
+ "tangle.baselineContentHash": record.baselineContentHash,
3572
+ "tangle.winnerContentHash": record.winnerContentHash,
3573
+ "tangle.baselineSearchComposite": record.baselineSearchComposite,
3574
+ "tangle.gateDecision": record.gate.decision,
3575
+ "tangle.backendVerdict": record.backend.verdict,
3576
+ "tangle.workerCallCount": record.backend.workerCallCount,
3577
+ "tangle.totalCostUsd": record.totalCostUsd
3578
+ };
3579
+ if (record.heldOutLift !== void 0) rootAttributes["tangle.heldOutLift"] = record.heldOutLift;
3580
+ if (record.holdout) rootAttributes["tangle.holdout"] = record.holdout;
3540
3581
  spans.push({
3541
3582
  traceId,
3542
3583
  spanId: rootSpanId,
3543
3584
  name: "improvement-loop",
3544
3585
  startTimeUnixNano: baseNano,
3545
3586
  endTimeUnixNano: endNano,
3546
- attributes: {
3547
- "tangle.runId": record.runId,
3548
- "tangle.runDir": record.runDir,
3549
- "tangle.baselineContentHash": record.baselineContentHash,
3550
- "tangle.winnerContentHash": record.winnerContentHash,
3551
- "tangle.baselineSearchComposite": record.baselineSearchComposite,
3552
- "tangle.heldOutLift": record.heldOutLift,
3553
- "tangle.gateDecision": record.gate.decision,
3554
- "tangle.backendVerdict": record.backend.verdict,
3555
- "tangle.workerCallCount": record.backend.workerCallCount,
3556
- "tangle.totalCostUsd": record.totalCostUsd
3557
- },
3587
+ attributes: rootAttributes,
3558
3588
  status: gateStatus(record.gate.decision),
3559
3589
  "tangle.runId": record.runId
3560
3590
  });
@@ -3625,6 +3655,21 @@ function loopProvenanceSpans(record, opts = {}) {
3625
3655
  }
3626
3656
  }
3627
3657
  const gateSpanId = hashId(["gate", record.runId]).slice(0, 16);
3658
+ const gateAttributes = {
3659
+ "tangle.runId": record.runId,
3660
+ "tangle.gateDecision": record.gate.decision,
3661
+ "tangle.gateReasons": JSON.stringify(record.gate.reasons)
3662
+ };
3663
+ const gateDelta = record.gate.delta ?? record.heldOutLift;
3664
+ if (gateDelta !== void 0) gateAttributes["tangle.gateDelta"] = gateDelta;
3665
+ if (record.heldOutLift !== void 0) gateAttributes["tangle.heldOutLift"] = record.heldOutLift;
3666
+ if (record.baselineHoldoutComposite !== void 0) {
3667
+ gateAttributes["tangle.baselineHoldoutComposite"] = record.baselineHoldoutComposite;
3668
+ }
3669
+ if (record.winnerHoldoutComposite !== void 0) {
3670
+ gateAttributes["tangle.winnerHoldoutComposite"] = record.winnerHoldoutComposite;
3671
+ }
3672
+ if (record.holdout) gateAttributes["tangle.holdout"] = record.holdout;
3628
3673
  spans.push({
3629
3674
  traceId,
3630
3675
  spanId: gateSpanId,
@@ -3632,15 +3677,7 @@ function loopProvenanceSpans(record, opts = {}) {
3632
3677
  name: "gate-decision",
3633
3678
  startTimeUnixNano: endNano,
3634
3679
  endTimeUnixNano: endNano,
3635
- attributes: {
3636
- "tangle.runId": record.runId,
3637
- "tangle.gateDecision": record.gate.decision,
3638
- "tangle.gateDelta": record.gate.delta ?? record.heldOutLift,
3639
- "tangle.gateReasons": JSON.stringify(record.gate.reasons),
3640
- "tangle.heldOutLift": record.heldOutLift,
3641
- "tangle.baselineHoldoutComposite": record.baselineHoldoutComposite,
3642
- "tangle.winnerHoldoutComposite": record.winnerHoldoutComposite
3643
- },
3680
+ attributes: gateAttributes,
3644
3681
  status: gateStatus(record.gate.decision),
3645
3682
  "tangle.runId": record.runId
3646
3683
  });
@@ -3695,7 +3732,9 @@ function buildEvalRunEvent(args, record) {
3695
3732
  snapshotFromHoldout(1, record.winnerContentHash, args.winnerSurface, args.winnerOnHoldout)
3696
3733
  ],
3697
3734
  gateDecision: args.gate.decision,
3698
- holdoutLift: record.heldOutLift,
3735
+ // Deferred holdout ships NO lift — the wire field is optional and a 0
3736
+ // would read downstream as a measured no-improvement.
3737
+ ...record.heldOutLift !== void 0 ? { holdoutLift: record.heldOutLift } : {},
3699
3738
  totalCostUsd: args.totalCostUsd,
3700
3739
  totalDurationMs: args.totalDurationMs
3701
3740
  };
@@ -3797,4 +3836,4 @@ export {
3797
3836
  provenanceSpansPath,
3798
3837
  emitLoopProvenance
3799
3838
  };
3800
- //# sourceMappingURL=chunk-4EDDIK77.js.map
3839
+ //# sourceMappingURL=chunk-HZJF4IUO.js.map