@tangle-network/agent-eval 0.110.1 → 0.111.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 (48) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/belief-state/index.js +1 -1
  3. package/dist/benchmarks/index.js +6 -6
  4. package/dist/builder-eval/index.js +1 -1
  5. package/dist/campaign/index.d.ts +2 -2
  6. package/dist/campaign/index.js +5 -5
  7. package/dist/{chunk-X6NIXVOD.js → chunk-3LDPUYAC.js} +2 -2
  8. package/dist/{chunk-N22ZO7FV.js → chunk-7QPK6W7R.js} +2 -2
  9. package/dist/{chunk-QFGTU7MT.js → chunk-BOLYPSAE.js} +4 -4
  10. package/dist/{chunk-GBI5J5DB.js → chunk-D2XDWRFX.js} +4 -4
  11. package/dist/{chunk-6MFFKPZ4.js → chunk-EMKORATZ.js} +2 -2
  12. package/dist/{chunk-J4AKLZEV.js → chunk-RCXMWGRY.js} +5 -5
  13. package/dist/{chunk-6HFYGEZ3.js → chunk-RT2AFUXM.js} +2 -2
  14. package/dist/{chunk-XMSYF4A7.js → chunk-VC43KQCK.js} +24 -1
  15. package/dist/chunk-VC43KQCK.js.map +1 -0
  16. package/dist/{chunk-T6W5ADLG.js → chunk-VLNGPUJJ.js} +2 -2
  17. package/dist/{chunk-6PL5MGDL.js → chunk-WZOIFFG2.js} +2 -2
  18. package/dist/{chunk-3PFZBGMR.js → chunk-XNCF3JU3.js} +2 -2
  19. package/dist/{chunk-PLOMR3HP.js → chunk-YWGKQARF.js} +2 -2
  20. package/dist/contract/index.d.ts +3 -3
  21. package/dist/contract/index.js +6 -6
  22. package/dist/index.d.ts +120 -3
  23. package/dist/index.js +470 -210
  24. package/dist/index.js.map +1 -1
  25. package/dist/meta-eval/index.d.ts +1 -1
  26. package/dist/meta-eval/index.js +2 -2
  27. package/dist/openapi.json +1 -1
  28. package/dist/pipelines/index.js +2 -2
  29. package/dist/{provenance-CyxkvEi9.d.ts → provenance-KhY8ESVM.d.ts} +1 -1
  30. package/dist/reporting.d.ts +1 -1
  31. package/dist/reporting.js +4 -4
  32. package/dist/rl.js +5 -5
  33. package/dist/{run-campaign-PNHAJIT2.js → run-campaign-HJQEDCJQ.js} +3 -3
  34. package/dist/{statistics-D88peojY.d.ts → statistics-CDfpwIdX.d.ts} +13 -1
  35. package/package.json +1 -1
  36. package/dist/chunk-XMSYF4A7.js.map +0 -1
  37. /package/dist/{chunk-X6NIXVOD.js.map → chunk-3LDPUYAC.js.map} +0 -0
  38. /package/dist/{chunk-N22ZO7FV.js.map → chunk-7QPK6W7R.js.map} +0 -0
  39. /package/dist/{chunk-QFGTU7MT.js.map → chunk-BOLYPSAE.js.map} +0 -0
  40. /package/dist/{chunk-GBI5J5DB.js.map → chunk-D2XDWRFX.js.map} +0 -0
  41. /package/dist/{chunk-6MFFKPZ4.js.map → chunk-EMKORATZ.js.map} +0 -0
  42. /package/dist/{chunk-J4AKLZEV.js.map → chunk-RCXMWGRY.js.map} +0 -0
  43. /package/dist/{chunk-6HFYGEZ3.js.map → chunk-RT2AFUXM.js.map} +0 -0
  44. /package/dist/{chunk-T6W5ADLG.js.map → chunk-VLNGPUJJ.js.map} +0 -0
  45. /package/dist/{chunk-6PL5MGDL.js.map → chunk-WZOIFFG2.js.map} +0 -0
  46. /package/dist/{chunk-3PFZBGMR.js.map → chunk-XNCF3JU3.js.map} +0 -0
  47. /package/dist/{chunk-PLOMR3HP.js.map → chunk-YWGKQARF.js.map} +0 -0
  48. /package/dist/{run-campaign-PNHAJIT2.js.map → run-campaign-HJQEDCJQ.js.map} +0 -0
package/dist/index.js CHANGED
@@ -9,12 +9,12 @@ import {
9
9
  checkBehavioralCanary,
10
10
  checkCanaries,
11
11
  runBehavioralCanaries
12
- } from "./chunk-QFGTU7MT.js";
12
+ } from "./chunk-BOLYPSAE.js";
13
13
  import {
14
14
  BENCHMARK_SPLIT_SEED,
15
15
  benchmarks_exports,
16
16
  deterministicSplit
17
- } from "./chunk-T6W5ADLG.js";
17
+ } from "./chunk-VLNGPUJJ.js";
18
18
  import {
19
19
  DEFAULT_RULES,
20
20
  buildTrajectory,
@@ -23,7 +23,7 @@ import {
23
23
  computeToolUseMetrics,
24
24
  iqr,
25
25
  welchsTTest
26
- } from "./chunk-PLOMR3HP.js";
26
+ } from "./chunk-YWGKQARF.js";
27
27
  import {
28
28
  analyzeSeries
29
29
  } from "./chunk-BOD4O7OF.js";
