1
0
Эх сурвалжийг харах

test(agent-eval): report the occupancy metric's own error bar (CG-7)

On a gap that is >=95% one tool result, the measured context delta IS that
result's token count, so the spread between it and the run-level ratio is the
attribution error. Median over such gaps: +/-1-2% on real runs.
Colby McHenry 1 сар өмнө
parent
commit
4d5f8d371a

+ 15 - 1
scripts/agent-eval/parse-run.mjs

@@ -188,6 +188,19 @@ export function parseSession(files) {
   const charsPerToken = sumD > 0 ? sumC / sumD : CHARS_PER_TOKEN_FALLBACK;
   const charsPerToken = sumD > 0 ? sumC / sumD : CHARS_PER_TOKEN_FALLBACK;
   const calibrated = sumD > 0;
   const calibrated = sumD > 0;
 
 
+  // How far a single result's token density strays from the run-level ratio.
+  // On a gap that is almost entirely one tool result, `delta` IS that result's
+  // token count, so |chars/ratio - delta| / delta is the attribution error for
+  // that result. The median over such gaps is the metric's real error bar.
+  const errs = [];
+  for (const g of gaps) {
+    if (g.compacted || g.delta <= 0 || g.chars <= 500) continue;
+    if (g.toolChars / g.chars < 0.95) continue;
+    errs.push(Math.abs(g.toolChars / charsPerToken - g.delta) / g.delta);
+  }
+  errs.sort((a, b) => a - b);
+  const dispersion = errs.length ? errs[(errs.length - 1) >> 1] : null;
+
   // ---- Pass 2: attribute gap tokens, then apply evictions FIFO. ------------
   // ---- Pass 2: attribute gap tokens, then apply evictions FIFO. ------------
   const contributed = Object.fromEntries(FAMILIES.map((f) => [f, 0]));
   const contributed = Object.fromEntries(FAMILIES.map((f) => [f, 0]));
   const resultChars = Object.fromEntries(FAMILIES.map((f) => [f, 0]));
   const resultChars = Object.fromEntries(FAMILIES.map((f) => [f, 0]));
@@ -258,7 +271,7 @@ export function parseSession(files) {
     processed,
     processed,
     occupancy: {
     occupancy: {
       ctxFinal, ctxBase, windowTokens: WINDOW_TOKENS,
       ctxFinal, ctxBase, windowTokens: WINDOW_TOKENS,
-      charsPerToken, calibrated, compactions, evicted: Math.round(evicted),
+      charsPerToken, calibrated, compactions, dispersion, evicted: Math.round(evicted),
       residual: Object.fromEntries(FAMILIES.map((f) => [f, Math.round(residual[f])])),
       residual: Object.fromEntries(FAMILIES.map((f) => [f, Math.round(residual[f])])),
       contributed: Object.fromEntries(FAMILIES.map((f) => [f, Math.round(contributed[f])])),
       contributed: Object.fromEntries(FAMILIES.map((f) => [f, Math.round(contributed[f])])),
       chars: resultChars, results: resultCount,
       chars: resultChars, results: resultCount,
@@ -298,6 +311,7 @@ export function formatOccupancy(s, indent = '  ') {
     - (o.residual.codegraph + o.residualFileAccess + o.residual.other);
     - (o.residual.codegraph + o.residualFileAccess + o.residual.other);
   out.push(
   out.push(
     `${indent}  measure: ${o.charsPerToken.toFixed(2)} chars/tok ${o.calibrated ? 'measured' : '(FALLBACK — no clean gap to calibrate on)'}` +
     `${indent}  measure: ${o.charsPerToken.toFixed(2)} chars/tok ${o.calibrated ? 'measured' : '(FALLBACK — no clean gap to calibrate on)'}` +
+    (o.dispersion !== null ? ` ±${(o.dispersion * 100).toFixed(1)}%` : '') +
     ` · turns ${s.turns} · compactions ${o.compactions}` +
     ` · turns ${s.turns} · compactions ${o.compactions}` +
     (o.evicted > 0 || dropped > 1 ? ` · evicted ${n(o.evicted)} tok` : '')
     (o.evicted > 0 || dropped > 1 ? ` · evicted ${n(o.evicted)} tok` : '')
   );
   );