Repository navigation
MIT-661: eval grader v2, word-start matching, no version-only causes, versioned results - #166
Merged
Merged
Conversation
MIT-661. Cause and symptom words match as whole words; a cause word that is only a version never makes the cause right. Every result records GRADER_VERSION (2); results without it are version 1, and report and compare print each grader version apart. Each proposal keeps its cause and fix, scrubbed and cut like the patch excerpt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qc1CQTb8r67J32HpkhS43y
MIT-661. How proposals are graded, what v2 changed, and how results of different grader versions are compared (never pooled). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qc1CQTb8r67J32HpkhS43y
MIT-661 review. A word must start a word; only a word ending in a digit
must also end one, so stems and plurals ("truncat", "offset") match
again while "utc" in "outcomes" and "9.2" in "9.21" still don't.
trials gives a row per grader version and effects a section per
version, so no good-proposal figure mixes graders.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qc1CQTb8r67J32HpkhS43y
MIT-661 review. "pep 649" and "rfc 3339" are causes, not versions, so is_version_word takes the discovery's library. A grade_proposal test now shows symptom and cause words both match from a word's start, and another pins the skipped words. The ledger table names grader_version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qc1CQTb8r67J32HpkhS43y
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 changed
tools/eval/runner.pymentions). This applies tocause_wordsandsymptom_words, after lowercasing.[a-z0-9_]character may come just before the word. That stops "utc" in "outcomes", "view" in "reviews", "ops" in "drops" and "2.0" in "21002.0".cause_right(is_version_word). A version word is digits and dots with an optional leadingv. It may have one prefix, but only the discovery'slibraryor "python": "9.2", "pytest 9.2" (for pytest), "polars 2" (for polars) and "python 3.14" are version words; "pep 649" and "rfc 3339" are not. That is whyis_version_word(word, library)takes the library. The data keeps these words; the grader skips them forcause_rightonly. Across measured and retired scenarios, the skipped words are exactly 9.2, 2.14, 0.0.45, 0.11, polars 2, 3.14, 3.0, 2.1 and 2.0, the same set as before the prefix rule changed. A test pins that set.GRADER_VERSION = 2is recorded on every per-session JSON (Result.grader_version) and on every ledger line. A result without it is version 1 (agent_eval.grader_version).agent_eval.by_grader).report,compareandeffectsprint a section per version (== <condition>: N sessions, grader vN).comparegives each version its own verdict and notes when a condition holds more than one.trialsgroups by version too, with a new last column,grader.Proposal(cause,fix, defaulting to""). It goes through the patch excerpt's scrubber and cap. I renamedpatch_excerpttoexcerpt, since it now handles any text, and updated both callers. Old JSON files and ledger lines without these fields still load.test_eval_grader.py,test_eval_compare.py,test_eval_arms.py):grade_proposalitself uses whole-word-start matching for both lists: withsymptom_words=("view",)andcause_words=("utc",), a proposal saying "reviews" and "outcomes" getson_topicandcause_rightboth False, and one saying "view" and "UTC" gets both True. With substring matching, this test fails;cause_right=False;grader_version2;docs/eval/baseline-holdoutresults report as grader v1;comparegives each version its own verdict;trialsandeffectssplit by version;docs/eval/README.mdand agrader_versionrow to its ledger field table. The decision record isdocs/decisions/2026-11-08-MIT-661-grader-v2.md, named by date:docs/decisions/README.mdsays records after 0038 never use a sequence number.test_herding_reads_a_lines_excerpt_and_an_older_lines_whole_patch_by_hash(test_eval_arms.py). Its older ledger line has nograder_version, so it is v1, and the appended lines are v2. It expectedcompareto pool their herding (2/3), but this ticket sayscomparemust not pool grader versions. The pooledherded(rows) == 2check is kept, so a line's excerpt and an older line's whole patch still herd by hash. Thecompareassertion now checks each version's own section: 0/1 for v1 and 0/2 for v2.test_the_ledger_records_the_skill_and_old_lines_still_load(test_eval_skill.py). The old v1 baseline line and the new v2 baseline line are now separatetrialsgroups. The assertion that old lines still load is unchanged.Why
Ticket: MIT-661. Substring matching gave false hits that start mid-word ("utc" in "outcomes", "9.2" in "9.21"). A bare version also counted as naming the cause, though a version only says when the cause arrived. Because v2 changes what a good proposal means, every result now records which grader scored it, and no figure pools two graders. Storing cause and fix lets later grader changes re-score new results.
How it was tested
scripts/test-db.sh uv run pytest server/tests/test_eval_*.py server/tests/test_variants.py: 279 passed.make check(origin/feature/eval-setupalready merged and unchanged since): all checks passed.Learned
cause_words_in_shipped_textintest_variants.pyand the skill/example check catch a superset of what v2 matches. Their docstrings ("matched the way the grader does") now describe v1.trialshas a new last column,grader. The section headers ofreport,compareandeffectsnow end in, grader vN. Substring assertions on the old headers still pass.🤖 Generated with Claude Code
https://claude.ai/code/session_01Qc1CQTb8r67J32HpkhS43y