@@ -59,7 +59,7 @@ import {
59
59
  llmJudge,
60
60
  parseCorrectnessResponse,
61
61
  verifyCompletion
62
- } from "./chunk-GBI5J5DB.js";
62
+ } from "./chunk-D2XDWRFX.js";
63
63
  import {
64
64
  DEFAULT_MUTATION_PRIMITIVES,
65
65
  DEFAULT_RED_TEAM_CORPUS,
@@ -83,7 +83,7 @@ import {
83
83
  scoreRedTeamOutput,
84
84
  surfaceContentHash,
85
85
  toolNamesForRun
86
- } from "./chunk-J4AKLZEV.js";
86
+ } from "./chunk-RCXMWGRY.js";
87
87
  import {
88
88
  MODEL_PRICING,
89
89
  MetricsCollector,
@@ -102,7 +102,7 @@ import {
102
102
  fileVerdictCache,
103
103
  inMemoryVerdictCache,
104
104
  summarizeBackendIntegrity
105
- } from "./chunk-3PFZBGMR.js";
105
+ } from "./chunk-XNCF3JU3.js";
106
106
  import {
107
107
  DEFAULT_COMPLEXITY_WEIGHTS,
108
108
  FindingsStore,
@@ -179,11 +179,11 @@ import {
179
179
  evaluateReleaseConfidence,
180
180
  judgeReplayGate,
181
181
  renderReleaseReport
182
- } from "./chunk-6HFYGEZ3.js";
182
+ } from "./chunk-RT2AFUXM.js";
183
183
  import {
184
184
  runEvalCampaign
185
- } from "./chunk-6PL5MGDL.js";
186
- import "./chunk-N22ZO7FV.js";
185
+ } from "./chunk-WZOIFFG2.js";
186
+ import "./chunk-7QPK6W7R.js";
187
187
  import {
188
188
  evaluateInterimReleaseConfidence,
189
189
  pairedEvalueSequence
@@ -194,7 +194,7 @@ import {
194
194
  paretoChart,
195
195
  researchReport,
196
196
  summaryTable
197
- } from "./chunk-6MFFKPZ4.js";
197
+ } from "./chunk-EMKORATZ.js";
198
198
  import {
199
199
  benjaminiHochberg,
200
200
  bonferroni,
@@ -207,6 +207,7 @@ import {
207
207
  corpusInterRaterAgreement,
208
208
  corpusInterRaterAgreementFromJudgeScores,
209
209
  eProcess,
210
+ holm,
210
211
  interRaterReliability,
211
212
  interpretCliffs,
212
213
  mannWhitneyU,
@@ -232,7 +233,7 @@ import {
232
233
  weightedMean,
233
234
  wilcoxonSignedRank,
234
235
  wilson
235
- } from "./chunk-XMSYF4A7.js";
236
+ } from "./chunk-VC43KQCK.js";
236
237
  import {
237
238
  FileSystemTraceStore,
238
239
  InMemoryTraceStore,
@@ -1300,6 +1301,412 @@ async function runE2EWorkflow(client, name, workflow) {
1300
1301
  };
1301
1302
  }
1302
1303
 
1304
+ // src/paired-arms.ts
1305
+ function pairArms(rows, opts) {
1306
+ const { baselineArm, treatmentArm } = opts;
1307
+ if (baselineArm === treatmentArm) {
1308
+ throw new ValidationError(
1309
+ `pairArms: baselineArm and treatmentArm are both '${baselineArm}' \u2014 an arm cannot be compared to itself`
1310
+ );
1311
+ }
1312
+ const byArm = /* @__PURE__ */ new Map();
1313
+ const armsSeen = /* @__PURE__ */ new Set();
1314
+ for (const row of rows) {
1315
+ armsSeen.add(row.arm);
1316
+ if (row.arm !== baselineArm && row.arm !== treatmentArm) continue;
1317
+ const byKey = byArm.get(row.arm) ?? /* @__PURE__ */ new Map();
1318
+ const group = byKey.get(row.pairKey) ?? [];
1319
+ group.push(row);
1320
+ byKey.set(row.pairKey, group);
1321
+ byArm.set(row.arm, byKey);
1322
+ }
1323
+ for (const arm of [baselineArm, treatmentArm]) {
1324
+ if (!byArm.has(arm)) {
1325
+ const seen = [...armsSeen].sort().join(", ") || "<none>";
1326
+ throw new ValidationError(`pairArms: no rows for arm '${arm}' (arms present: ${seen})`);
1327
+ }
1328
+ }
1329
+ const baselineByKey = byArm.get(baselineArm);
1330
+ const treatmentByKey = byArm.get(treatmentArm);
1331
+ const allKeys = [.../* @__PURE__ */ new Set([...baselineByKey.keys(), ...treatmentByKey.keys()])].sort();
1332
+ const pairs = [];
1333
+ const unpairedBaseline = [];
1334
+ const unpairedTreatment = [];
1335
+ for (const pairKey2 of allKeys) {
1336
+ const b = baselineByKey.get(pairKey2) ?? [];
1337
+ const t = treatmentByKey.get(pairKey2) ?? [];
1338
+ if (b.length <= 1 && t.length <= 1) {
1339
+ if (b.length === 1 && t.length === 1) {
1340
+ pairs.push({ pairKey: pairKey2, repIndex: 0, baseline: b[0], treatment: t[0] });
1341
+ } else {
1342
+ unpairedBaseline.push(...b);
1343
+ unpairedTreatment.push(...t);
1344
+ }
1345
+ continue;
1346
+ }
1347
+ const bByRep = indexByRepKey(b, pairKey2, baselineArm);
1348
+ const tByRep = indexByRepKey(t, pairKey2, treatmentArm);
1349
+ const repKeys = [.../* @__PURE__ */ new Set([...bByRep.keys(), ...tByRep.keys()])].sort();
1350
+ let repIndex = 0;
1351
+ for (const repKey of repKeys) {
1352
+ const baseline = bByRep.get(repKey);
1353
+ const treatment = tByRep.get(repKey);
1354
+ if (baseline !== void 0 && treatment !== void 0) {
1355
+ pairs.push({ pairKey: pairKey2, repIndex: repIndex++, baseline, treatment });
1356
+ } else if (baseline !== void 0) {
1357
+ unpairedBaseline.push(baseline);
1358
+ } else if (treatment !== void 0) {
1359
+ unpairedTreatment.push(treatment);
1360
+ }
1361
+ }
1362
+ }
1363
+ return { pairs, unpairedBaseline, unpairedTreatment };
1364
+ }
1365
+ function indexByRepKey(group, pairKey2, arm) {
1366
+ const byRep = /* @__PURE__ */ new Map();
1367
+ for (const row of group) {
1368
+ if (row.repKey === void 0) {
1369
+ throw new ValidationError(
1370
+ `pairArms: pairKey '${pairKey2}' has multiple reps in an arm, but a row in arm '${arm}' is missing repKey \u2014 multi-rep items require an explicit repKey on every row so reps pair by identity (pairing reps by outcome or by index would bias the paired statistics)`
1371
+ );
1372
+ }
1373
+ if (byRep.has(row.repKey)) {
1374
+ throw new ValidationError(
1375
+ `pairArms: duplicate repKey '${row.repKey}' for pairKey '${pairKey2}' in arm '${arm}' \u2014 (pairKey, repKey) must uniquely identify a rep within an arm`
1376
+ );
1377
+ }
1378
+ byRep.set(row.repKey, row);
1379
+ }
1380
+ return byRep;
1381
+ }
1382
+ function comparePairedArms(rows, opts) {
1383
+ const { pairs, unpairedBaseline, unpairedTreatment } = pairArms(rows, opts);
1384
+ let correctness = null;
1385
+ const baselinePass = [];
1386
+ const treatmentPass = [];
1387
+ for (const pair of pairs) {
1388
+ if (pair.baseline.pass === void 0 || pair.treatment.pass === void 0) continue;
1389
+ baselinePass.push(pair.baseline.pass ? 1 : 0);
1390
+ treatmentPass.push(pair.treatment.pass ? 1 : 0);
1391
+ }
1392
+ if (baselinePass.length > 0) {
1393
+ const mc = mcnemar(baselinePass, treatmentPass);
1394
+ correctness = {
1395
+ b10: mc.b,
1396
+ b01: mc.c,
1397
+ mcnemar: mc,
1398
+ riskDifference: pairedRiskDifference(baselinePass, treatmentPass)
1399
+ };
1400
+ }
1401
+ const metricNames = opts.metricNames ?? [
1402
+ ...new Set(
1403
+ pairs.flatMap((p) => [
1404
+ ...Object.keys(p.baseline.metrics ?? {}),
1405
+ ...Object.keys(p.treatment.metrics ?? {})
1406
+ ])
1407
+ )
1408
+ ].sort();
1409
+ const metricDeltas = metricNames.map((name) => {
1410
+ const before = [];
1411
+ const after = [];
1412
+ let nMissing = 0;
1413
+ for (const pair of pairs) {
1414
+ const b = metricValue(pair.baseline, name);
1415
+ const t = metricValue(pair.treatment, name);
1416
+ if (b === void 0 || t === void 0) {
1417
+ nMissing++;
1418
+ continue;
1419
+ }
1420
+ before.push(b);
1421
+ after.push(t);
1422
+ }
1423
+ const bootstrapCi2 = before.length === 0 ? null : pairedBootstrap(before, after, opts.bootstrap);
1424
+ return {
1425
+ name,
1426
+ n: before.length,
1427
+ nMissing,
1428
+ medianDelta: bootstrapCi2 === null ? Number.NaN : bootstrapCi2.median,
1429
+ meanDelta: bootstrapCi2 === null ? Number.NaN : bootstrapCi2.mean,
1430
+ bootstrapCi: bootstrapCi2,
1431
+ wilcoxon: before.length === 0 ? null : wilcoxonSignedRank(before, after)
1432
+ };
1433
+ });
1434
+ return {
1435
+ nPairs: pairs.length,
1436
+ nUnpairedBaseline: unpairedBaseline.length,
1437
+ nUnpairedTreatment: unpairedTreatment.length,
1438
+ correctness,
1439
+ metricDeltas
1440
+ };
1441
+ }
1442
+ function metricValue(row, name) {
1443
+ const v = row.metrics?.[name];
1444
+ if (v === void 0) return void 0;
1445
+ if (!Number.isFinite(v)) {
1446
+ throw new ValidationError(
1447
+ `comparePairedArms: non-finite value for metric '${name}' on pairKey '${row.pairKey}' (arm '${row.arm}'): ${v}`
1448
+ );
1449
+ }
1450
+ return v;
1451
+ }
1452
+
1453
+ // src/clustered-paired-binary.ts
1454
+ var DEFAULT_BOOTSTRAP_RESAMPLES = 1e4;
1455
+ var DEFAULT_SIGN_FLIP_RESAMPLES = 1e5;
1456
+ var MAX_RESAMPLES = 1e6;
1457
+ var DEFAULT_EXACT_CLUSTER_LIMIT = 20;
1458
+ var SIGN_FLIP_SEED_SALT = 2654435769;
1459
+ function clusteredPairedBinary(rows, options) {
1460
+ const config = validateOptions(options);
1461
+ const projected = projectSelectedRows(rows, options);
1462
+ const paired = pairArms(projected, {
1463
+ baselineArm: options.baselineArm,
1464
+ treatmentArm: options.treatmentArm
1465
+ });
1466
+ const matchedPairs = paired.pairs.map((pair) => {
1467
+ const baseline = pair.baseline;
1468
+ const treatment = pair.treatment;
1469
+ if (baseline.clusterKey !== treatment.clusterKey) {
1470
+ throw new ValidationError(
1471
+ `clusteredPairedBinary: pairKey '${pair.pairKey}' rep ${pair.repIndex} crosses clusters ('${baseline.clusterKey}' vs '${treatment.clusterKey}')`
1472
+ );
1473
+ }
1474
+ return {
1475
+ pairKey: pair.pairKey,
1476
+ repIndex: pair.repIndex,
1477
+ clusterKey: baseline.clusterKey,
1478
+ baseline: baseline.original,
1479
+ treatment: treatment.original,
1480
+ baselinePass: baseline.pass,
1481
+ treatmentPass: treatment.pass
1482
+ };
1483
+ });
1484
+ const unpairedBaseline = paired.unpairedBaseline.map(
1485
+ (row) => row.original
1486
+ );
1487
+ const unpairedTreatment = paired.unpairedTreatment.map(
1488
+ (row) => row.original
1489
+ );
1490
+ if (matchedPairs.length === 0) {
1491
+ return { matchedPairs, unpairedBaseline, unpairedTreatment, statistics: null };
1492
+ }
1493
+ const clusters = summarizeClusters(matchedPairs);
1494
+ const b10 = clusters.reduce((sum4, cluster) => sum4 + cluster.b10, 0);
1495
+ const b01 = clusters.reduce((sum4, cluster) => sum4 + cluster.b01, 0);
1496
+ const taskWeightedRiskDifference = (b10 - b01) / matchedPairs.length;
1497
+ const equalClusterMean = mean(clusters.map((cluster) => cluster.meanDifference));
1498
+ const bootstrap = clusters.length < 2 ? null : clusterBootstrap(clusters, config);
1499
+ const signFlip = clusterSignFlip(clusters, config);
1500
+ return {
1501
+ matchedPairs,
1502
+ unpairedBaseline,
1503
+ unpairedTreatment,
1504
+ statistics: {
1505
+ nPairs: matchedPairs.length,
1506
+ nClusters: clusters.length,
1507
+ b10,
1508
+ b01,
1509
+ taskWeightedRiskDifference,
1510
+ equalClusterMean,
1511
+ clusters,
1512
+ bootstrap,
1513
+ signFlip
1514
+ }
1515
+ };
1516
+ }
1517
+ function validateOptions(options) {
1518
+ assertNonEmptyString("baselineArm", options.baselineArm);
1519
+ assertNonEmptyString("treatmentArm", options.treatmentArm);
1520
+ if (options.baselineArm === options.treatmentArm) {
1521
+ throw new ValidationError(
1522
+ `clusteredPairedBinary: baselineArm and treatmentArm are both '${options.baselineArm}'`
1523
+ );
1524
+ }
1525
+ if (!Number.isInteger(options.seed)) {
1526
+ throw new ValidationError(`clusteredPairedBinary: seed must be an integer, got ${options.seed}`);
1527
+ }
1528
+ const confidence = options.confidence ?? 0.95;
1529
+ if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) {
1530
+ throw new ValidationError(
1531
+ `clusteredPairedBinary: confidence must be in (0,1), got ${confidence}`
1532
+ );
1533
+ }
1534
+ const bootstrapResamples = options.bootstrapResamples ?? DEFAULT_BOOTSTRAP_RESAMPLES;
1535
+ assertResampleCount("bootstrapResamples", bootstrapResamples);
1536
+ const rawMinimumBootstrapResamples = 2 / (1 - confidence);
1537
+ const minimumBootstrapResamples = Math.ceil(
1538
+ rawMinimumBootstrapResamples - Number.EPSILON * Math.max(1, rawMinimumBootstrapResamples) * 8
1539
+ );
1540
+ if (bootstrapResamples < minimumBootstrapResamples) {
1541
+ throw new ValidationError(
1542
+ `clusteredPairedBinary: bootstrapResamples must be at least ${minimumBootstrapResamples} for confidence ${confidence} so both interval tails are represented, got ${bootstrapResamples}`
1543
+ );
1544
+ }
1545
+ const signFlipResamples = options.signFlipResamples ?? DEFAULT_SIGN_FLIP_RESAMPLES;
1546
+ assertResampleCount("signFlipResamples", signFlipResamples);
1547
+ const exactClusterLimit = options.exactClusterLimit ?? DEFAULT_EXACT_CLUSTER_LIMIT;
1548
+ if (!Number.isInteger(exactClusterLimit) || exactClusterLimit < 0 || exactClusterLimit > DEFAULT_EXACT_CLUSTER_LIMIT) {
1549
+ throw new ValidationError(
1550
+ `clusteredPairedBinary: exactClusterLimit must be an integer in [0,${DEFAULT_EXACT_CLUSTER_LIMIT}], got ${exactClusterLimit}`
1551
+ );
1552
+ }
1553
+ const alternative = options.alternative ?? "two-sided";
1554
+ if (alternative !== "two-sided" && alternative !== "greater" && alternative !== "less") {
1555
+ throw new ValidationError(
1556
+ `clusteredPairedBinary: alternative must be 'two-sided', 'greater', or 'less', got ${String(alternative)}`
1557
+ );
1558
+ }
1559
+ return {
1560
+ seed: options.seed,
1561
+ confidence,
1562
+ bootstrapResamples,
1563
+ alternative,
1564
+ exactClusterLimit,
1565
+ signFlipResamples
1566
+ };
1567
+ }
1568
+ function assertResampleCount(name, value) {
1569
+ if (!Number.isInteger(value) || value <= 0) {
1570
+ throw new ValidationError(
1571
+ `clusteredPairedBinary: ${name} must be a positive integer, got ${value}`
1572
+ );
1573
+ }
1574
+ if (value > MAX_RESAMPLES) {
1575
+ throw new ValidationError(
1576
+ `clusteredPairedBinary: ${name} must not exceed ${MAX_RESAMPLES}, got ${value}`
1577
+ );
1578
+ }
1579
+ }
1580
+ function projectSelectedRows(rows, options) {
1581
+ const projected = [];
1582
+ for (const original of rows) {
1583
+ const arm = options.arm(original);
1584
+ assertNonEmptyString("arm", arm);
1585
+ if (arm !== options.baselineArm && arm !== options.treatmentArm) continue;
1586
+ const pairKey2 = options.pairKey(original);
1587
+ const clusterKey = options.clusterKey(original);
1588
+ const pass = options.pass(original);
1589
+ const repKey = options.repKey?.(original);
1590
+ assertNonEmptyString("pairKey", pairKey2);
1591
+ assertNonEmptyString("clusterKey", clusterKey);
1592
+ if (typeof pass !== "boolean") {
1593
+ throw new ValidationError(
1594
+ `clusteredPairedBinary: pass accessor must return boolean for pairKey '${pairKey2}'`
1595
+ );
1596
+ }
1597
+ if (repKey !== void 0) assertNonEmptyString("repKey", repKey);
1598
+ projected.push({ pairKey: pairKey2, clusterKey, arm, pass, repKey, original });
1599
+ }
1600
+ return projected;
1601
+ }
1602
+ function assertNonEmptyString(name, value) {
1603
+ if (typeof value !== "string" || value.trim().length === 0) {
1604
+ throw new ValidationError(
1605
+ `clusteredPairedBinary: ${name} accessor must return a non-empty string`
1606
+ );
1607
+ }
1608
+ }
1609
+ function summarizeClusters(pairs) {
1610
+ const byCluster = /* @__PURE__ */ new Map();
1611
+ for (const pair of pairs) {
1612
+ const summary = byCluster.get(pair.clusterKey) ?? { nPairs: 0, b10: 0, b01: 0 };
1613
+ summary.nPairs++;
1614
+ if (pair.treatmentPass && !pair.baselinePass) summary.b10++;
1615
+ else if (pair.baselinePass && !pair.treatmentPass) summary.b01++;
1616
+ byCluster.set(pair.clusterKey, summary);
1617
+ }
1618
+ return [...byCluster.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([clusterKey, summary]) => ({
1619
+ clusterKey,
1620
+ ...summary,
1621
+ meanDifference: (summary.b10 - summary.b01) / summary.nPairs
1622
+ }));
1623
+ }
1624
+ function clusterBootstrap(clusters, config) {
1625
+ const rng = mulberry32(config.seed);
1626
+ const samples = new Array(config.bootstrapResamples);
1627
+ for (let draw = 0; draw < config.bootstrapResamples; draw++) {
1628
+ let differenceSum = 0;
1629
+ let pairCount = 0;
1630
+ for (let index = 0; index < clusters.length; index++) {
1631
+ const cluster = clusters[Math.floor(rng() * clusters.length)];
1632
+ differenceSum += cluster.b10 - cluster.b01;
1633
+ pairCount += cluster.nPairs;
1634
+ }
1635
+ samples[draw] = differenceSum / pairCount;
1636
+ }
1637
+ samples.sort((a, b) => a - b);
1638
+ const alpha = 1 - config.confidence;
1639
+ const lowerIndex = Math.floor(alpha / 2 * config.bootstrapResamples);
1640
+ const upperIndex = Math.min(
1641
+ config.bootstrapResamples - 1,
1642
+ Math.ceil((1 - alpha / 2) * config.bootstrapResamples) - 1
1643
+ );
1644
+ return {
1645
+ statistic: "task-weighted-risk-difference",
1646
+ lower: samples[lowerIndex],
1647
+ upper: samples[Math.max(lowerIndex, upperIndex)],
1648
+ confidence: config.confidence,
1649
+ resamples: config.bootstrapResamples,
1650
+ seed: config.seed
1651
+ };
1652
+ }
1653
+ function clusterSignFlip(clusters, config) {
1654
+ const clusterTotals = clusters.map((cluster) => cluster.b10 - cluster.b01);
1655
+ const nonZero = clusterTotals.filter((delta) => delta !== 0);
1656
+ const totalPairs = clusters.reduce((sum4, cluster) => sum4 + cluster.nPairs, 0);
1657
+ const statistic = clusterTotals.reduce((sum4, delta) => sum4 + delta, 0) / totalPairs;
1658
+ if (nonZero.length <= config.exactClusterLimit) {
1659
+ const assignments = 2 ** nonZero.length;
1660
+ let extreme2 = 0;
1661
+ for (let mask = 0; mask < assignments; mask++) {
1662
+ let sum4 = 0;
1663
+ for (let index = 0; index < nonZero.length; index++) {
1664
+ sum4 += (mask & 2 ** index ? 1 : -1) * nonZero[index];
1665
+ }
1666
+ const permuted = sum4 / totalPairs;
1667
+ if (isExtreme(permuted, statistic, config.alternative)) extreme2++;
1668
+ }
1669
+ return {
1670
+ statistic,
1671
+ pValue: extreme2 / assignments,
1672
+ alternative: config.alternative,
1673
+ method: "exact",
1674
+ assignments,
1675
+ nClusters: clusters.length,
1676
+ nNonZeroClusters: nonZero.length,
1677
+ seed: null
1678
+ };
1679
+ }
1680
+ const signFlipSeed = (config.seed ^ SIGN_FLIP_SEED_SALT) >>> 0;
1681
+ const rng = mulberry32(signFlipSeed);
1682
+ let extreme = 0;
1683
+ for (let draw = 0; draw < config.signFlipResamples; draw++) {
1684
+ let sum4 = 0;
1685
+ for (const delta of nonZero) sum4 += (rng() < 0.5 ? -1 : 1) * delta;
1686
+ const permuted = sum4 / totalPairs;
1687
+ if (isExtreme(permuted, statistic, config.alternative)) extreme++;
1688
+ }
1689
+ return {
1690
+ statistic,
1691
+ pValue: (extreme + 1) / (config.signFlipResamples + 1),
1692
+ alternative: config.alternative,
1693
+ method: "monte-carlo",
1694
+ assignments: config.signFlipResamples,
1695
+ nClusters: clusters.length,
1696
+ nNonZeroClusters: nonZero.length,
1697
+ seed: signFlipSeed
1698
+ };
1699
+ }
1700
+ function isExtreme(candidate, observed, alternative) {
1701
+ const tolerance = Number.EPSILON * Math.max(1, Math.abs(observed)) * 16;
1702
+ if (alternative === "greater") return candidate >= observed - tolerance;
1703
+ if (alternative === "less") return candidate <= observed + tolerance;
1704
+ return Math.abs(candidate) >= Math.abs(observed) - tolerance;
1705
+ }
1706
+ function mean(values) {
1707
+ return values.reduce((sum4, value) => sum4 + value, 0) / values.length;
1708
+ }
1709
+
1303
1710
  // src/convergence.ts
