Files
waggle-os/benchmarks/harness/scripts/e1-aggregate.ts
Oleg Maslov b20b138fe4 moving
2026-09-02 10:14:22 +02:00

138 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env tsx
/**
* E1 aggregation — Eywa answers @ OUR gpt-5 judge vs Eywa self-judge.
* Reads e1-eywa-ourjudge.jsonl + the original Eywa JSON, emits console + markdown.
*/
import fs from 'node:fs';
const EYWA_JSON =
'D:/Projects/KorroResearch/benchmarks/eywa-artifacts/eywa-beam-sonnet46-answers.json';
const OUT_JSONL =
'D:/Projects/KorroResearch/benchmarks/eywa-artifacts/e1-eywa-ourjudge.jsonl';
interface EywaRecord { id: string; cat: string; eywaNugget: number[]; }
interface OutRecord {
id: string; cat: string; our_raw_score: number;
our_nugget_scores: number[]; eywa_raw: number;
}
const OUR_OWN_HEADLINE = 0.6482; // our own answers @ our gpt-5 judge
function mean(xs: number[]): number { return xs.length ? xs.reduce((s, x) => s + x, 0) / xs.length : 0; }
function pct(x: number): string { return (x * 100).toFixed(2) + '%'; }
const eywaRecords = JSON.parse(fs.readFileSync(EYWA_JSON, 'utf-8')) as EywaRecord[];
const eywaById = new Map(eywaRecords.map(r => [r.id, r]));
const out: OutRecord[] = [];
for (const line of fs.readFileSync(OUT_JSONL, 'utf-8').split('\n')) {
const t = line.trim(); if (!t) continue;
out.push(JSON.parse(t) as OutRecord);
}
// dedup by id (last wins)
const outById = new Map(out.map(r => [r.id, r]));
const rows = [...outById.values()];
console.log(`[agg] scored records: ${rows.length}/700`);
// Overall
const ourOverall = mean(rows.map(r => r.our_raw_score));
const eywaOverall = mean(rows.map(r => r.eywa_raw));
// Per-category
const cats = [...new Set(rows.map(r => r.cat))].sort();
interface CatStat { cat: string; n: number; our: number; eywa: number; delta: number; }
const catStats: CatStat[] = cats.map(cat => {
const rs = rows.filter(r => r.cat === cat);
const our = mean(rs.map(r => r.our_raw_score));
const eywa = mean(rs.map(r => r.eywa_raw));
return { cat, n: rs.length, our, eywa, delta: our - eywa };
});
// Per-nugget agreement (align our_nugget_scores to eywaNugget by index)
let nTotal = 0, nOurLess = 0, nOurMore = 0, nEqual = 0;
let sumOur = 0, sumEywa = 0;
for (const r of rows) {
const e = eywaById.get(r.id);
if (!e) continue;
const our = r.our_nugget_scores;
const eyw = e.eywaNugget;
const k = Math.min(our.length, eyw.length);
for (let i = 0; i < k; i++) {
nTotal++;
sumOur += our[i]; sumEywa += eyw[i];
if (our[i] < eyw[i]) nOurLess++;
else if (our[i] > eyw[i]) nOurMore++;
else nEqual++;
}
}
// ── Console report ──
console.log('\n=== OVERALL ===');
console.log(`Eywa answers @ OUR gpt-5 judge : ${pct(ourOverall)}`);
console.log(`Eywa self-judge (Sonnet 4.6) : ${pct(eywaOverall)} (published headline 81.45%)`);
console.log(`Self-judge inflation delta : ${((eywaOverall - ourOverall) * 100).toFixed(2)} pp`);
console.log(`\nHONEST SAME-JUDGE LEADERBOARD (gpt-5 nugget judge):`);
console.log(` Eywa answers @ gpt-5 judge : ${pct(ourOverall)}`);
console.log(` OUR answers @ gpt-5 judge : ${pct(OUR_OWN_HEADLINE)}`);
console.log(` Eywa - ours = ${((ourOverall - OUR_OWN_HEADLINE) * 100).toFixed(2)} pp`);
console.log('\n=== PER CATEGORY ===');
console.log('cat'.padEnd(28), 'n'.padStart(4), 'ourJ%'.padStart(8), 'eywaSelf%'.padStart(10), 'delta_pp'.padStart(9));
for (const c of catStats.sort((a, b) => a.delta - b.delta)) {
console.log(
c.cat.padEnd(28), String(c.n).padStart(4),
pct(c.our).padStart(8), pct(c.eywa).padStart(10),
((c.delta) * 100).toFixed(2).padStart(9),
);
}
console.log('\n=== PER-NUGGET AGREEMENT ===');
console.log(`total nuggets compared: ${nTotal}`);
console.log(`our < eywa (we stricter): ${nOurLess} (${pct(nOurLess / nTotal)})`);
console.log(`our > eywa (we lenient) : ${nOurMore} (${pct(nOurMore / nTotal)})`);
console.log(`equal : ${nEqual} (${pct(nEqual / nTotal)})`);
console.log(`mean(our) - mean(eywa) per nugget: ${((sumOur - sumEywa) / nTotal).toFixed(4)}`);
// ── Markdown ──
const md: string[] = [];
md.push('# E1 — Eywa BEAM answers re-judged with OUR canonical gpt-5 nugget judge\n');
md.push(`_Judge: gpt-5 (model id \`gpt-5\`), verbatim mem0 graded nugget prompt from \`src/beam-nugget-judge.ts\` — the SAME judge behind our published 0.6482 headline. Per-question score = mean of 0/0.5/1 nugget scores._\n`);
md.push(`_Scored ${rows.length}/700 Eywa Sonnet-4.6 answers over ${nTotal} rubric nuggets._\n`);
md.push('## Headline\n');
md.push('| Metric | Value |');
md.push('|---|---|');
md.push(`| Eywa answers @ **our gpt-5 judge** | **${pct(ourOverall)}** |`);
md.push(`| Eywa self-judge (Sonnet 4.6), our recompute | ${pct(eywaOverall)} |`);
md.push(`| Eywa published headline | 81.45% |`);
md.push(`| **Self-judge inflation** (eywa-self our-judge) | **${((eywaOverall - ourOverall) * 100).toFixed(2)} pp** |`);
md.push('');
md.push('## Honest same-judge leaderboard (both @ gpt-5 nugget judge)\n');
md.push('| System | Answers @ gpt-5 judge |');
md.push('|---|---|');
md.push(`| Eywa (Sonnet 4.6 answers) | **${pct(ourOverall)}** |`);
md.push(`| Ours (published) | ${pct(OUR_OWN_HEADLINE)} |`);
md.push(`| Gap (Eywa ours) | ${((ourOverall - OUR_OWN_HEADLINE) * 100).toFixed(2)} pp |`);
md.push('');
md.push('## Per-category (n=70 each)\n');
md.push('| Category | n | Our gpt-5 judge % | Eywa self-judge % | Delta (pp) |');
md.push('|---|---|---|---|---|');
for (const c of catStats.sort((a, b) => a.delta - b.delta)) {
md.push(`| ${c.cat} | ${c.n} | ${pct(c.our)} | ${pct(c.eywa)} | ${(c.delta * 100).toFixed(2)} |`);
}
md.push('');
md.push('_Delta = our-judge eywa-self-judge. Large negative delta = Eywa self-judge inflated that category. Small delta = self-judge was honest there._\n');
md.push('## Per-nugget judge agreement\n');
md.push(`- Total nuggets compared: ${nTotal}`);
md.push(`- Our score **< **Eywa (we stricter / leniency in their favor): ${nOurLess} (${pct(nOurLess / nTotal)})`);
md.push(`- Our score **>** Eywa (we more lenient): ${nOurMore} (${pct(nOurMore / nTotal)})`);
md.push(`- Equal: ${nEqual} (${pct(nEqual / nTotal)})`);
md.push(`- mean(our) mean(eywa) per nugget: **${((sumOur - sumEywa) / nTotal).toFixed(4)}**`);
md.push('');
fs.writeFileSync(
'D:/Projects/KorroResearch/benchmarks/eywa-artifacts/E1-eywa-answers-ourjudge.md',
md.join('\n'),
);
console.log('\n[agg] wrote E1-eywa-answers-ourjudge.md');