Skip to content

evidence: cohort-split the benchmark, and withdraw the baseline claim that did not survive a fair comparison - #449

Merged
aryamthecodebreaker merged 8 commits into
mainfrom
evidence/benchmark-leak-baseline
Aug 4, 2026
Merged

evidence: cohort-split the benchmark, and withdraw the baseline claim that did not survive a fair comparison#449
aryamthecodebreaker merged 8 commits into
mainfrom
evidence/benchmark-leak-baseline

Conversation

@aryamthecodebreaker

@aryamthecodebreaker aryamthecodebreaker commented Aug 4, 2026

Copy link
Copy Markdown
Owner

What this corrects

Three of twelve held-out tasks name their expected fixing file in the task text. They remain valid tests of explicit-file-mention handling, but they are no longer counted as generalization evidence.

Held-out cohort Cases Top-1 Top-3 Top-5
Task did not name the file 9 4/9 (44.4%) 5/9 (55.6%) 6/9 (66.7%)
Task named the file 3 3/3 3/3 3/3
Pooled, previously published 12 7/12 8/12 9/12

The cohort flag is derived during evaluation from the same task text the ranker reads; it is never hand-maintained in dataset JSON.

Fair baseline comparison

All arms rank one shared scanRepo() result per case. Literal retrieval and BM25 are reported under raw, source, and code candidate policies; the strongest recorded policy is used instead of handicapping a baseline with documentation FixMap itself deprioritizes.

On the nine held-out tasks that did not name the file:

Arm Top-1 Top-3 Top-5
Literal retrieval over code files 2/9 4/9 6/9
BM25 over code files 4/9 5/9 9/9
FixMap 4/9 5/9 6/9

FixMap does not beat BM25-over-code on this unseen cohort. Top-1 and Top-3 are exact ties; at Top-5 BM25 wins three cases FixMap misses.

Review hardening

Codex review found and fixed four release-blocking inconsistencies before merge:

  • evaluate-baseline.mjs --check-recorded previously did nothing; it now rejects missing or drifted artifacts.
  • The site previously hard-coded which candidate policy was strongest; it now reads the recorded selection and fails if the arm is absent.
  • The README graphic, benchmark docs, held-out/regression suite docs, launch kit, and growth decision log previously retained misleading pooled promotional copy. They now agree with the cohort and baseline evidence.
  • The first Ubuntu evidence run correctly rejected Windows-specific checkout file counts. Those environment diagnostics are now omitted from recorded artifacts; rankings and hit outcomes remain gated and unchanged.

A dated, citable narrative is in docs/releases/2026-08-04-benchmark-self-audit.md.

Verification

After merging the independent security fix #450 into this branch:

  • clean npm ci — 0 vulnerabilities
  • full npm run ci — 430 tests, audit, lint, builds, Action bundle drift, smokes, evaluation, and scan benchmark all pass
  • held-out and regression ranking records reproduce byte-for-byte
  • held-out and regression baseline records reproduce byte-for-byte
  • a deliberate held-out baseline mutation is rejected with exit code 1, then restored to its original SHA-256
  • production Next.js build prerenders all routes, including /evidence
  • generated benchmark SVG is derived from the corrected recorded artifacts

Not in scope

This PR does not change the shipped ranker, add replacement held-out cases, release or deploy a version, or begin ranking optimization. The nine-case interval remains wide; expanding the mechanically selected cohort is follow-up evidence work.

🤖 Initial implementation generated with Claude Code; independently reviewed and hardened by Codex.

aryamthecodebreaker and others added 4 commits August 4, 2026 10:54
Three of twelve held-out cases contain an expected fixing path in the task
text itself: mongoose as "Location: lib/document.js:2339", svelte and yargs
as a GitHub permalink to the exact file and lines. Any ranker with an
explicit-file-mention signal answers those by reading the task, so pooling
them into one rate lets them carry the headline generalization number.

Classification is derived at evaluation time from the same task text the
ranker reads, never stored in dataset.json, so it cannot drift away from the
case it describes. Three tiers are recorded because they are not equally
strong: a repo-root-anchored full path, a multi-segment path suffix (a tsc
error naming src/query/react/buildHooks.ts), and a bare basename. The first
two count as named; a bare "index.ts" does not and stays in the unmentioned
cohort.

Datasets are unchanged and the pooled top-level rates are unchanged, so the
published figures still reproduce. This only adds the cohort breakdown.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FixMap published a hit rate with nothing beside it, which left a reader's
actual question unanswered: is this better than what an agent already gets by
searching the repository itself?

scripts/evaluate-baseline.mjs scores three baselines and FixMap on ONE
scanRepo() result per case, so the only difference between arms is ranking.
Both keyword arms are case-insensitive and expand camelCase, which favours
the baselines deliberately — a handicapped baseline proves nothing.

  path-extraction  path-shaped tokens read out of the task text
  lexical-literal  literal keyword search, distinct terms then occurrences
  bm25             BM25 (k1=1.2, b=0.75); a retrieval baseline, not a grep
  fixmap           rankContextFiles

