fix(eval): make eval runners self-contained for deterministic headless scoring#72
Merged
Merged
Conversation
…s scoring The runners injected the valid label set as opaque IDs (cat#1..5) but not their definitions. The headless scan is sandboxed to the temp work dir, so the model couldn't read baseline-categories.md to learn what the numbers mean — it thrashed on denied reads (intermittently never emitting the <<<EVAL>>> block, scored as PARTIAL) and guessed categories (cat#2-vs-cat#3 flips on the same fixture). Inject the category legend inline from baseline-categories.md (read-only, no sandbox loosening, no plugin-path discovery), tell the model the definitions are provided so it need not read skill files, steer it to reason directly on the single fixture, and strengthen "always emit the block." Symmetric across claude.sh and codex.sh — divergence between runners is a bug. java/held-out went from 0.33(±0.47)/PARTIAL to 1.00/1.00(±0.00), deterministic. Closes #71 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
evemcgivern
added a commit
that referenced
this pull request
Jun 17, 2026
… (#73) The held-out java fixtures were agent-authored in #15 and never real-model validated; they were ambiguous, so a real model scored the split 0.25/0.25 and tripped the seen-vs-held-out overfit FLAG — a fixture-quality problem, not a profile-overfit one. Rewrite them as unambiguous, realized defects, each with a clean precision twin: - BugPathTraversal: realized Files.readAllBytes(...) of the user-controlled path (was a bare new File(...) constructor a model reasonably won't flag) -> cat#3 - BugSwallowedInterrupt -> BugSwallowedParse: swallowed NumberFormatException to a sentinel, no concurrency flavor, so no cat#2-vs-cat#5 ambiguity -> cat#2 - CleanSafePath: path read behind a strict whitelist (precision twin for cat#3) - CleanReportedParse: parse error propagates, nothing swallowed (twin for cat#2) Recalibrate baseline.held-out.txt to the measured 1.00/1.00 (runs=3, ±0.00, clean_fp_runs=0, gate PASS) now that the runners are deterministic (#71/#72). The seen-vs-held-out gap closes, so the overfit FLAG correctly clears. Closes #68 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Make the eval runners self-contained so headless scoring is deterministic.
The runners injected the valid label set as opaque IDs (
cat#1..5) but not theirdefinitions. The headless scan is sandboxed to the temp work dir, so the model could
not read the skill's
baseline-categories.mdto learn what those numbers mean. It both:<<<EVAL>>>block (PARTIAL), andcat#2-vs-cat#3flips on the same fixture.Fix
cat#N = <definition>legend frombaseline-categories.md(read-only, in thedev repo — no sandbox loosening, no plugin-path discovery) and inject it into the prompt.
it to reason directly on the single fixture (the scope/triage/tool stages are N/A for one
file and only generate denied-read noise).
claude.shandcodex.sh— divergence between runners is a bug.Evidence
java/held-out,--runs 3:mean_precision=0.33(±0.47) recall=0.17+ PARTIALmean_precision=1.00(±0.00) recall=1.00(±0.00)+ gate PASSThe
±0.00is the point — the runner is now deterministic.Scope / safety
time from the dev repo).
bats tests/detect.batsgreen (147/0),sh -nclean.languages' baselines were set with the old flaky runner and may now measure higher — a
re-baseline sweep is noted as follow-up in Eval runners inject opaque category IDs without definitions — nondeterministic headless scoring #71.
Closes #71
🤖 Generated with Claude Code