1304
1711
  var ConvergenceTracker = class {
1305
1712
  criteria;
@@ -2501,155 +2908,6 @@ function liveProofToReleaseTrace(config, trajectory, durationMs) {
2501
2908
  };
2502
2909
  }
2503
2910
 
2504
- // src/paired-arms.ts
2505
- function pairArms(rows, opts) {
2506
- const { baselineArm, treatmentArm } = opts;
2507
- if (baselineArm === treatmentArm) {
2508
- throw new ValidationError(
2509
- `pairArms: baselineArm and treatmentArm are both '${baselineArm}' \u2014 an arm cannot be compared to itself`
2510
- );
2511
- }
2512
- const byArm = /* @__PURE__ */ new Map();
2513
- const armsSeen = /* @__PURE__ */ new Set();
2514
- for (const row of rows) {
2515
- armsSeen.add(row.arm);
2516
- if (row.arm !== baselineArm && row.arm !== treatmentArm) continue;
2517
- const byKey = byArm.get(row.arm) ?? /* @__PURE__ */ new Map();
2518
- const group = byKey.get(row.pairKey) ?? [];
2519
- group.push(row);
2520
- byKey.set(row.pairKey, group);
2521
- byArm.set(row.arm, byKey);
2522
- }
2523
- for (const arm of [baselineArm, treatmentArm]) {
2524
- if (!byArm.has(arm)) {
2525
- const seen = [...armsSeen].sort().join(", ") || "<none>";
2526
- throw new ValidationError(`pairArms: no rows for arm '${arm}' (arms present: ${seen})`);
2527
- }
2528
- }
2529
- const baselineByKey = byArm.get(baselineArm);
2530
- const treatmentByKey = byArm.get(treatmentArm);
2531
- const allKeys = [.../* @__PURE__ */ new Set([...baselineByKey.keys(), ...treatmentByKey.keys()])].sort();
2532
- const pairs = [];
2533
- const unpairedBaseline = [];
2534
- const unpairedTreatment = [];
2535
- for (const pairKey2 of allKeys) {
2536
- const b = baselineByKey.get(pairKey2) ?? [];
2537
- const t = treatmentByKey.get(pairKey2) ?? [];
2538
- if (b.length <= 1 && t.length <= 1) {
2539
- if (b.length === 1 && t.length === 1) {
2540
- pairs.push({ pairKey: pairKey2, repIndex: 0, baseline: b[0], treatment: t[0] });
2541
- } else {
2542
- unpairedBaseline.push(...b);
2543
- unpairedTreatment.push(...t);
2544
- }
2545
- continue;
2546
- }
2547
- const bByRep = indexByRepKey(b, pairKey2, baselineArm);
2548
- const tByRep = indexByRepKey(t, pairKey2, treatmentArm);
2549
- const repKeys = [.../* @__PURE__ */ new Set([...bByRep.keys(), ...tByRep.keys()])].sort();
2550
- let repIndex = 0;
2551
- for (const repKey of repKeys) {
2552
- const baseline = bByRep.get(repKey);
2553
- const treatment = tByRep.get(repKey);
2554
- if (baseline !== void 0 && treatment !== void 0) {
2555
- pairs.push({ pairKey: pairKey2, repIndex: repIndex++, baseline, treatment });
2556
- } else if (baseline !== void 0) {
2557
- unpairedBaseline.push(baseline);
2558
- } else if (treatment !== void 0) {
2559
- unpairedTreatment.push(treatment);
2560
- }
2561
- }
2562
- }
2563
- return { pairs, unpairedBaseline, unpairedTreatment };
2564
- }
2565
- function indexByRepKey(group, pairKey2, arm) {
2566
- const byRep = /* @__PURE__ */ new Map();
2567
- for (const row of group) {
2568
- if (row.repKey === void 0) {
2569
- throw new ValidationError(
2570
- `pairArms: pairKey '${pairKey2}' has multiple reps in an arm, but a row in arm '${arm}' is missing repKey \u2014 multi-rep items require an explicit repKey on every row so reps pair by identity (pairing reps by outcome or by index would bias the paired statistics)`
2571
- );
2572
- }
2573
- if (byRep.has(row.repKey)) {
2574
- throw new ValidationError(
2575
- `pairArms: duplicate repKey '${row.repKey}' for pairKey '${pairKey2}' in arm '${arm}' \u2014 (pairKey, repKey) must uniquely identify a rep within an arm`
2576
- );
2577
- }
2578
- byRep.set(row.repKey, row);
2579
- }
2580
- return byRep;
2581
- }
2582
- function comparePairedArms(rows, opts) {
2583
- const { pairs, unpairedBaseline, unpairedTreatment } = pairArms(rows, opts);
2584
- let correctness = null;
2585
- const baselinePass = [];
2586
- const treatmentPass = [];
2587
- for (const pair of pairs) {
2588
- if (pair.baseline.pass === void 0 || pair.treatment.pass === void 0) continue;
2589
- baselinePass.push(pair.baseline.pass ? 1 : 0);
2590
- treatmentPass.push(pair.treatment.pass ? 1 : 0);
2591
- }
2592
- if (baselinePass.length > 0) {
2593
- const mc = mcnemar(baselinePass, treatmentPass);
2594
- correctness = {
2595
- b10: mc.b,
2596
- b01: mc.c,
2597
- mcnemar: mc,
2598
- riskDifference: pairedRiskDifference(baselinePass, treatmentPass)
2599
- };
2600
- }
2601
- const metricNames = opts.metricNames ?? [
2602
- ...new Set(
2603
- pairs.flatMap((p) => [
2604
- ...Object.keys(p.baseline.metrics ?? {}),
2605
- ...Object.keys(p.treatment.metrics ?? {})
2606
- ])
2607
- )
2608
- ].sort();
2609
- const metricDeltas = metricNames.map((name) => {
2610
- const before = [];
2611
- const after = [];
2612
- let nMissing = 0;
2613
- for (const pair of pairs) {
2614
- const b = metricValue(pair.baseline, name);
2615
- const t = metricValue(pair.treatment, name);
2616
- if (b === void 0 || t === void 0) {
2617
- nMissing++;
2618
- continue;
2619
- }
2620
- before.push(b);
2621
- after.push(t);
2622
- }
2623
- const bootstrapCi2 = before.length === 0 ? null : pairedBootstrap(before, after, opts.bootstrap);
2624
- return {
2625
- name,
2626
- n: before.length,
2627
- nMissing,
2628
- medianDelta: bootstrapCi2 === null ? Number.NaN : bootstrapCi2.median,
2629
- meanDelta: bootstrapCi2 === null ? Number.NaN : bootstrapCi2.mean,
2630
- bootstrapCi: bootstrapCi2,
2631
- wilcoxon: before.length === 0 ? null : wilcoxonSignedRank(before, after)
2632
- };
2633
- });
2634
- return {
2635
- nPairs: pairs.length,
2636
- nUnpairedBaseline: unpairedBaseline.length,
2637
- nUnpairedTreatment: unpairedTreatment.length,
2638
- correctness,
2639
- metricDeltas
2640
- };
2641
- }
2642
- function metricValue(row, name) {
2643
- const v = row.metrics?.[name];
2644
- if (v === void 0) return void 0;
2645
- if (!Number.isFinite(v)) {
2646
- throw new ValidationError(
2647
- `comparePairedArms: non-finite value for metric '${name}' on pairKey '${row.pairKey}' (arm '${row.arm}'): ${v}`
2648
- );
2649
- }
2650
- return v;
2651
- }
2652
-
2653
2911
  // src/pr-review-benchmark.ts