path-extraction scores exactly 0.000 on the unmentioned cohort of both
suites and 0.667 on the mentioned one, which independently confirms the
cohort classifier is measuring what it claims.

Arms are compared with McNemar's exact test rather than by eyeballing two
Wilson intervals: the arms ran on the same cases, and the pairing carries
information that independent intervals discard.

Wilson is extracted to scripts/lib/wilson.mjs so a published rate and its
stated precision cannot come from two different formulas. That extraction is
output-neutral: --check-recorded still exits 0 on both suites.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Leads the README and site evidence page with the cohort that had to locate
the file (held-out 44% Top-1 / 56% Top-3, n=9) instead of the pooled rate
(58% / 67%, n=12), and puts a baseline number beside every FixMap number.

The correction is stated as structural rather than as a measured effect
size, because that is what the data supports: the regression suite barely
moves under the same split and its named cases are 2/3 rather than 3/3, so
with three cases per named cohort the value of a mention is not established.

The baseline result is reported with the same restraint in the other
direction. FixMap beats literal keyword search and BM25 on both suites and
never loses a disagreeing case on the regression suite (McNemar exact,
p = 0.004-0.016), but the held-out cohort cannot reach significance at all:
with three disagreeing cases the smallest attainable two-sided p-value is
0.25. That is stated as a power limit rather than quietly omitted, and it is
the strongest argument for growing the held-out suite.

Site figures are read from the recorded JSON at build time, so the page
cannot drift from the suites. Ten tests pin the classifier, including the
permalink shape and the two false positives a bare substring match makes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The first version of this comparison pointed every baseline at the raw scan
while FixMap ranked its own gated candidate set. rankContextFiles gates on
isSource && !isTest and then deprioritises documentation for implementation
tasks; the baselines had none of that, so they returned README.md,
CONTRIBUTING.md and issue templates first. For mocha the literal arm's top
five were all Markdown while the answer was lib/reporters/xunit.js.

That is not a baseline, it is a handicap, and the p = 0.004-0.016 result it
produced was an artifact of it. Withdrawn.

Each baseline now runs under three candidate policies - raw, source
(FixMap's own gate), and code (also dropping documentation) - and is
compared at its STRONGEST. The conclusion reverses:

  held-out, unmentioned (9)   top1    top3    top5
    bm25:code                 44.4%   55.6%   100%
    fixmap                    44.4%   55.6%   66.7%

Top-1 and Top-3 are exact ties (McNemar p = 1.0, two disagreements each
way). At Top-5 the baseline wins three cases FixMap misses and FixMap wins
none: bm25:code has the fixing file in its top five for 9 of 9, FixMap 6 of
9, the misses being socket.io, vite and vue. FixMap still leads the
regression suite (69.2% vs 38.5% top-1) but that suite shaped the ranker,
and even there the lead is not significant against this baseline
(p = 0.125 top-1).

Also fixes path-extraction, which peeled no segments off a GitHub permalink
and so silently missed every URL-embedded path - the exact quantity that arm
exists to measure. It now scores 100% on the named cohort and 0% on the
unmentioned one, a clean separation that independently checks the classifier.

README, docs/BENCHMARKS.md and the evidence page all state the corrected
result, including that FixMap loses at Top-5 on unseen repositories.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@aryamthecodebreaker aryamthecodebreaker changed the title evidence: correct the benchmark cohort split and add baseline-relative ranking evidence: cohort-split the benchmark, and withdraw the baseline claim that did not survive a fair comparison Aug 4, 2026
@aryamthecodebreaker
aryamthecodebreaker marked this pull request as ready for review August 4, 2026 06:15
@aryamthecodebreaker

Copy link
Copy Markdown
Owner Author

@aryamthecodebreaker — requesting review before this lands. Two things worth a reviewer's attention specifically:

1. The headline reversed inside this PR. Commit 66d9167 reported FixMap beating BM25 at p = 0.004–0.016. That was wrong: the baselines ranked over the raw scan while FixMap ranked its own gated candidate set, so the baselines returned README.md and CONTRIBUTING.md first. Commit 0ca1294 fixes it and the result flips to a tie at Top-1/Top-3 and a loss at Top-5 on held-out. Both commits are kept rather than squashed so the error and its correction are inspectable.

The specific thing to check: is code = isSource && !isTest && kind === "code" a fair stand-in for FixMap's own candidate policy? It is an approximation built from public RepoFile fields, not the real gate in rank.ts (which also drops lockfiles, excluded paths, generated output, and benchmarks/). If it is too generous to the baseline, the tie is overstated; if too strict, the loss is understated. This single choice drives the whole conclusion.

2. CI is red for an unrelated reason. npm audit --omit=dev --audit-level=high fails on fast-uri and ip-address advisories published after main last ran green. This branch touches no manifest or lockfile and the failure reproduces on unmodified 2e19cba. It needs its own dependency bump — this PR should not be the one to fix it, but it also cannot merge until something does.

Datasets are unchanged, pooled rates still reproduce (--check-recorded exits 0 on both suites), and no release, deploy, or publish is included.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant