@tangle-network/agent-eval 0.95.1 → 0.96.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.
Files changed (65) hide show
  1. package/dist/adapters/http.d.ts +1 -1
  2. package/dist/adapters/langchain.d.ts +1 -1
  3. package/dist/adapters/otel.d.ts +1 -1
  4. package/dist/analyst/index.js +1 -1
  5. package/dist/belief-state/index.js +1 -1
  6. package/dist/builder-eval/index.js +4 -29
  7. package/dist/builder-eval/index.js.map +1 -1
  8. package/dist/campaign/index.d.ts +6 -6
  9. package/dist/campaign/index.js +5 -5
  10. package/dist/{chunk-AQ5WQAIV.js → chunk-3NHEO6ZC.js} +2 -2
  11. package/dist/chunk-3NHEO6ZC.js.map +1 -0
  12. package/dist/{chunk-URWVKRCS.js → chunk-6GT4NI4V.js} +2 -2
  13. package/dist/{chunk-5HRORJQY.js → chunk-AIGWQEME.js} +5 -16
  14. package/dist/{chunk-5HRORJQY.js.map → chunk-AIGWQEME.js.map} +1 -1
  15. package/dist/{chunk-2T4EZACH.js → chunk-HRGTA6U5.js} +2 -2
  16. package/dist/{chunk-56GC6VYO.js → chunk-HRGUJTER.js} +669 -665
  17. package/dist/chunk-HRGUJTER.js.map +1 -0
  18. package/dist/{chunk-NACM5RS7.js → chunk-IH7LYRHL.js} +2 -2
  19. package/dist/{chunk-7QTQKIDD.js → chunk-JMIUM2HE.js} +3 -3
  20. package/dist/{chunk-YRZ4M5GS.js → chunk-NF7OZ4J7.js} +7 -29
  21. package/dist/chunk-NF7OZ4J7.js.map +1 -0
  22. package/dist/{chunk-X74V6ESX.js → chunk-OKQ2LAT7.js} +2 -2
  23. package/dist/{chunk-Z6L6YSU6.js → chunk-QZYXA7ZO.js} +11 -45
  24. package/dist/chunk-QZYXA7ZO.js.map +1 -0
  25. package/dist/{chunk-KKWJD5E6.js → chunk-RPZMBW27.js} +5 -5
  26. package/dist/{chunk-QTMYW64F.js → chunk-VDGPPGE3.js} +2 -2
  27. package/dist/contract/index.d.ts +144 -9
  28. package/dist/contract/index.js +152 -8
  29. package/dist/contract/index.js.map +1 -1
  30. package/dist/diagnose.js +1 -1
  31. package/dist/{gepa-C1NCIZ9o.d.ts → gepa-Dprxvz8r.d.ts} +2 -2
  32. package/dist/hosted/index.d.ts +1 -1
  33. package/dist/index.d.ts +3 -3
  34. package/dist/index.js +15 -9
  35. package/dist/index.js.map +1 -1
  36. package/dist/meta-eval/index.d.ts +1 -1
  37. package/dist/meta-eval/index.js +6 -28
  38. package/dist/meta-eval/index.js.map +1 -1
  39. package/dist/multishot/index.d.ts +1 -1
  40. package/dist/openapi.json +1 -1
  41. package/dist/pipelines/index.js +5 -19
  42. package/dist/pipelines/index.js.map +1 -1
  43. package/dist/{provenance-CncDq9qE.d.ts → provenance-DJ--Jcbg.d.ts} +3 -3
  44. package/dist/reporting.d.ts +1 -1
  45. package/dist/reporting.js +4 -4
  46. package/dist/rl.d.ts +1 -1
  47. package/dist/rl.js +5 -5
  48. package/dist/{run-campaign-WXY7KI67.js → run-campaign-OWCFOEQG.js} +3 -3
  49. package/dist/{statistics-CCJpTGOS.d.ts → statistics-xP-cWc5k.d.ts} +17 -1
  50. package/dist/{types-DQRY8ZT-.d.ts → types-BMahhhio.d.ts} +1 -1
  51. package/dist/workflow/index.d.ts +1 -1
  52. package/dist/workflow/index.js +1 -1
  53. package/package.json +1 -1
  54. package/dist/chunk-56GC6VYO.js.map +0 -1
  55. package/dist/chunk-AQ5WQAIV.js.map +0 -1
  56. package/dist/chunk-YRZ4M5GS.js.map +0 -1
  57. package/dist/chunk-Z6L6YSU6.js.map +0 -1
  58. /package/dist/{chunk-URWVKRCS.js.map → chunk-6GT4NI4V.js.map} +0 -0
  59. /package/dist/{chunk-2T4EZACH.js.map → chunk-HRGTA6U5.js.map} +0 -0
  60. /package/dist/{chunk-NACM5RS7.js.map → chunk-IH7LYRHL.js.map} +0 -0
  61. /package/dist/{chunk-7QTQKIDD.js.map → chunk-JMIUM2HE.js.map} +0 -0
  62. /package/dist/{chunk-X74V6ESX.js.map → chunk-OKQ2LAT7.js.map} +0 -0
  63. /package/dist/{chunk-KKWJD5E6.js.map → chunk-RPZMBW27.js.map} +0 -0
  64. /package/dist/{chunk-QTMYW64F.js.map → chunk-VDGPPGE3.js.map} +0 -0
  65. /package/dist/{run-campaign-WXY7KI67.js.map → run-campaign-OWCFOEQG.js.map} +0 -0
@@ -2,435 +2,115 @@ import {
2
2
  ValidationError
3
3
  } from "./chunk-3BFEG2F6.js";
4
4
 