2654
2912
  var DEFAULT_PR_REVIEW_SCORE_WEIGHTS = {
2655
2913
  recall: 4,
@@ -2714,12 +2972,12 @@ function summarizePrReviewBenchmark(scores2) {
2714
2972
  source,
2715
2973
  caseCount: sourceScores.length,
2716
2974
  commentCount: sum(sourceScores.map((score) => score.commentCount)),
2717
- aggregateMean: mean(sourceScores.map((score) => score.aggregate)),
2718
- recallMean: mean(sourceScores.map((score) => score.recall)),
2719
- precisionMean: mean(sourceScores.map((score) => score.precision)),
2720
- actionabilityMean: mean(sourceScores.map((score) => score.actionability)),
2721
- severityCalibrationMean: mean(sourceScores.map((score) => score.severityCalibration)),
2722
- lowNoiseMean: mean(sourceScores.map((score) => score.lowNoise))
2975
+ aggregateMean: mean2(sourceScores.map((score) => score.aggregate)),
2976
+ recallMean: mean2(sourceScores.map((score) => score.recall)),
2977
+ precisionMean: mean2(sourceScores.map((score) => score.precision)),
2978
+ actionabilityMean: mean2(sourceScores.map((score) => score.actionability)),
2979
+ severityCalibrationMean: mean2(sourceScores.map((score) => score.severityCalibration)),
2980
+ lowNoiseMean: mean2(sourceScores.map((score) => score.lowNoise))
2723
2981
  })).sort((a, b) => b.aggregateMean - a.aggregateMean);
