Skip to content

fix(evaluation): score CAR on groundtruth_eval.json concept recall - #634

Merged
ShuxinLin merged 3 commits into
aafeedback_changesfrom
fix/car-concept-coverage-scoring
Oct 14, 2026
Merged

ShuxinLin merged 3 commits into
aafeedback_changesfrom
fix/car-concept-coverage-scoring

Conversation

@ShuxinLin

@ShuxinLin ShuxinLin commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Description

CAR scenarios ship groundtruth_eval.json again, but static_json never read it: the loader put it on Scenario.evaluation_metadata and the scorer ignored it. This PR scores CAR answers against its required_terms.

Fix Details

When a CAR scenario's groundtruth_eval.json has required_terms, the score is recall:

  1. Mode gate. The answer gets recall 0 unless it is a JSON object with exactly one top-level key and that key equals the mode key of groundtruth.txt. A multi-key answer counts as a mismatch.
  2. Concept coverage. Otherwise recall is the fraction of required concepts covered. A concept is covered when any one of its any_of forms, or a form's regular plural, appears in the value under the key. Matching is case-insensitive and on whole words.
  3. Pass. The scenario passes at recall >= 0.5 (CAR_PASS_THRESHOLD).

score and the Harbor reward are that recall. precision and f1 are null for these answers. A free-text value gives no count of what the model asserted, so precision could only repeat recall, and an F1 built from them would be recall under another name.

Example with two required concepts, asset (asset / equipment) and time window (time window / date range):

Model answer Recall Passed
{"clarification": "Which equipment, over what date range?"} 1.0 yes
{"clarification": "Which assets?"} 0.5 yes
{"clarification": "Can you say more?"} 0.0 no
{"abstain": "Which asset and time window?"} 0.0 no

Other details:

  • Plurals: a form also matches an added s, an es after s/x/z/ch/sh, or ies for a consonant + y (asset → assets, switch → switches, battery → batteries). For multi-word forms the plural goes on the last word. Irregular plurals still have to be listed.
  • Metadata fields: mode and optional_terms are not scored. Bare-string required_terms entries are accepted as one-form concepts.
  • Structured values: term matching read a structured value (an object or list under the key) through json.dumps. That kept upper-case letters out of the [a-z0-9] filter and turned a newline into \n, gluing an n onto the next word. It now joins the structure's keys and scalars and lowercases them.
  • Reports: the stale car_score aggregate is removed from report.py.
  • Unchanged: CAR scenarios without required_terms keep the extracted-term F1 and strict pass rule, with exact matching (no plurals). Non-CAR scoring is unchanged.

Impact on Benchmarking

  • No change to baselines: This fix only improves stability/performance.
  • Baseline change: This fix corrects a scoring error. (Please provide "Before vs. After" results).

Pooled re-score of 515 saved CAR answers (11 models), each through the loader and StaticJsonScorer:

Scorer Pass rate Mean score
Before (aafeedback_changes: extracted-term F1, strict pass) 3.7% 0.290
After (concept recall, pass >= 0.5) 39% 0.360
Reference: answers with the correct mode key 41% n/a

Earlier CAR results are on a different scale and should be re-scored from saved answers.

Known limits of term matching: nothing penalises padding, so an answer that lists every form gets full recall. Negation is not detected.

Related Issues

Verification Steps

  1. uv run pytest src/evaluation -q: 126 passed. In the full uv run pytest src/ -v -k "not integration", the only failures are 2 in src/observability/tests/test_file_exporter.py, which fail the same way on the base commit.
  2. Re-scored the saved answers above with the base and branch scorers. On the branch, every CAR result came from the concept path (f1 is null).
  3. Ran uv run evaluate on one CAR scenario: the report has f1_avg: null and recall as the score.

Checklist

  • I have added tests that prove my fix is effective.
  • My code follows the project's Ruff formatting and linting rules. (No new findings; 2 pre-existing ones are on untouched lines.)
  • I have signed off my commits (DCO).

When a CAR scenario ships groundtruth_eval.json with required_terms, the
static_json scorer now uses it. The answer earns 0 unless it is a
single-key object whose key is the groundtruth.txt mode. Otherwise its
credit is the fraction of required concepts covered, a concept being
covered when any one of its any_of forms appears, on word boundaries, in
the value under the key. The scenario passes at credit >= 0.5
(CAR_PASS_THRESHOLD). Precision, recall, f1 and the new car_score field
all report the credit: with one matching key the model side holds
exactly the gold entries, so an F1 reduces to coverage.

CAR scenarios without required_terms keep the extracted-term F1 and the
strict pass rule.

Term matching also read structured values through json.dumps, which
kept upper-case letters out of the a-z0-9 filter and turned a newline
into "\n", gluing an "n" onto the next word. It now joins the
structure's keys and scalars and lowercases the result.

Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
A groundtruth_eval.json form now also matches its regular plural: an
added s, es after s/x/z/ch/sh, or ies for a consonant + y. Before,
"Which assets?" missed the form "asset". Plurals apply to the last word,
so "failure type" matches "failure types". Terms extracted from the gold
value, used when a scenario has no groundtruth_eval.json, still match
exactly.

Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
A CAR answer scored on groundtruth_eval.json concepts now reports recall
as its score and pass criterion (recall >= 0.5). Precision and f1 are
None: a free-text value gives no count of what the model asserted, so
precision could only repeat recall and the f1 built from them was recall
under another name. car_score duplicated recall and is removed, along with
its report aggregate.

Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
@ShuxinLin ShuxinLin changed the title fix(evaluation): score CAR on groundtruth_eval.json concept coverage fix(evaluation): score CAR on groundtruth_eval.json concept recall Oct 14, 2026
@ShuxinLin
ShuxinLin merged commit 0ef2898 into aafeedback_changes Oct 14, 2026
5 checks passed
@ShuxinLin
ShuxinLin deleted the fix/car-concept-coverage-scoring branch October 14, 2026 23:45
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