Add neutral ignored_comments bucket to code-review scoring - #768
Conversation
Introduce an optional ignored_comments list on each code-review gold entry. A generated comment that matches an ignored comment (structural pairing plus the LLM judge, on the leftovers after expected matching) is dropped from scoring entirely: it earns no recall and does not count against precision. Expected comments always take precedence, so a comment that could match both is credited as a real find. Ignored counts are aggregated into the summary (micro precision subtracts them) and surfaced in the markdown/console tables and category_metrics for transparency. Macro precision now keys on scorable comments so a positive task whose only output is ignored is treated as silent rather than rewarded. Entries with no ignored_comments score identically to before. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 25bfd7a7-1805-4b6d-a577-7c9e5b7061b2
There was a problem hiding this comment.
🟡 Not ready to approve
The second judge pass can reuse stale expected-match verdicts and produce incorrect scores.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
Adds neutral ignored_comments support to code-review scoring.
Changes:
- Matches ignored comments after expected comments and excludes them from precision.
- Surfaces ignored counts in metrics and reports.
- Adds model, documentation, and scoring tests.
File summaries
| File | Description |
|---|---|
src/bcbench/dataset/codereview.py |
Defines ignored gold comments. |
src/bcbench/evaluate/codereview.py |
Adds ignored-comment judge pass. |
src/bcbench/results/codereview.py |
Updates scoring, aggregation, and reporting. |
tests/conftest.py |
Extends code-review test factories. |
tests/test_codereview.py |
Tests neutral scoring and aggregation. |
docs/code-review.md |
Documents ignored comments. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 3
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Addresses review feedback: the ignored bucket previously triggered a second LLM judge subprocess per evaluation, adding run-to-run nondeterminism and a second calibration target, and could reuse a stale judge_results.json from the expected pass. Expected and ignored structural matches are now judged in one judge_comment_matches_split call and split back by bucket. Also update the metric help text and docs so precision is defined over scorable generated (generated minus ignored).
There was a problem hiding this comment.
🟡 Changes recommended
Ignored matching excludes structurally paired comments before expected matches are semantically validated, causing incorrect precision penalties.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (1)
src/bcbench/evaluate/codereview.py:80
leftoveris computed before the semantic judge confirms the expected pairs. Becausematch_commentscan structurally pair any same-file comment, a generated finding that semantically matches an ignored comment can first be paired with an unrelated expected comment, receive a false expected verdict, and then never be considered for the ignored bucket. It is therefore counted as an incorrect comment instead of neutral. Run expected judging first and derive leftovers from the validated expected pairs before matching/judging ignored comments (or implement equivalent reassignment while preserving expected precedence).
leftover = unmatched_generated(generated_comments, structural_matches)
ignored_structural = match_comments(context.entry.ignored_comments, leftover)
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Sun Haoran (haoranpb)
left a comment
There was a problem hiding this comment.
Looks good, would be great to get test coverage on your critical metrics calculation path
Address review feedback on the neutral ignored_comments scoring: - Extract the scoring math from CodeReviewResult.create into a pure _score_counts helper and unit-test it directly (matched/incorrect/missed/ignored, precision, recall). - Add direct tests for unmatched_generated, including identity (not value) semantics. - Match ignored comments against all generated comments and apply expected precedence AFTER the judge, so a finding whose expected pair the judge rejects can still be neutralized as ignored instead of counting as a false positive (single judge pass preserved). - Remove the now-unused judge_comment_matches; rename judge_comment_matches_split to judge_expected_and_ignored and retarget the judge mechanics tests to judge_verdicts. - Rename ignored_comment_count to ignored_matched_comment_count to make clear it counts matched ignored comments, not the dataset size.
|
Thanks Sun Haoran (@haoranpb) - round 2 pushed (f156cbe). Summary: Test coverage (the blocking asks)
Naming / dedup
Correctness (from the bot thread)
Gauntlet green: ruff format/check + ty clean, 682 passed / 1 skipped (+10 new tests). |
Sun Haoran (haoranpb)
left a comment
There was a problem hiding this comment.
Looks good overall.
One design question: the distinction between ignored_comments and severity is not immediately clear to me. My understanding is that severity represents impact, while ignored_comments represents whether a finding is required for benchmark scoring. A low-severity expected comment still affects recall, whereas an ignored comment is neutral. Could we document that rationale and the criteria for choosing one bucket over the other?
This also highlighted that the core F score weights every expected finding equally: missing a critical issue has the same effect as missing a low-severity issue. Is that intentional? If impact should affect the leaderboard, severity-weighted precision/recall could provide a more general model, potentially ignored_comments can simplify be zero-weight findings => much easier.
Good work, see above comment for the challenge on the design here. Wenjie Fan (@gggdttt) |
What
Adds an optional
ignored_commentslist to each code-review gold entry (CodeReviewEntry). A generated comment that matches an ignored comment is treated as neutral: it is dropped from scoring entirely — it earns no recall and does not count against precision.This gives the code-review category a third comment state alongside the two it has today:
expected_commentsignored_commentsThe neutral bucket captures legitimate-but-debatable or out-of-scope findings that we do not want to force the agent to raise, but also do not want to punish it for raising (the long tail of "maintainer-judgment / accepted-noise" comments).
How it scores
judge_comment_matches_split), then split back apart by bucket - one judge subprocess per evaluation, so no extra run-to-run nondeterminism, no second calibration target, and no stale verdict-file reuse.precision = matched / (generated - ignored)recallis unchanged (ignored comments never grant recall).precision_recall(0, 0, N)already returns precision1.0(the "correct silence" convention), so a positive task whose only output is an ignored comment scores precision1.0/ recall0.0— it is treated as effectively silent, and macro precision keys on scorable comments so it is not rewarded as if it had commented correctly.Surfacing
ignored_comment_countis added toCodeReviewResult,CodeReviewResultSummary, andcategory_metrics.docs/code-review.mddocuments the neutral bucket and the new column.Backward compatibility
ignored_commentsdefaults to empty on every existing gold entry, soignored_count = 0and scoring is identical to today. All 81 gold entries are unaffected.Tests / validation
ruff format+ruff checkclean,tyclean, full suite 678 passed / 1 skipped (was 668 + 10 new tests).Open decisions (safe defaults — flagging for review)
judge_comment_matches_split), so this adds no extra LLM call. Alternative would be structural-only.category_metricsfor transparency. Easy to hide if we'd rather keep them internal.Happy to adjust either based on how we want to author gold entries.