2724
2982
  }
2725
2983
  function aggregatePrReviewScore(dimensions, weights = {}) {
@@ -2815,7 +3073,7 @@ function normalizeTerm(input) {
2815
3073
  function normalizePath(input) {
2816
3074
  return input.replace(/^\.\/+/, "");
2817
3075
  }
2818
- function mean(values) {
3076
+ function mean2(values) {
2819
3077
  return values.length ? sum(values) / values.length : 0;
2820
3078
  }
2821
3079
  function sum(values) {
@@ -3605,10 +3863,10 @@ function summarizeHarnessResults(results) {
3605
3863
  return {
3606
3864
  variant,
3607
3865
  runs,
3608
- aggregateMean: mean2(runs.map((r) => r.aggregate)),
3609
- passRate: mean2(runs.map((r) => r.score.success)),
3610
- costUsdMean: mean2(runs.map((r) => r.score.costUsd)),
3611
- wallSecondsMean: mean2(runs.map((r) => r.score.wallSeconds)),
3866
+ aggregateMean: mean3(runs.map((r) => r.aggregate)),
3867
+ passRate: mean3(runs.map((r) => r.score.success)),
3868
+ costUsdMean: mean3(runs.map((r) => r.score.costUsd)),
3869
+ wallSecondsMean: mean3(runs.map((r) => r.score.wallSeconds)),
3612
3870
  scoreMean: meanRunScore(runs.map((r) => r.score))
3613
3871
  };
3614
3872
  }).sort((a, b) => b.aggregateMean - a.aggregateMean);
@@ -3645,22 +3903,22 @@ async function mapLimit(items, limit, fn) {
3645
3903
  );
3646
3904
  return results;
3647
3905
  }
3648
- function mean2(values) {
3906
+ function mean3(values) {
3649
3907
  return values.length ? values.reduce((sum4, value) => sum4 + value, 0) / values.length : 0;
3650
3908
  }
3651
3909
  function meanRunScore(scores2) {
3652
3910
  return {
3653
- success: mean2(scores2.map((s) => s.success)),
3654
- goalProgress: mean2(scores2.map((s) => s.goalProgress)),
3655
- repoGroundedness: mean2(scores2.map((s) => s.repoGroundedness)),
3656
- driftPenalty: mean2(scores2.map((s) => s.driftPenalty)),
3657
- toolUseQuality: mean2(scores2.map((s) => s.toolUseQuality)),
3658
- patchQuality: mean2(scores2.map((s) => s.patchQuality)),
3659
- testReality: mean2(scores2.map((s) => s.testReality)),
3660
- finalGate: mean2(scores2.map((s) => s.finalGate)),
3661
- reviewerBlockers: mean2(scores2.map((s) => s.reviewerBlockers)),
3662
- costUsd: mean2(scores2.map((s) => s.costUsd)),
3663
- wallSeconds: mean2(scores2.map((s) => s.wallSeconds)),
3911
+ success: mean3(scores2.map((s) => s.success)),
3912
+ goalProgress: mean3(scores2.map((s) => s.goalProgress)),
3913
+ repoGroundedness: mean3(scores2.map((s) => s.repoGroundedness)),
3914
+ driftPenalty: mean3(scores2.map((s) => s.driftPenalty)),
3915
+ toolUseQuality: mean3(scores2.map((s) => s.toolUseQuality)),
3916
+ patchQuality: mean3(scores2.map((s) => s.patchQuality)),
3917
+ testReality: mean3(scores2.map((s) => s.testReality)),
3918
+ finalGate: mean3(scores2.map((s) => s.finalGate)),
3919
+ reviewerBlockers: mean3(scores2.map((s) => s.reviewerBlockers)),
3920
+ costUsd: mean3(scores2.map((s) => s.costUsd)),
3921
+ wallSeconds: mean3(scores2.map((s) => s.wallSeconds)),
3664
3922
  notes: scores2.flatMap((s) => s.notes ?? [])
3665
3923
  };
3666
3924
  }
@@ -4865,9 +5123,9 @@ function median(sorted) {
4865
5123
  const mid = Math.floor(n / 2);
4866
5124
  return n % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
4867
5125
  }
4868
- function stddev(values, mean6) {
5126
+ function stddev(values, mean7) {
4869
5127
  if (values.length < 2) return 0;
4870
- const variance = values.reduce((acc, v) => acc + (v - mean6) ** 2, 0) / values.length;
5128
+ const variance = values.reduce((acc, v) => acc + (v - mean7) ** 2, 0) / values.length;
4871
5129
  return Math.sqrt(variance);
4872
5130
  }
4873
5131
  function computeExperimentStats(reps, thresholds) {
@@ -4893,15 +5151,15 @@ function computeExperimentStats(reps, thresholds) {
4893
5151
  return r.score;
4894
5152
  });
4895
5153
  const sorted = [...scores2].sort((a, b) => a - b);
4896
- const mean6 = scores2.reduce((s, v) => s + v, 0) / n;
4897
- const sd = stddev(scores2, mean6);
5154
+ const mean7 = scores2.reduce((s, v) => s + v, 0) / n;
5155
+ const sd = stddev(scores2, mean7);
4898
5156
  const spread = iqr(scores2);
4899
5157
  const rated = reps.filter((r) => typeof r.passed === "boolean");
4900
5158
  const passRate = rated.length === 0 ? null : rated.filter((r) => r.passed).length / rated.length;
4901
5159
  const stable = spread < t.iqrUnstableAbove && sd < t.stddevUnstableAbove;
4902
5160
  return {
4903
5161
  median: median(sorted),
4904
- mean: mean6,
5162
+ mean: mean7,
4905
5163
  min: sorted[0],
4906
5164
  max: sorted[n - 1],
4907
5165
  iqr: spread,
@@ -5072,7 +5330,7 @@ var ExperimentTracker = class {
5072
5330
  };
5073
5331
 
5074
5332
  // src/leaderboard.ts
5075
- function mean3(xs) {
5333
+ function mean4(xs) {
5076
5334
  return xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : null;
5077
5335
  }
5078
5336
  function leaderboard(records, opts) {
@@ -5099,10 +5357,10 @@ function leaderboard(records, opts) {
5099
5357
  n: rs.length,
5100
5358
  passRate: ci.estimate,
5101
5359
  passRateCi95: [ci.lower, ci.upper],
5102
- meanCostUsd: mean3(rs.map((r) => r.costUsd)),
5103
- meanTokensIn: mean3(rs.map((r) => r.tokenUsage.input)),
5104
- meanTokensOut: mean3(rs.map((r) => r.tokenUsage.output)),
5105
- meanWallMs: mean3(rs.map((r) => r.wallMs))
5360
+ meanCostUsd: mean4(rs.map((r) => r.costUsd)),
5361
+ meanTokensIn: mean4(rs.map((r) => r.tokenUsage.input)),
5362
+ meanTokensOut: mean4(rs.map((r) => r.tokenUsage.output)),
5363
+ meanWallMs: mean4(rs.map((r) => r.wallMs))
5106
5364
  };
5107
5365
  });
5108
5366
  rows.sort(
@@ -6659,12 +6917,12 @@ async function paraphraseRobustness(prompt, mutators, scoreFn, options = {}) {
6659
6917
  variantScores.push({ mutator: id, score, mutated });
6660
6918
  all.push(score);
6661
6919
  }
6662
- const mean6 = all.reduce((a, b) => a + b, 0) / all.length;
6663
- const variance = all.reduce((a, v) => a + (v - mean6) ** 2, 0) / all.length;
6920
+ const mean7 = all.reduce((a, b) => a + b, 0) / all.length;
6921
+ const variance = all.reduce((a, v) => a + (v - mean7) ** 2, 0) / all.length;
6664
6922
  const stdDev = Math.sqrt(variance);
6665
- const ref = Math.abs(mean6) > 1e-9 ? Math.abs(mean6) : 1;
6923
+ const ref = Math.abs(mean7) > 1e-9 ? Math.abs(mean7) : 1;
6666
6924
  const robustness = Math.max(0, 1 - stdDev / ref);
6667
- return { originalScore, variantScores, meanScore: mean6, stdDev, robustness };
6925
+ return { originalScore, variantScores, meanScore: mean7, stdDev, robustness };
6668
6926
  }
6669
6927
  var lowercaseMutator = (p) => p.toLowerCase();
6670
6928
  var sentenceReorderMutator = (p, seed) => {
@@ -6730,8 +6988,8 @@ async function paraphraseRobustnessScenarios(args) {
6730
6988
  });
6731
6989
  scores2.push(out.score);
6732
6990
  }
6733
- const mean6 = scores2.reduce((a, b) => a + b, 0) / scores2.length;
6734
- deltas[m.name] = mean6 - originalScore;
6991
+ const mean7 = scores2.reduce((a, b) => a + b, 0) / scores2.length;
6992
+ deltas[m.name] = mean7 - originalScore;
6735
6993
  paraphrasedAll.push(...scores2);
6736
6994
  }
6737
6995
  const paraphrasedMean = paraphrasedAll.length === 0 ? originalScore : paraphrasedAll.reduce((a, b) => a + b, 0) / paraphrasedAll.length;
@@ -7149,8 +7407,8 @@ async function proposeSynthesisTargets(dataset, traceStore, options = {}) {
7149
7407
  const sRuns = runs.filter((r) => r.scenarioId === s.id);
7150
7408
  const scores2 = sRuns.map((r) => r.outcome?.score).filter((x) => typeof x === "number");
7151
7409
  if (scores2.length < 3) continue;
7152
- const mean6 = scores2.reduce((a, b) => a + b, 0) / scores2.length;
7153
- const variance = scores2.reduce((a, b) => a + (b - mean6) ** 2, 0) / scores2.length;
7410
+ const mean7 = scores2.reduce((a, b) => a + b, 0) / scores2.length;
7411
+ const variance = scores2.reduce((a, b) => a + (b - mean7) ** 2, 0) / scores2.length;
7154
7412
  if (variance > varianceThreshold) {
7155
7413
  targets.push({
7156
7414
  reason: "high-variance",
@@ -8666,7 +8924,7 @@ function decideReferenceReplayPromotion(baseline, candidate, policy = {}) {
8666
8924
  regressions
8667
8925
  };
8668
8926
  }
8669
- const requiredMeanDelta = mean4(compared.map((item) => item.f1Delta));
8927
+ const requiredMeanDelta = mean5(compared.map((item) => item.f1Delta));
8670
8928
  if (requiredMeanDelta < minF1Delta) {
8671
8929
  return {
8672
8930
  promote: false,
@@ -8902,7 +9160,7 @@ function clamp013(value) {
8902
9160
  function sum2(values) {
8903
9161
  return values.reduce((acc, value) => acc + value, 0);
8904
9162
  }
8905
- function mean4(values) {
9163
+ function mean5(values) {
8906
9164
  return values.length ? sum2(values) / values.length : 0;
8907
9165
  }
8908
9166
  function formatPct(value) {
@@ -9356,10 +9614,10 @@ var HeldOutGate = class {
9356
9614
  afterHoldout.push(run.outcome.holdoutScore);
9357
9615
  }
9358
9616
  const productiveRuns = beforeHoldout.length;
9359
- const candidateSearchMean = mean5(scores(candidate, "searchScore", "search"));
9360
- const candidateHoldoutMean = mean5(scores(candidate, "holdoutScore", "holdout"));
9361
- const baselineSearchMean = mean5(scores(baseline, "searchScore", "search"));
9362
- const baselineHoldoutMean = mean5(scores(baseline, "holdoutScore", "holdout"));
9617
+ const candidateSearchMean = mean6(scores(candidate, "searchScore", "search"));
9618
+ const candidateHoldoutMean = mean6(scores(candidate, "holdoutScore", "holdout"));
9619
+ const baselineSearchMean = mean6(scores(baseline, "searchScore", "search"));
9620
+ const baselineHoldoutMean = mean6(scores(baseline, "holdoutScore", "holdout"));
9363
9621
  const overfitGap = safeDiff(candidateSearchMean, candidateHoldoutMean);
9364
9622
  const baselineOverfitGap = safeDiff(baselineSearchMean, baselineHoldoutMean);
9365
9623
  const medianCandidateCost = medianFinite(candidate.map((r) => r.costUsd));
@@ -9471,7 +9729,7 @@ function scores(runs, field, splitFilter) {
9471
9729
  }
9472
9730
  return out;
9473
9731
  }
9474
- function mean5(xs) {
9732
+ function mean6(xs) {
9475
9733
  if (xs.length === 0) return Number.NaN;
9476
9734
  return xs.reduce((s, x) => s + x, 0) / xs.length;
9477
9735
  }
@@ -9511,9 +9769,9 @@ function passOrthogonality(input) {
9511
9769
  sims.push(cosineSimilarity(vectors[i], vectors[j]));
9512
9770
  }
9513
9771
  }
9514
- const mean6 = sims.length === 0 ? 0 : sims.reduce((a, b) => a + b, 0) / sims.length;
9772
+ const mean7 = sims.length === 0 ? 0 : sims.reduce((a, b) => a + b, 0) / sims.length;
9515
9773
  return {
9516
- orthogonality: Math.max(0, Math.min(1, 1 - mean6)),
9774
+ orthogonality: Math.max(0, Math.min(1, 1 - mean7)),
9517
9775
  passCount: passes.length,
9518
9776
  similarities: sims
9519
9777
  };
@@ -11530,6 +11788,7 @@ export {
11530
11788
  classifyFailure,
11531
11789
  classifyTreatment,
11532
11790
  cliffsDelta,
11791
+ clusteredPairedBinary,
11533
11792
  codeExecutionJudge,
11534
11793
  cohensD,
11535
11794
  coherenceJudge,
@@ -11668,6 +11927,7 @@ export {
11668
11927
  hashScenarios,
11669
11928
  hashToUnit,
11670
11929
  hiddenGrade,
11930
+ holm,
11671
11931
  htmlContainsElement,
11672
11932
  httpGithubClient,
11673
11933
  improvementVerdict,