5
- // src/judge-calibration.ts
6
- function calibrateJudge(golden, candidate) {
7
- const map = /* @__PURE__ */ new Map();
8
- for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
9
- for (const c of candidate) {
10
- const entry = map.get(c.itemId);
11
- if (entry) entry.j = c.score;
12
- }
13
- const common = [...map.values()].filter((v) => Number.isFinite(v.j));
14
- const n = common.length;
15
- if (n < 2) {
16
- return { n, pearson: NaN, kappa: NaN, mae: NaN, worstItems: [] };
5
+ // src/statistics.ts
6
+ var normalizeScores = (scores) => scores;
7
+ function weightedMean(scores) {
8
+ if (scores.length === 0) return 0;
9
+ let totalWeight = 0;
10
+ let weightedSum = 0;
11
+ for (const { score, weight } of scores) {
12
+ const w = weight ?? 1;
13
+ weightedSum += score * w;
14
+ totalWeight += w;
17
15
  }
18
- const humans = common.map((c) => c.h);
19
- const judges = common.map((c) => c.j);
20
- const pearson = pearsonR(humans, judges);
21
- const kappa = weightedKappa(humans.map(Math.round), judges.map(Math.round));
22
- const absDiffs = common.map((c) => Math.abs(c.j - c.h));
23
- const mae = absDiffs.reduce((a, b) => a + b, 0) / n;
24
- const worst = [...map.entries()].filter(([, v]) => Number.isFinite(v.j)).map(([itemId, v]) => ({ itemId, judge: v.j, human: v.h, delta: Math.abs(v.j - v.h) })).sort((a, b) => b.delta - a.delta).slice(0, 5);
25
- return { n, pearson, kappa, mae, worstItems: worst };
16
+ return totalWeight > 0 ? weightedSum / totalWeight : 0;
26
17
  }
27
- function positionalBias(scores) {
28
- const pairs = /* @__PURE__ */ new Map();
29
- for (const s of scores) {
30
- const slot = pairs.get(s.itemId) ?? {};
31
- if (s.positionOfAInput === "first") slot.first = s.score;
32
- else if (s.positionOfAInput === "second") slot.second = s.score;
33
- pairs.set(s.itemId, slot);
34
- }
35
- const deltas = [];
36
- for (const { first, second } of pairs.values()) {
37
- if (first !== void 0 && second !== void 0) deltas.push(first - second);
18
+ function confidenceInterval(scores, confidence = 0.95, opts = {}) {
19
+ if (scores.length === 0) return { mean: 0, lower: 0, upper: 0 };
20
+ if (scores.length === 1) return { mean: scores[0], lower: scores[0], upper: scores[0] };
21
+ const n = scores.length;
22
+ const mean = scores.reduce((a, b) => a + b, 0) / n;
23
+ const B = opts.resamples ?? 1e3;
24
+ const rng = makeRng(opts.seed);
25
+ const bootstrapMeans = [];
26
+ for (let i = 0; i < B; i++) {
27
+ let sum = 0;
28
+ for (let j = 0; j < n; j++) {
29
+ sum += scores[Math.floor(rng() * n)];
30
+ }
31
+ bootstrapMeans.push(sum / n);
38
32
  }
39
- if (deltas.length === 0) return { avgDelta: 0, n: 0 };
40
- return { avgDelta: deltas.reduce((a, b) => a + b, 0) / deltas.length, n: deltas.length };
41
- }
42
- function verbosityBias(samples) {
43
- const n = samples.length;
44
- if (n < 3) return { pearson: NaN, n };
45
- return {
46
- pearson: pearsonR(
47
- samples.map((s) => s.outputLen),
48
- samples.map((s) => s.score)
49
- ),
50
- n
51
- };
52
- }
53
- function selfPreference(samples) {
54
- const inF = samples.filter((s) => s.inFamily).map((s) => s.score);
55
- const outF = samples.filter((s) => !s.inFamily).map((s) => s.score);
56
- if (inF.length === 0 || outF.length === 0)
57
- return { inFamilyMean: 0, outOfFamilyMean: 0, deltaMean: 0, n: 0 };
58
- const inMean = inF.reduce((a, b) => a + b, 0) / inF.length;
59
- const outMean = outF.reduce((a, b) => a + b, 0) / outF.length;
33
+ bootstrapMeans.sort((a, b) => a - b);
34
+ const alpha = 1 - confidence;
35
+ const lowerIdx = Math.floor(alpha / 2 * B);
36
+ const upperIdx = Math.floor((1 - alpha / 2) * B) - 1;
60
37
  return {
61
- inFamilyMean: inMean,
62
- outOfFamilyMean: outMean,
63
- deltaMean: inMean - outMean,
64
- n: samples.length
38
+ mean,
39
+ lower: bootstrapMeans[lowerIdx],
40
+ upper: bootstrapMeans[Math.min(upperIdx, B - 1)]
65
41
  };
66
42
  }
67
- function pearsonR(a, b) {
68
- if (a.length !== b.length || a.length < 2) return NaN;
69
- const mA = a.reduce((s, v) => s + v, 0) / a.length;
70
- const mB = b.reduce((s, v) => s + v, 0) / b.length;
71
- let num = 0, dA = 0, dB = 0;
72
- for (let i = 0; i < a.length; i++) {
73
- const da = a[i] - mA;
74
- const db = b[i] - mB;
75
- num += da * db;
76
- dA += da * da;
77
- dB += db * db;
78
- }
79
- if (dA === 0 || dB === 0) return dA === 0 && dB === 0 ? 1 : 0;
80
- return num / Math.sqrt(dA * dB);
81
- }
82
- function weightedKappa(a, b) {
83
- if (a.length !== b.length || a.length === 0) return NaN;
84
- const min = Math.min(...a, ...b);
85
- const max = Math.max(...a, ...b);
86
- const K = max - min + 1;
87
- if (K < 2) return 1;
88
- const observed = Array.from({ length: K }, () => new Array(K).fill(0));
89
- const rowMarg = new Array(K).fill(0);
90
- const colMarg = new Array(K).fill(0);
91
- for (let i = 0; i < a.length; i++) {
92
- const ai = a[i] - min;
93
- const bi = b[i] - min;
94
- const row = observed[ai];
95
- row[bi] = (row[bi] ?? 0) + 1;
96
- rowMarg[ai]++;
97
- colMarg[bi]++;
98
- }
99
- let num = 0;
100
- let den = 0;
101
- for (let i = 0; i < K; i++) {
102
- for (let j = 0; j < K; j++) {
103
- const w = (i - j) ** 2 / (K - 1) ** 2;
104
- const expected = rowMarg[i] * colMarg[j] / a.length;
105
- num += w * observed[i][j];
106
- den += w * expected;
43
+ function interRaterReliability(judgeScores) {
44
+ if (judgeScores.length < 2) return 1;
45
+ const dimensionMap = /* @__PURE__ */ new Map();
46
+ for (const judgeSet of judgeScores) {
47
+ for (const s of judgeSet) {
48
+ if (!dimensionMap.has(s.dimension)) dimensionMap.set(s.dimension, []);
49
+ const arr = dimensionMap.get(s.dimension);
50
+ if (arr.length === 0 || arr[arr.length - 1].length >= judgeScores.length) {
51
+ arr.push([s.score]);
52
+ } else {
53
+ arr[arr.length - 1].push(s.score);
54
+ }
107
55
  }
108
56
  }
109
- if (den === 0) return 1;
110
- return 1 - num / den;
111
- }
112
- function continuousAgreement(scores, opts = {}) {
113
- const bootstrap = opts.bootstrap ?? 1e3;
114
- const weights = opts.weights ?? "quadratic";
115
- const seed = opts.seed ?? 12648430;
116
- const ciLevel = opts.ciLevel ?? 0.95;
117
- const matrix = scores.filter((row) => row.length >= 2 && row.every((v) => Number.isFinite(v)));
118
- const raters = matrix[0]?.length ?? 0;
119
- const clean = matrix.filter((row) => row.length === raters);
120
- const nClean = clean.length;
121
- if (nClean < 2 || raters < 2) {
122
- return {
123
- weightedKappa: NaN,
124
- icc: NaN,
125
- pearson: NaN,
126
- spearman: NaN,
127
- ci: { icc: [NaN, NaN], weightedKappa: [NaN, NaN] },
128
- n: nClean,
129
- raters
130
- };
131
- }
132
- const kappa = continuousWeightedKappa(clean, weights);
133
- const icc = icc21(clean);
134
- const pearson = avgPairwise(clean, pearsonR);
135
- const spearman = avgPairwise(clean, spearmanR);
136
- const ciIcc = [NaN, NaN];
137
- const ciKappa = [NaN, NaN];
138
- if (bootstrap > 0) {
139
- const rng = mulberry32(seed);
140
- const iccs = [];
141
- const kappas = [];
142
- for (let b = 0; b < bootstrap; b++) {
143
- const sample = new Array(nClean);
144
- for (let i = 0; i < nClean; i++) {
145
- sample[i] = clean[Math.floor(rng() * nClean)];
57
+ const allValues = [];
58
+ const pairDiffs = [];
59
+ for (const items of dimensionMap.values()) {
60
+ for (const ratings of items) {
61
+ if (ratings.length < 2) continue;
62
+ for (const v of ratings) allValues.push(v);
63
+ for (let i = 0; i < ratings.length; i++) {
64
+ for (let j = i + 1; j < ratings.length; j++) {
65
+ pairDiffs.push((ratings[i] - ratings[j]) ** 2);
66
+ }
146
67
  }
147
- const iccB = icc21(sample);
148
- const kB = continuousWeightedKappa(sample, weights);
149
- if (Number.isFinite(iccB)) iccs.push(iccB);
150
- if (Number.isFinite(kB)) kappas.push(kB);
151
- }
152
- const [lo, hi] = percentileBounds(ciLevel);
153
- if (iccs.length > 0) {
154
- iccs.sort((a, b) => a - b);
155
- ciIcc[0] = quantile(iccs, lo);
156
- ciIcc[1] = quantile(iccs, hi);
157
68
  }
158
- if (kappas.length > 0) {
159
- kappas.sort((a, b) => a - b);
160
- ciKappa[0] = quantile(kappas, lo);
161
- ciKappa[1] = quantile(kappas, hi);
69
+ }
70
+ if (pairDiffs.length === 0 || allValues.length < 2) return 1;
71
+ const observedDisagreement = pairDiffs.reduce((a, b) => a + b, 0) / pairDiffs.length;
72
+ let expectedDisagreement = 0;
73
+ let expectedCount = 0;
74
+ for (let i = 0; i < allValues.length; i++) {
75
+ for (let j = i + 1; j < allValues.length; j++) {
76
+ expectedDisagreement += (allValues[i] - allValues[j]) ** 2;
77
+ expectedCount++;
162
78
  }
163
79
  }
164
- return {
165
- weightedKappa: kappa,
166
- icc,
167
- pearson,
168
- spearman,
169
- ci: { icc: ciIcc, weightedKappa: ciKappa },
170
- n: nClean,
171
- raters
172
- };
80
+ expectedDisagreement = expectedCount > 0 ? expectedDisagreement / expectedCount : 0;
81
+ if (expectedDisagreement === 0) return 1;
82
+ return 1 - observedDisagreement / expectedDisagreement;
173
83
  }
174
- function calibrateJudgeContinuous(golden, candidate, opts = {}) {
175
- const base = calibrateJudge(golden, candidate);
176
- const map = /* @__PURE__ */ new Map();
177
- for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
178
- for (const c of candidate) {
179
- const entry = map.get(c.itemId);
180
- if (entry) entry.j = c.score;
84
+ function mannWhitneyU(a, b) {
85
+ if (a.length === 0 || b.length === 0) return { u: 0, p: 1 };
86
+ const n1 = a.length;
87
+ const n2 = b.length;
88
+ const combined = [
89
+ ...a.map((v) => ({ v, group: "a" })),
90
+ ...b.map((v) => ({ v, group: "b" }))
91
+ ].sort((x, y) => x.v - y.v);
92
+ const ranks2 = new Array(combined.length);
93
+ let i = 0;
94
+ while (i < combined.length) {
95
+ let j = i;
96
+ while (j < combined.length && combined[j].v === combined[i].v) j++;
97
+ const avgRank = (i + 1 + j) / 2;
98
+ for (let k = i; k < j; k++) ranks2[k] = avgRank;
99
+ i = j;
181
100
  }
182
- const rows = [];
183
- for (const v of map.values()) {
184
- if (Number.isFinite(v.j)) rows.push([v.h, v.j]);
101
+ let r1 = 0;
102
+ for (let k = 0; k < combined.length; k++) {
103
+ if (combined[k].group === "a") r1 += ranks2[k];
185
104
  }
186
- const agreement = continuousAgreement(rows, opts);
187
- return {
188
- ...base,
189
- weightedKappaContinuous: agreement.weightedKappa,
190
- icc: agreement.icc,
191
- spearman: agreement.spearman,
192
- ci: agreement.ci
193
- };
194
- }
195
- function continuousWeightedKappa(rows, scheme) {
196
- if (rows.length === 0) return NaN;
197
- const raters = rows[0].length;
198
- if (raters < 2) return NaN;
199
- const wFn = scheme === "linear" ? (x, y) => Math.abs(x - y) : (x, y) => (x - y) ** 2;
200
- let sum = 0;
201
- let pairs = 0;
202
- for (let r1 = 0; r1 < raters; r1++) {
203
- for (let r2 = r1 + 1; r2 < raters; r2++) {
204
- const a = rows.map((row) => row[r1]);
205
- const b = rows.map((row) => row[r2]);
206
- const n = a.length;
207
- let obs = 0;
208
- for (let i = 0; i < n; i++) obs += wFn(a[i], b[i]);
209
- obs /= n;
210
- let exp = 0;
211
- for (let i = 0; i < n; i++) {
212
- for (let j = 0; j < n; j++) exp += wFn(a[i], b[j]);
213
- }
214
- exp /= n * n;
215
- if (exp === 0) {
216
- sum += obs === 0 ? 1 : 0;
217
- } else {
218
- sum += 1 - obs / exp;
219
- }
220
- pairs++;
221
- }
222
- }
223
- return pairs === 0 ? NaN : sum / pairs;
224
- }
225
- function icc21(rows) {
226
- const n = rows.length;
227
- if (n < 2) return NaN;
228
- const k = rows[0].length;
229
- if (k < 2) return NaN;
230
- const rowMeans = rows.map((row) => row.reduce((s, v) => s + v, 0) / k);
231
- const colMeans = new Array(k).fill(0);
232
- for (let j = 0; j < k; j++) {
233
- let s = 0;
234
- for (let i = 0; i < n; i++) s += rows[i][j];
235
- colMeans[j] = s / n;
236
- }
237
- let grand = 0;
238
- for (let i = 0; i < n; i++) grand += rowMeans[i];
239
- grand /= n;
240
- let ssR = 0;
241
- for (let i = 0; i < n; i++) ssR += (rowMeans[i] - grand) ** 2;
242
- ssR *= k;
243
- let ssC = 0;
244
- for (let j = 0; j < k; j++) ssC += (colMeans[j] - grand) ** 2;
245
- ssC *= n;
246
- let ssT = 0;
247
- for (let i = 0; i < n; i++) {
248
- for (let j = 0; j < k; j++) ssT += (rows[i][j] - grand) ** 2;
249
- }
250
- const ssE = ssT - ssR - ssC;
251
- const dfR = n - 1;
252
- const dfC = k - 1;
253
- const dfE = (n - 1) * (k - 1);
254
- const msR = ssR / dfR;
255
- const msC = ssC / dfC;
256
- const msE = dfE > 0 ? ssE / dfE : 0;
257
- const denom = msR + (k - 1) * msE + k * (msC - msE) / n;
258
- if (denom === 0) {
259
- return msR === 0 && msE === 0 ? 1 : 0;
260
- }
261
- return (msR - msE) / denom;
262
- }
263
- function avgPairwise(rows, fn) {
264
- const k = rows[0]?.length ?? 0;
265
- if (k < 2) return NaN;
266
- let sum = 0;
267
- let pairs = 0;
268
- for (let i = 0; i < k; i++) {
269
- for (let j = i + 1; j < k; j++) {
270
- const a = rows.map((row) => row[i]);
271
- const b = rows.map((row) => row[j]);
272
- const r = fn(a, b);
273
- if (Number.isFinite(r)) {
274
- sum += r;
275
- pairs++;
276
- }
277
- }
278
- }
279
- return pairs === 0 ? NaN : sum / pairs;
280
- }
281
- function spearmanR(a, b) {
282
- if (a.length !== b.length || a.length < 2) return NaN;
283
- return pearsonR(rankWithTies(a), rankWithTies(b));
284
- }
285
- function rankWithTies(xs) {
286
- const n = xs.length;
287
- const indexed = xs.map((v, i2) => ({ v, i: i2 }));
288
- indexed.sort((x, y) => x.v - y.v);
289
- const ranks = new Array(n).fill(0);
290
- let i = 0;
291
- while (i < n) {
292
- let j = i;
293
- while (j + 1 < n && indexed[j + 1].v === indexed[i].v) j++;
294
- const avg = (i + j) / 2 + 1;
295
- for (let k = i; k <= j; k++) ranks[indexed[k].i] = avg;
296
- i = j + 1;
297
- }
298
- return ranks;
299
- }
300
- function mulberry32(seed) {
301
- let a = seed >>> 0;
302
- return () => {
303
- a = a + 1831565813 >>> 0;
304
- let t = a;
305
- t = Math.imul(t ^ t >>> 15, t | 1);
306
- t ^= t + Math.imul(t ^ t >>> 7, t | 61);
307
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
308
- };
309
- }
310
- function percentileBounds(ciLevel) {
311
- const tail = (1 - ciLevel) / 2;
312
- return [tail, 1 - tail];
313
- }
314
- function quantile(sorted, q) {
315
- if (sorted.length === 0) return NaN;
316
- if (sorted.length === 1) return sorted[0];
317
- const pos = q * (sorted.length - 1);
318
- const lo = Math.floor(pos);
319
- const hi = Math.ceil(pos);
320
- if (lo === hi) return sorted[lo];
321
- const frac = pos - lo;
322
- return sorted[lo] * (1 - frac) + sorted[hi] * frac;
323
- }
324
-
325
- // src/statistics.ts
326
- var normalizeScores = (scores) => scores;
327
- function weightedMean(scores) {
328
- if (scores.length === 0) return 0;
329
- let totalWeight = 0;
330
- let weightedSum = 0;
331
- for (const { score, weight } of scores) {
332
- const w = weight ?? 1;
333
- weightedSum += score * w;
334
- totalWeight += w;
335
- }
336
- return totalWeight > 0 ? weightedSum / totalWeight : 0;
337
- }
338
- function confidenceInterval(scores, confidence = 0.95, opts = {}) {
339
- if (scores.length === 0) return { mean: 0, lower: 0, upper: 0 };
340
- if (scores.length === 1) return { mean: scores[0], lower: scores[0], upper: scores[0] };
341
- const n = scores.length;
342
- const mean = scores.reduce((a, b) => a + b, 0) / n;
343
- const B = opts.resamples ?? 1e3;
344
- const rng = makeRng(opts.seed);
345
- const bootstrapMeans = [];
346
- for (let i = 0; i < B; i++) {
347
- let sum = 0;
348
- for (let j = 0; j < n; j++) {
349
- sum += scores[Math.floor(rng() * n)];
350
- }
351
- bootstrapMeans.push(sum / n);
352
- }
353
- bootstrapMeans.sort((a, b) => a - b);
354
- const alpha = 1 - confidence;
355
- const lowerIdx = Math.floor(alpha / 2 * B);
356
- const upperIdx = Math.floor((1 - alpha / 2) * B) - 1;
357
- return {
358
- mean,
359
- lower: bootstrapMeans[lowerIdx],
360
- upper: bootstrapMeans[Math.min(upperIdx, B - 1)]
361
- };
362
- }
363
- function interRaterReliability(judgeScores) {
364
- if (judgeScores.length < 2) return 1;
365
- const dimensionMap = /* @__PURE__ */ new Map();
366
- for (const judgeSet of judgeScores) {
367
- for (const s of judgeSet) {
368
- if (!dimensionMap.has(s.dimension)) dimensionMap.set(s.dimension, []);
369
- const arr = dimensionMap.get(s.dimension);
370
- if (arr.length === 0 || arr[arr.length - 1].length >= judgeScores.length) {
371
- arr.push([s.score]);
372
- } else {
373
- arr[arr.length - 1].push(s.score);
374
- }
375
- }
376
- }
377
- const allValues = [];
378
- const pairDiffs = [];
379
- for (const items of dimensionMap.values()) {
380
- for (const ratings of items) {
381
- if (ratings.length < 2) continue;
382
- for (const v of ratings) allValues.push(v);
383
- for (let i = 0; i < ratings.length; i++) {
384
- for (let j = i + 1; j < ratings.length; j++) {
385
- pairDiffs.push((ratings[i] - ratings[j]) ** 2);
386
- }
387
- }
388
- }
389
- }
390
- if (pairDiffs.length === 0 || allValues.length < 2) return 1;
391
- const observedDisagreement = pairDiffs.reduce((a, b) => a + b, 0) / pairDiffs.length;
392
- let expectedDisagreement = 0;
393
- let expectedCount = 0;
394
- for (let i = 0; i < allValues.length; i++) {
395
- for (let j = i + 1; j < allValues.length; j++) {
396
- expectedDisagreement += (allValues[i] - allValues[j]) ** 2;
397
- expectedCount++;
398
- }
399
- }
400
- expectedDisagreement = expectedCount > 0 ? expectedDisagreement / expectedCount : 0;
401
- if (expectedDisagreement === 0) return 1;
402
- return 1 - observedDisagreement / expectedDisagreement;
403
- }
404
- function mannWhitneyU(a, b) {
405
- if (a.length === 0 || b.length === 0) return { u: 0, p: 1 };
406
- const n1 = a.length;
407
- const n2 = b.length;
408
- const combined = [
409
- ...a.map((v) => ({ v, group: "a" })),
410
- ...b.map((v) => ({ v, group: "b" }))
411
- ].sort((x, y) => x.v - y.v);
412
- const ranks = new Array(combined.length);
413
- let i = 0;
414
- while (i < combined.length) {
415
- let j = i;
416
- while (j < combined.length && combined[j].v === combined[i].v) j++;
417
- const avgRank = (i + 1 + j) / 2;
418
- for (let k = i; k < j; k++) ranks[k] = avgRank;
419
- i = j;
420
- }
421
- let r1 = 0;
422
- for (let k = 0; k < combined.length; k++) {
423
- if (combined[k].group === "a") r1 += ranks[k];
424
- }
425
- const u1 = r1 - n1 * (n1 + 1) / 2;
426
- const u2 = n1 * n2 - u1;
427
- const u = Math.min(u1, u2);
428
- const mu = n1 * n2 / 2;
429
- const sigma = Math.sqrt(n1 * n2 * (n1 + n2 + 1) / 12);
430
- if (sigma === 0) return { u, p: 1 };
431
- const z = Math.abs(u - mu) / sigma;
432
- const p = 2 * (1 - normalCdf(z));
433
- return { u, p };
105
+ const u1 = r1 - n1 * (n1 + 1) / 2;
106
+ const u2 = n1 * n2 - u1;
107
+ const u = Math.min(u1, u2);
108
+ const mu = n1 * n2 / 2;
109
+ const sigma = Math.sqrt(n1 * n2 * (n1 + n2 + 1) / 12);
110
+ if (sigma === 0) return { u, p: 1 };
111
+ const z = Math.abs(u - mu) / sigma;
112
+ const p = 2 * (1 - normalCdf(z));
113
+ return { u, p };
434
114
  }
435
115
  function partialCredit(current, target) {
436
116
  if (target <= 0) return 1;
@@ -464,17 +144,17 @@ function wilcoxonSignedRank(before, after) {
464
144
  const n = diffs.length;
465
145
  if (n < 6) return { w: 0, p: 1 };
466
146
  const absRanks = diffs.map((d, i2) => ({ abs: Math.abs(d), sign: Math.sign(d), i: i2 })).sort((a, b) => a.abs - b.abs);
467
- const ranks = new Array(n);
147
+ const ranks2 = new Array(n);
468
148
  let i = 0;
469
149
  while (i < n) {
470
150
  let j = i;
471
151
  while (j < n && absRanks[j].abs === absRanks[i].abs) j++;
472
152
  const avg = (i + 1 + j) / 2;
473
- for (let k = i; k < j; k++) ranks[absRanks[k].i] = avg;
153
+ for (let k = i; k < j; k++) ranks2[absRanks[k].i] = avg;
474
154
  i = j;
475
155
  }
476
156
  let wPlus = 0;
477
- for (let k = 0; k < n; k++) if (diffs[k] > 0) wPlus += ranks[k];
157
+ for (let k = 0; k < n; k++) if (diffs[k] > 0) wPlus += ranks2[k];
478
158
  const mean = n * (n + 1) / 4;
479
159
  const variance = n * (n + 1) * (2 * n + 1) / 24;
480
160
  const z = (wPlus - mean) / Math.sqrt(variance);
@@ -512,6 +192,41 @@ function interpretCliffs(delta) {
512
192
  if (d < 0.474) return "medium";
513
193
  return "large";
514
194
  }
195
+ function ranks(xs) {
196
+ const indexed = xs.map((v, i2) => ({ v, i: i2 })).sort((a, b) => a.v - b.v);
197
+ const r = new Array(xs.length);
198
+ let i = 0;
199
+ while (i < indexed.length) {
200
+ let j = i;
201
+ while (j + 1 < indexed.length && indexed[j + 1].v === indexed[i].v) j++;
202
+ const avg = (i + j) / 2 + 1;
203
+ for (let k = i; k <= j; k++) r[indexed[k].i] = avg;
204
+ i = j + 1;
205
+ }
206
+ return r;
207
+ }
208
+ function pearsonR(a, b) {
209
+ if (a.length !== b.length || a.length < 2) return Number.NaN;
210
+ const n = a.length;
211
+ const meanA = a.reduce((s, v) => s + v, 0) / n;
212
+ const meanB = b.reduce((s, v) => s + v, 0) / n;
213
+ let num = 0;
214
+ let varA = 0;
215
+ let varB = 0;
216
+ for (let i = 0; i < n; i++) {
217
+ const da = a[i] - meanA;
218
+ const db = b[i] - meanB;
219
+ num += da * db;
220
+ varA += da * da;
221
+ varB += db * db;
222
+ }
223
+ if (varA === 0 || varB === 0) return varA === 0 && varB === 0 ? 1 : 0;
224
+ return num / Math.sqrt(varA * varB);
225
+ }
226
+ function spearmanR(a, b) {
227
+ if (a.length !== b.length || a.length < 2) return Number.NaN;
228
+ return pearsonR(ranks(a), ranks(b));
229
+ }
515
230
  function weightedComposite(input) {
516
231
  const entries = Object.entries(input.weights);
517
232
  if (entries.length === 0) {
@@ -777,292 +492,578 @@ function mcnemarPower(opts) {
777
492
  if (p10 < 0 || p01 < 0 || p10 + p01 > 1) {
778
493
  throw new Error(`mcnemarPower: require p10,p01 \u2265 0 and p10+p01 \u2264 1 (got ${p10}, ${p01})`);
779
494
  }
780
- const alpha = opts.alpha ?? 0.05;
781
- const twoSided = opts.twoSided ?? true;
782
- const delta = p10 - p01;
783
- if (delta === 0 || nPairs <= 0) return alpha;
784
- const pDisc = p10 + p01;
785
- const zAlpha = zQuantile(twoSided ? 1 - alpha / 2 : 1 - alpha);
786
- const denom = Math.sqrt(Math.max(1e-12, pDisc - delta * delta));
787
- const zBeta = (Math.sqrt(nPairs) * Math.abs(delta) - zAlpha * Math.sqrt(pDisc)) / denom;
788
- return Math.min(1, Math.max(0, normalCdf(zBeta)));
495
+ const alpha = opts.alpha ?? 0.05;
496
+ const twoSided = opts.twoSided ?? true;
497
+ const delta = p10 - p01;
498
+ if (delta === 0 || nPairs <= 0) return alpha;
499
+ const pDisc = p10 + p01;
500
+ const zAlpha = zQuantile(twoSided ? 1 - alpha / 2 : 1 - alpha);
501
+ const denom = Math.sqrt(Math.max(1e-12, pDisc - delta * delta));
502
+ const zBeta = (Math.sqrt(nPairs) * Math.abs(delta) - zAlpha * Math.sqrt(pDisc)) / denom;
503
+ return Math.min(1, Math.max(0, normalCdf(zBeta)));
504
+ }
505
+ function bonferroni(pValues, alpha = 0.05) {
506
+ const k = pValues.length;
507
+ const adjusted = pValues.map((p) => Math.min(1, p * k));
508
+ const significant = adjusted.map((p) => p < alpha);
509
+ return { adjusted, significant };
510
+ }
511
+ function benjaminiHochberg(pValues, fdr = 0.05) {
512
+ const n = pValues.length;
513
+ if (n === 0) return { qValues: [], significant: [] };
514
+ const indexed = pValues.map((p, i) => ({ p, i })).sort((a, b) => a.p - b.p);
515
+ const q = new Array(n);
516
+ let minRight = 1;
517
+ for (let k = n - 1; k >= 0; k--) {
518
+ const rank = k + 1;
519
+ const entry = indexed[k];
520
+ const raw = entry.p * n / rank;
521
+ const bounded = Math.min(minRight, raw);
522
+ minRight = bounded;
523
+ q[entry.i] = Math.min(1, bounded);
524
+ }
525
+ const significant = q.map((v) => v < fdr);
526
+ return { qValues: q, significant };
527
+ }
528
+ function pairedBootstrap(before, after, opts = {}) {
529
+ if (before.length !== after.length) {
530
+ throw new Error(`pairedBootstrap: unequal sample sizes (${before.length} vs ${after.length})`);
531
+ }
532
+ const confidence = opts.confidence ?? 0.95;
533
+ const resamples = opts.resamples ?? 2e3;
534
+ const statistic = opts.statistic ?? "median";
535
+ if (confidence <= 0 || confidence >= 1) {
536
+ throw new Error(`pairedBootstrap: confidence must be in (0,1), got ${confidence}`);
537
+ }
538
+ const n = before.length;
539
+ const deltas = before.map((b, i) => after[i] - b);
540
+ if (n === 0) {
541
+ return { n: 0, median: 0, mean: 0, low: 0, high: 0, confidence, resamples };
542
+ }
543
+ if (n === 1) {
544
+ const d = deltas[0];
545
+ return { n: 1, median: d, mean: d, low: d, high: d, confidence, resamples };
546
+ }
547
+ const rng = makeRng(opts.seed);
548
+ const samples = new Array(resamples);
549
+ for (let b = 0; b < resamples; b++) {
550
+ if (statistic === "mean") {
551
+ let sum = 0;
552
+ for (let k = 0; k < n; k++) {
553
+ sum += deltas[Math.floor(rng() * n)];
554
+ }
555
+ samples[b] = sum / n;
556
+ } else {
557
+ const acc = new Array(n);
558
+ for (let k = 0; k < n; k++) {
559
+ acc[k] = deltas[Math.floor(rng() * n)];
560
+ }
561
+ samples[b] = medianInPlace(acc);
562
+ }
563
+ }
564
+ samples.sort((a, b) => a - b);
565
+ const alpha = 1 - confidence;
566
+ const lowIdx = Math.floor(alpha / 2 * resamples);
567
+ const highIdx = Math.min(resamples - 1, Math.ceil((1 - alpha / 2) * resamples) - 1);
568
+ return {
569
+ n,
570
+ median: medianInPlace([...deltas]),
571
+ mean: deltas.reduce((s, x) => s + x, 0) / n,
572
+ low: samples[lowIdx],
573
+ high: samples[Math.max(highIdx, lowIdx)],
574
+ confidence,
575
+ resamples
576
+ };
577
+ }
578
+ function wilson(successes, n, confidence = 0.95) {
579
+ if (n <= 0) return { estimate: 0, lower: 0, upper: 0 };
580
+ if (successes < 0 || successes > n) {
581
+ throw new Error(`wilson: successes (${successes}) must be in [0, ${n}]`);
582
+ }
583
+ const z = zQuantile(1 - (1 - confidence) / 2);
584
+ const p = successes / n;
585
+ const z2 = z * z;
586
+ const denom = 1 + z2 / n;
587
+ const center = (p + z2 / (2 * n)) / denom;
588
+ const half = z * Math.sqrt((p * (1 - p) + z2 / (4 * n)) / n) / denom;
589
+ return {
590
+ estimate: p,
591
+ lower: Math.max(0, center - half),
592
+ upper: Math.min(1, center + half)
593
+ };
594
+ }
595
+ function mcnemar(control, treatment) {
596
+ if (control.length !== treatment.length) {
597
+ throw new Error(`mcnemar: unequal sample sizes (${control.length} vs ${treatment.length})`);
598
+ }
599
+ const n = control.length;
600
+ let b = 0;
601
+ let c = 0;
602
+ for (let i = 0; i < n; i++) {
603
+ const ctrl = control[i] ? 1 : 0;
604
+ const treat = treatment[i] ? 1 : 0;
605
+ if (treat === 1 && ctrl === 0) b++;
606
+ else if (treat === 0 && ctrl === 1) c++;
607
+ }
608
+ const nDiscordant = b + c;
609
+ const statistic = nDiscordant === 0 ? 0 : (Math.abs(b - c) - 1) ** 2 / nDiscordant;
610
+ return { n, nDiscordant, b, c, statistic, pValue: binomialSignTwoSided(b, c) };
611
+ }
612
+ function pairedRiskDifference(control, treatment, confidence = 0.95) {
613
+ if (control.length !== treatment.length) {
614
+ throw new Error(
615
+ `pairedRiskDifference: unequal sample sizes (${control.length} vs ${treatment.length})`
616
+ );
617
+ }
618
+ const n = control.length;
619
+ if (n === 0) return { n: 0, b: 0, c: 0, riskDifference: 0, lower: 0, upper: 0, confidence };
620
+ let b = 0;
621
+ let c = 0;
622
+ for (let i = 0; i < n; i++) {
623
+ const ctrl = control[i] ? 1 : 0;
624
+ const treat = treatment[i] ? 1 : 0;
625
+ if (treat === 1 && ctrl === 0) b++;
626
+ else if (treat === 0 && ctrl === 1) c++;
627
+ }
628
+ const rd = (b - c) / n;
629
+ const variance = (b + c - (b - c) ** 2 / n) / (n * n);
630
+ const z = zQuantile(1 - (1 - confidence) / 2);
631
+ const half = z * Math.sqrt(Math.max(0, variance));
632
+ return {
633
+ n,
634
+ b,
635
+ c,
636
+ riskDifference: rd,
637
+ lower: Math.max(-1, rd - half),
638
+ upper: Math.min(1, rd + half),
639
+ confidence
640
+ };
641
+ }
642
+ function passAtK(n, c, k) {
643
+ if (!Number.isInteger(n) || !Number.isInteger(c) || !Number.isInteger(k)) {
644
+ throw new Error(`passAtK: n, c, k must be integers (got n=${n}, c=${c}, k=${k})`);
645
+ }
646
+ if (k < 1 || k > n || c < 0 || c > n) {
647
+ throw new Error(`passAtK: require 1 \u2264 k \u2264 n and 0 \u2264 c \u2264 n (got n=${n}, c=${c}, k=${k})`);
648
+ }
649
+ if (n - c < k) return 1;
650
+ let prob = 1;
651
+ for (let i = n - c + 1; i <= n; i++) prob *= 1 - k / i;
652
+ return 1 - prob;
653
+ }
654
+ function binomialSignTwoSided(b, c) {
655
+ const nd = b + c;
656
+ if (nd === 0) return 1;
657
+ const k = Math.min(b, c);
658
+ const logHalfN = nd * Math.log(0.5);
659
+ let tail = 0;
660
+ for (let i = 0; i <= k; i++) {
661
+ const logChoose = lnGamma(nd + 1) - lnGamma(i + 1) - lnGamma(nd - i + 1);
662
+ tail += Math.exp(logChoose + logHalfN);
663
+ }
664
+ return Math.min(1, 2 * tail);
665
+ }
666
+ function eProcess(opts = {}) {
667
+ const alpha = opts.alpha ?? 0.05;
668
+ const maxBet = opts.maxBet ?? 0.5;
669
+ const nullMean = opts.nullMean ?? 0.5;
670
+ if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {
671
+ throw new ValidationError(`eProcess: alpha must be in (0,1), got ${alpha}`);
672
+ }
673
+ if (!Number.isFinite(nullMean) || nullMean <= 0 || nullMean >= 1) {
674
+ throw new ValidationError(`eProcess: nullMean must be in (0,1), got ${nullMean}`);
675
+ }
676
+ if (!Number.isFinite(maxBet) || maxBet <= 0 || maxBet >= 1 / nullMean) {
677
+ throw new ValidationError(
678
+ `eProcess: maxBet must be in (0, 1/nullMean=${(1 / nullMean).toFixed(4)}) so wealth factors stay positive, got ${maxBet}`
679
+ );
680
+ }
681
+ const threshold = 1 / alpha;
682
+ let wealth = 1;
683
+ let n = 0;
684
+ let decided = false;
685
+ let decidedAtN;
686
+ let sumX = 0;
687
+ let varSum = 0;
688
+ return {
689
+ update(x) {
690
+ if (typeof x !== "number" || !Number.isFinite(x) || x < 0 || x > 1) {
691
+ throw new ValidationError(
692
+ `eProcess: observation must be a finite number in [0,1], got ${x}`
693
+ );
694
+ }
695
+ const muPrev = (0.5 + sumX) / (n + 1);
696
+ const varPrev = (0.25 + varSum) / (n + 1);
697
+ const edge = muPrev - nullMean;
698
+ const lambda = Math.min(maxBet, Math.max(0, edge / (varPrev + edge * edge)));
699
+ wealth *= 1 + lambda * (x - nullMean);
700
+ n += 1;
701
+ sumX += x;
702
+ const muNow = (0.5 + sumX) / (n + 1);
703
+ varSum += (x - muNow) ** 2;
704
+ if (!decided && wealth >= threshold) {
705
+ decided = true;
706
+ decidedAtN = n;
707
+ }
708
+ return { wealth, n, decided };
709
+ },
710
+ state() {
711
+ return { wealth, n, decided, alpha, maxBet, nullMean, threshold, decidedAtN };
712
+ }
713
+ };
714
+ }
715
+ function zQuantile(p) {
716
+ if (p <= 0 || p >= 1) {
717
+ if (p === 0) return -Infinity;
718
+ if (p === 1) return Infinity;
719
+ return NaN;
720
+ }
721
+ const a = [
722
+ -39.69683028665376,
723
+ 220.9460984245205,
724
+ -275.9285104469687,
725
+ 138.357751867269,
726
+ -30.66479806614716,
727
+ 2.506628277459239
728
+ ];
729
+ const b = [
730
+ -54.47609879822406,
731
+ 161.5858368580409,
732
+ -155.6989798598866,
733
+ 66.80131188771972,
734
+ -13.28068155288572
735
+ ];
736
+ const c = [
737
+ -0.007784894002430293,
738
+ -0.3223964580411365,
739
+ -2.400758277161838,
740
+ -2.549732539343734,
741
+ 4.374664141464968,
742
+ 2.938163982698783
743
+ ];
744
+ const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
745
+ const pLow = 0.02425;
746
+ const pHigh = 1 - pLow;
747
+ let q;
748
+ let r;
749
+ if (p < pLow) {
750
+ q = Math.sqrt(-2 * Math.log(p));
751
+ return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
752
+ }
753
+ if (p <= pHigh) {
754
+ q = p - 0.5;
755
+ r = q * q;
756
+ return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
757
+ }
758
+ q = Math.sqrt(-2 * Math.log(1 - p));
759
+ return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
789
760
  }
790
- function bonferroni(pValues, alpha = 0.05) {
791
- const k = pValues.length;
792
- const adjusted = pValues.map((p) => Math.min(1, p * k));
793
- const significant = adjusted.map((p) => p < alpha);
794
- return { adjusted, significant };
761
+ function medianInPlace(xs) {
762
+ if (xs.length === 0) return 0;
763
+ xs.sort((a, b) => a - b);
764
+ const mid = Math.floor(xs.length / 2);
765
+ return xs.length % 2 === 0 ? (xs[mid - 1] + xs[mid]) / 2 : xs[mid];
795
766
  }
796
- function benjaminiHochberg(pValues, fdr = 0.05) {
797
- const n = pValues.length;
798
- if (n === 0) return { qValues: [], significant: [] };
799
- const indexed = pValues.map((p, i) => ({ p, i })).sort((a, b) => a.p - b.p);
800
- const q = new Array(n);
801
- let minRight = 1;
802
- for (let k = n - 1; k >= 0; k--) {
803
- const rank = k + 1;
804
- const entry = indexed[k];
805
- const raw = entry.p * n / rank;
806
- const bounded = Math.min(minRight, raw);
807
- minRight = bounded;
808
- q[entry.i] = Math.min(1, bounded);
809
- }
810
- const significant = q.map((v) => v < fdr);
811
- return { qValues: q, significant };
767
+ function makeRng(seed) {
768
+ if (seed === void 0) return Math.random;
769
+ return mulberry32(seed);
812
770
  }
813
- function pairedBootstrap(before, after, opts = {}) {
814
- if (before.length !== after.length) {
815
- throw new Error(`pairedBootstrap: unequal sample sizes (${before.length} vs ${after.length})`);
816
- }
817
- const confidence = opts.confidence ?? 0.95;
818
- const resamples = opts.resamples ?? 2e3;
819
- const statistic = opts.statistic ?? "median";
820
- if (confidence <= 0 || confidence >= 1) {
821
- throw new Error(`pairedBootstrap: confidence must be in (0,1), got ${confidence}`);
771
+ function mulberry32(seed) {
772
+ let s = seed | 0 || 2654435769;
773
+ return () => {
774
+ s = s + 1831565813 | 0;
775
+ let t = s;
776
+ t = Math.imul(t ^ t >>> 15, t | 1);
777
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
778
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
779
+ };
780
+ }
781
+
782
+ // src/judge-calibration.ts
783
+ function calibrateJudge(golden, candidate) {
784
+ const map = /* @__PURE__ */ new Map();
785
+ for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
786
+ for (const c of candidate) {
787
+ const entry = map.get(c.itemId);
788
+ if (entry) entry.j = c.score;
822
789
  }
823
- const n = before.length;
824
- const deltas = before.map((b, i) => after[i] - b);
825
- if (n === 0) {
826
- return { n: 0, median: 0, mean: 0, low: 0, high: 0, confidence, resamples };
790
+ const common = [...map.values()].filter((v) => Number.isFinite(v.j));
791
+ const n = common.length;
792
+ if (n < 2) {
793
+ return { n, pearson: NaN, kappa: NaN, mae: NaN, worstItems: [] };
827
794
  }
828
- if (n === 1) {
829
- const d = deltas[0];
830
- return { n: 1, median: d, mean: d, low: d, high: d, confidence, resamples };
795
+ const humans = common.map((c) => c.h);
796
+ const judges = common.map((c) => c.j);
797
+ const pearson = pearsonR(humans, judges);
798
+ const kappa = weightedKappa(humans.map(Math.round), judges.map(Math.round));
799
+ const absDiffs = common.map((c) => Math.abs(c.j - c.h));
800
+ const mae = absDiffs.reduce((a, b) => a + b, 0) / n;
801
+ const worst = [...map.entries()].filter(([, v]) => Number.isFinite(v.j)).map(([itemId, v]) => ({ itemId, judge: v.j, human: v.h, delta: Math.abs(v.j - v.h) })).sort((a, b) => b.delta - a.delta).slice(0, 5);
802
+ return { n, pearson, kappa, mae, worstItems: worst };
803
+ }
804
+ function positionalBias(scores) {
805
+ const pairs = /* @__PURE__ */ new Map();
806
+ for (const s of scores) {
807
+ const slot = pairs.get(s.itemId) ?? {};
808
+ if (s.positionOfAInput === "first") slot.first = s.score;
809
+ else if (s.positionOfAInput === "second") slot.second = s.score;
810
+ pairs.set(s.itemId, slot);
831
811
  }
832
- const rng = makeRng(opts.seed);
833
- const samples = new Array(resamples);
834
- for (let b = 0; b < resamples; b++) {
835
- if (statistic === "mean") {
836
- let sum = 0;
837
- for (let k = 0; k < n; k++) {
838
- sum += deltas[Math.floor(rng() * n)];
839
- }
840
- samples[b] = sum / n;
841
- } else {
842
- const acc = new Array(n);
843
- for (let k = 0; k < n; k++) {
844
- acc[k] = deltas[Math.floor(rng() * n)];
845
- }
846
- samples[b] = medianInPlace(acc);
847
- }
812
+ const deltas = [];
813
+ for (const { first, second } of pairs.values()) {
814
+ if (first !== void 0 && second !== void 0) deltas.push(first - second);
848
815
  }
849
- samples.sort((a, b) => a - b);
850
- const alpha = 1 - confidence;
851
- const lowIdx = Math.floor(alpha / 2 * resamples);
852
- const highIdx = Math.min(resamples - 1, Math.ceil((1 - alpha / 2) * resamples) - 1);
816
+ if (deltas.length === 0) return { avgDelta: 0, n: 0 };
817
+ return { avgDelta: deltas.reduce((a, b) => a + b, 0) / deltas.length, n: deltas.length };
818
+ }
819
+ function verbosityBias(samples) {
820
+ const n = samples.length;
821
+ if (n < 3) return { pearson: NaN, n };
853
822
  return {
854
- n,
855
- median: medianInPlace([...deltas]),
856
- mean: deltas.reduce((s, x) => s + x, 0) / n,
857
- low: samples[lowIdx],
858
- high: samples[Math.max(highIdx, lowIdx)],
859
- confidence,
860
- resamples
823
+ pearson: pearsonR(
824
+ samples.map((s) => s.outputLen),
825
+ samples.map((s) => s.score)
826
+ ),
827
+ n
861
828
  };
862
829
  }
863
- function wilson(successes, n, confidence = 0.95) {
864
- if (n <= 0) return { estimate: 0, lower: 0, upper: 0 };
865
- if (successes < 0 || successes > n) {
866
- throw new Error(`wilson: successes (${successes}) must be in [0, ${n}]`);
867
- }
868
- const z = zQuantile(1 - (1 - confidence) / 2);
869
- const p = successes / n;
870
- const z2 = z * z;
871
- const denom = 1 + z2 / n;
872
- const center = (p + z2 / (2 * n)) / denom;
873
- const half = z * Math.sqrt((p * (1 - p) + z2 / (4 * n)) / n) / denom;
830
+ function selfPreference(samples) {
831
+ const inF = samples.filter((s) => s.inFamily).map((s) => s.score);
832
+ const outF = samples.filter((s) => !s.inFamily).map((s) => s.score);
833
+ if (inF.length === 0 || outF.length === 0)
834
+ return { inFamilyMean: 0, outOfFamilyMean: 0, deltaMean: 0, n: 0 };
835
+ const inMean = inF.reduce((a, b) => a + b, 0) / inF.length;
836
+ const outMean = outF.reduce((a, b) => a + b, 0) / outF.length;
874
837
  return {
875
- estimate: p,
876
- lower: Math.max(0, center - half),
877
- upper: Math.min(1, center + half)
838
+ inFamilyMean: inMean,
839
+ outOfFamilyMean: outMean,
840
+ deltaMean: inMean - outMean,
841
+ n: samples.length
878
842
  };
879
843
  }
880
- function mcnemar(control, treatment) {
881
- if (control.length !== treatment.length) {
882
- throw new Error(`mcnemar: unequal sample sizes (${control.length} vs ${treatment.length})`);
844
+ function weightedKappa(a, b) {
845
+ if (a.length !== b.length || a.length === 0) return NaN;
846
+ const min = Math.min(...a, ...b);
847
+ const max = Math.max(...a, ...b);
848
+ const K = max - min + 1;
849
+ if (K < 2) return 1;
850
+ const observed = Array.from({ length: K }, () => new Array(K).fill(0));
851
+ const rowMarg = new Array(K).fill(0);
852
+ const colMarg = new Array(K).fill(0);
853
+ for (let i = 0; i < a.length; i++) {
854
+ const ai = a[i] - min;
855
+ const bi = b[i] - min;
856
+ const row = observed[ai];
857
+ row[bi] = (row[bi] ?? 0) + 1;
858
+ rowMarg[ai]++;
859
+ colMarg[bi]++;
883
860
  }
884
- const n = control.length;
885
- let b = 0;
886
- let c = 0;
887
- for (let i = 0; i < n; i++) {
888
- const ctrl = control[i] ? 1 : 0;
889
- const treat = treatment[i] ? 1 : 0;
890
- if (treat === 1 && ctrl === 0) b++;
891
- else if (treat === 0 && ctrl === 1) c++;
861
+ let num = 0;
862
+ let den = 0;
863
+ for (let i = 0; i < K; i++) {
864
+ for (let j = 0; j < K; j++) {
865
+ const w = (i - j) ** 2 / (K - 1) ** 2;
866
+ const expected = rowMarg[i] * colMarg[j] / a.length;
867
+ num += w * observed[i][j];
868
+ den += w * expected;
869
+ }
892
870
  }
893
- const nDiscordant = b + c;
894
- const statistic = nDiscordant === 0 ? 0 : (Math.abs(b - c) - 1) ** 2 / nDiscordant;
895
- return { n, nDiscordant, b, c, statistic, pValue: binomialSignTwoSided(b, c) };
871
+ if (den === 0) return 1;
872
+ return 1 - num / den;
896
873
  }
897
- function pairedRiskDifference(control, treatment, confidence = 0.95) {
898
- if (control.length !== treatment.length) {
899
- throw new Error(
900
- `pairedRiskDifference: unequal sample sizes (${control.length} vs ${treatment.length})`
901
- );
874
+ function continuousAgreement(scores, opts = {}) {
875
+ const bootstrap = opts.bootstrap ?? 1e3;
876
+ const weights = opts.weights ?? "quadratic";
877
+ const seed = opts.seed ?? 12648430;
878
+ const ciLevel = opts.ciLevel ?? 0.95;
879
+ const matrix = scores.filter((row) => row.length >= 2 && row.every((v) => Number.isFinite(v)));
880
+ const raters = matrix[0]?.length ?? 0;
881
+ const clean = matrix.filter((row) => row.length === raters);
882
+ const nClean = clean.length;
883
+ if (nClean < 2 || raters < 2) {
884
+ return {
885
+ weightedKappa: NaN,
886
+ icc: NaN,
887
+ pearson: NaN,
888
+ spearman: NaN,
889
+ ci: { icc: [NaN, NaN], weightedKappa: [NaN, NaN] },
890
+ n: nClean,
891
+ raters
892
+ };
902
893
  }
903
- const n = control.length;
904
- if (n === 0) return { n: 0, b: 0, c: 0, riskDifference: 0, lower: 0, upper: 0, confidence };
905
- let b = 0;
906
- let c = 0;
907
- for (let i = 0; i < n; i++) {
908
- const ctrl = control[i] ? 1 : 0;
909
- const treat = treatment[i] ? 1 : 0;
910
- if (treat === 1 && ctrl === 0) b++;
911
- else if (treat === 0 && ctrl === 1) c++;
894
+ const kappa = continuousWeightedKappa(clean, weights);
895
+ const icc = icc21(clean);
896
+ const pearson = avgPairwise(clean, pearsonR);
897
+ const spearman = avgPairwise(clean, spearmanR);
898
+ const ciIcc = [NaN, NaN];
899
+ const ciKappa = [NaN, NaN];
900
+ if (bootstrap > 0) {
901
+ const rng = mulberry322(seed);
902
+ const iccs = [];
903
+ const kappas = [];
904
+ for (let b = 0; b < bootstrap; b++) {
905
+ const sample = new Array(nClean);
906
+ for (let i = 0; i < nClean; i++) {
907
+ sample[i] = clean[Math.floor(rng() * nClean)];
908
+ }
909
+ const iccB = icc21(sample);
910
+ const kB = continuousWeightedKappa(sample, weights);
911
+ if (Number.isFinite(iccB)) iccs.push(iccB);
912
+ if (Number.isFinite(kB)) kappas.push(kB);
913
+ }
914
+ const [lo, hi] = percentileBounds(ciLevel);
915
+ if (iccs.length > 0) {
916
+ iccs.sort((a, b) => a - b);
917
+ ciIcc[0] = quantile(iccs, lo);
918
+ ciIcc[1] = quantile(iccs, hi);
919
+ }
920
+ if (kappas.length > 0) {
921
+ kappas.sort((a, b) => a - b);
922
+ ciKappa[0] = quantile(kappas, lo);
923
+ ciKappa[1] = quantile(kappas, hi);
924
+ }
912
925
  }
913
- const rd = (b - c) / n;
914
- const variance = (b + c - (b - c) ** 2 / n) / (n * n);
915
- const z = zQuantile(1 - (1 - confidence) / 2);
916
- const half = z * Math.sqrt(Math.max(0, variance));
917
926
  return {
918
- n,
919
- b,
920
- c,
921
- riskDifference: rd,
922
- lower: Math.max(-1, rd - half),
923
- upper: Math.min(1, rd + half),
924
- confidence
927
+ weightedKappa: kappa,
928
+ icc,
929
+ pearson,
930
+ spearman,
931
+ ci: { icc: ciIcc, weightedKappa: ciKappa },
932
+ n: nClean,
933
+ raters
925
934
  };
926
935
  }
927
- function passAtK(n, c, k) {
928
- if (!Number.isInteger(n) || !Number.isInteger(c) || !Number.isInteger(k)) {
929
- throw new Error(`passAtK: n, c, k must be integers (got n=${n}, c=${c}, k=${k})`);
930
- }
931
- if (k < 1 || k > n || c < 0 || c > n) {
932
- throw new Error(`passAtK: require 1 \u2264 k \u2264 n and 0 \u2264 c \u2264 n (got n=${n}, c=${c}, k=${k})`);
933
- }
934
- if (n - c < k) return 1;
935
- let prob = 1;
936
- for (let i = n - c + 1; i <= n; i++) prob *= 1 - k / i;
937
- return 1 - prob;
938
- }
939
- function binomialSignTwoSided(b, c) {
940
- const nd = b + c;
941
- if (nd === 0) return 1;
942
- const k = Math.min(b, c);
943
- const logHalfN = nd * Math.log(0.5);
944
- let tail = 0;
945
- for (let i = 0; i <= k; i++) {
946
- const logChoose = lnGamma(nd + 1) - lnGamma(i + 1) - lnGamma(nd - i + 1);
947
- tail += Math.exp(logChoose + logHalfN);
948
- }
949
- return Math.min(1, 2 * tail);
950
- }
951
- function eProcess(opts = {}) {
952
- const alpha = opts.alpha ?? 0.05;
953
- const maxBet = opts.maxBet ?? 0.5;
954
- const nullMean = opts.nullMean ?? 0.5;
955
- if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {
956
- throw new ValidationError(`eProcess: alpha must be in (0,1), got ${alpha}`);
957
- }
958
- if (!Number.isFinite(nullMean) || nullMean <= 0 || nullMean >= 1) {
959
- throw new ValidationError(`eProcess: nullMean must be in (0,1), got ${nullMean}`);
936
+ function calibrateJudgeContinuous(golden, candidate, opts = {}) {
937
+ const base = calibrateJudge(golden, candidate);
938
+ const map = /* @__PURE__ */ new Map();
939
+ for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
940
+ for (const c of candidate) {
941
+ const entry = map.get(c.itemId);
942
+ if (entry) entry.j = c.score;
960
943
  }
961
- if (!Number.isFinite(maxBet) || maxBet <= 0 || maxBet >= 1 / nullMean) {
962
- throw new ValidationError(
963
- `eProcess: maxBet must be in (0, 1/nullMean=${(1 / nullMean).toFixed(4)}) so wealth factors stay positive, got ${maxBet}`
964
- );
944
+ const rows = [];
945
+ for (const v of map.values()) {
946
+ if (Number.isFinite(v.j)) rows.push([v.h, v.j]);
965
947
  }
966
- const threshold = 1 / alpha;
967
- let wealth = 1;
968
- let n = 0;
969
- let decided = false;
970
- let decidedAtN;
971
- let sumX = 0;
972
- let varSum = 0;
948
+ const agreement = continuousAgreement(rows, opts);
973
949
  return {
974
- update(x) {
975
- if (typeof x !== "number" || !Number.isFinite(x) || x < 0 || x > 1) {
976
- throw new ValidationError(
977
- `eProcess: observation must be a finite number in [0,1], got ${x}`
978
- );
950
+ ...base,
951
+ weightedKappaContinuous: agreement.weightedKappa,
952
+ icc: agreement.icc,
953
+ spearman: agreement.spearman,
954
+ ci: agreement.ci
955
+ };
956
+ }
957
+ function continuousWeightedKappa(rows, scheme) {
958
+ if (rows.length === 0) return NaN;
959
+ const raters = rows[0].length;
960
+ if (raters < 2) return NaN;
961
+ const wFn = scheme === "linear" ? (x, y) => Math.abs(x - y) : (x, y) => (x - y) ** 2;
962
+ let sum = 0;
963
+ let pairs = 0;
964
+ for (let r1 = 0; r1 < raters; r1++) {
965
+ for (let r2 = r1 + 1; r2 < raters; r2++) {
966
+ const a = rows.map((row) => row[r1]);
967
+ const b = rows.map((row) => row[r2]);
968
+ const n = a.length;
969
+ let obs = 0;
970
+ for (let i = 0; i < n; i++) obs += wFn(a[i], b[i]);
971
+ obs /= n;
972
+ let exp = 0;
973
+ for (let i = 0; i < n; i++) {
974
+ for (let j = 0; j < n; j++) exp += wFn(a[i], b[j]);
979
975
  }
980
- const muPrev = (0.5 + sumX) / (n + 1);
981
- const varPrev = (0.25 + varSum) / (n + 1);
982
- const edge = muPrev - nullMean;
983
- const lambda = Math.min(maxBet, Math.max(0, edge / (varPrev + edge * edge)));
984
- wealth *= 1 + lambda * (x - nullMean);
985
- n += 1;
986
- sumX += x;
987
- const muNow = (0.5 + sumX) / (n + 1);
988
- varSum += (x - muNow) ** 2;
989
- if (!decided && wealth >= threshold) {
990
- decided = true;
991
- decidedAtN = n;
976
+ exp /= n * n;
977
+ if (exp === 0) {
978
+ sum += obs === 0 ? 1 : 0;
979
+ } else {
980
+ sum += 1 - obs / exp;
992
981
  }
993
- return { wealth, n, decided };
994
- },
995
- state() {
996
- return { wealth, n, decided, alpha, maxBet, nullMean, threshold, decidedAtN };
982
+ pairs++;
997
983
  }
998
- };
984
+ }
985
+ return pairs === 0 ? NaN : sum / pairs;
999
986
  }
1000
- function zQuantile(p) {
1001
- if (p <= 0 || p >= 1) {
1002
- if (p === 0) return -Infinity;
1003
- if (p === 1) return Infinity;
1004
- return NaN;
987
+ function icc21(rows) {
988
+ const n = rows.length;
989
+ if (n < 2) return NaN;
990
+ const k = rows[0].length;
991
+ if (k < 2) return NaN;
992
+ const rowMeans = rows.map((row) => row.reduce((s, v) => s + v, 0) / k);
993
+ const colMeans = new Array(k).fill(0);
994
+ for (let j = 0; j < k; j++) {
995
+ let s = 0;
996
+ for (let i = 0; i < n; i++) s += rows[i][j];
997
+ colMeans[j] = s / n;
1005
998
  }
1006
- const a = [
1007
- -39.69683028665376,
1008
- 220.9460984245205,
1009
- -275.9285104469687,
1010
- 138.357751867269,
1011
- -30.66479806614716,
1012
- 2.506628277459239
1013
- ];
1014
- const b = [
1015
- -54.47609879822406,
1016
- 161.5858368580409,
1017
- -155.6989798598866,
1018
- 66.80131188771972,
1019
- -13.28068155288572
1020
- ];
1021
- const c = [
1022
- -0.007784894002430293,
1023
- -0.3223964580411365,
1024
- -2.400758277161838,
1025
- -2.549732539343734,
1026
- 4.374664141464968,
1027
- 2.938163982698783
1028
- ];
1029
- const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
1030
- const pLow = 0.02425;
1031
- const pHigh = 1 - pLow;
1032
- let q;
1033
- let r;
1034
- if (p < pLow) {
1035
- q = Math.sqrt(-2 * Math.log(p));
1036
- return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
999
+ let grand = 0;
1000
+ for (let i = 0; i < n; i++) grand += rowMeans[i];
1001
+ grand /= n;
1002
+ let ssR = 0;
1003
+ for (let i = 0; i < n; i++) ssR += (rowMeans[i] - grand) ** 2;
1004
+ ssR *= k;
1005
+ let ssC = 0;
1006
+ for (let j = 0; j < k; j++) ssC += (colMeans[j] - grand) ** 2;
1007
+ ssC *= n;
1008
+ let ssT = 0;
1009
+ for (let i = 0; i < n; i++) {
1010
+ for (let j = 0; j < k; j++) ssT += (rows[i][j] - grand) ** 2;
1037
1011
  }
1038
- if (p <= pHigh) {
1039
- q = p - 0.5;
1040
- r = q * q;
1041
- return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
1012
+ const ssE = ssT - ssR - ssC;
1013
+ const dfR = n - 1;
1014
+ const dfC = k - 1;
1015
+ const dfE = (n - 1) * (k - 1);
1016
+ const msR = ssR / dfR;
1017
+ const msC = ssC / dfC;
1018
+ const msE = dfE > 0 ? ssE / dfE : 0;
1019
+ const denom = msR + (k - 1) * msE + k * (msC - msE) / n;
1020
+ if (denom === 0) {
1021
+ return msR === 0 && msE === 0 ? 1 : 0;
1042
1022
  }
1043
- q = Math.sqrt(-2 * Math.log(1 - p));
1044
- return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
1045
- }
1046
- function medianInPlace(xs) {
1047
- if (xs.length === 0) return 0;
1048
- xs.sort((a, b) => a - b);
1049
- const mid = Math.floor(xs.length / 2);
1050
- return xs.length % 2 === 0 ? (xs[mid - 1] + xs[mid]) / 2 : xs[mid];
1023
+ return (msR - msE) / denom;
1051
1024
  }
1052
- function makeRng(seed) {
1053
- if (seed === void 0) return Math.random;
1054
- return mulberry322(seed);
1025
+ function avgPairwise(rows, fn) {
1026
+ const k = rows[0]?.length ?? 0;
1027
+ if (k < 2) return NaN;
1028
+ let sum = 0;
1029
+ let pairs = 0;
1030
+ for (let i = 0; i < k; i++) {
1031
+ for (let j = i + 1; j < k; j++) {
1032
+ const a = rows.map((row) => row[i]);
1033
+ const b = rows.map((row) => row[j]);
1034
+ const r = fn(a, b);
1035
+ if (Number.isFinite(r)) {
1036
+ sum += r;
1037
+ pairs++;
1038
+ }
1039
+ }
1040
+ }
1041
+ return pairs === 0 ? NaN : sum / pairs;
1055
1042
  }
1056
1043
  function mulberry322(seed) {
1057
- let s = seed | 0 || 2654435769;
1044
+ let a = seed >>> 0;
1058
1045
  return () => {
1059
- s = s + 1831565813 | 0;
1060
- let t = s;
1046
+ a = a + 1831565813 >>> 0;
1047
+ let t = a;
1061
1048
  t = Math.imul(t ^ t >>> 15, t | 1);
1062
1049
  t ^= t + Math.imul(t ^ t >>> 7, t | 61);
1063
1050
  return ((t ^ t >>> 14) >>> 0) / 4294967296;
1064
1051
  };
1065
1052
  }
1053
+ function percentileBounds(ciLevel) {
1054
+ const tail = (1 - ciLevel) / 2;
1055
+ return [tail, 1 - tail];
1056
+ }
1057
+ function quantile(sorted, q) {
1058
+ if (sorted.length === 0) return NaN;
1059
+ if (sorted.length === 1) return sorted[0];
1060
+ const pos = q * (sorted.length - 1);
1061
+ const lo = Math.floor(pos);
1062
+ const hi = Math.ceil(pos);
1063
+ if (lo === hi) return sorted[lo];
1064
+ const frac = pos - lo;
1065
+ return sorted[lo] * (1 - frac) + sorted[hi] * frac;
1066
+ }
1066
1067
 
1067
1068
  export {
1068
1069
  calibrateJudge,
@@ -1082,6 +1083,9 @@ export {
1082
1083
  cohensD,
1083
1084
  cliffsDelta,
1084
1085
  interpretCliffs,
1086
+ ranks,
1087
+ pearsonR,
1088
+ spearmanR,
1085
1089
  weightedComposite,
1086
1090
  corpusInterRaterAgreement,
1087
1091
  corpusInterRaterAgreementFromJudgeScores,
@@ -1097,6 +1101,6 @@ export {
1097
1101
  pairedRiskDifference,
1098
1102
  passAtK,
1099
1103
  eProcess,
1100
- mulberry322 as mulberry32
1104
+ mulberry32
1101
1105
  };
1102
- //# sourceMappingURL=chunk-56GC6VYO.js.map
1106
+ //# sourceMappingURL=chunk-HRGUJTER.js.map