Repository navigation
fix(task_formats): import blank judge and empty-list asserts unsupported - #266
Conversation
Settles two review points of intel#214 (task-format importers). promptfoo: a judged assert (llm-rubric, factuality, g-eval, ...) whose value is missing or blank after strip() imported as a judge check with no criterion or reference, and a contains*/icontains* assert with an empty list imported as a match check with no values. validate_grading refuses both, so one such assert made `eval reference` refuse the whole file. _other_check now returns None for a blank judged value and _text_check returns None for an empty contains* list, so both import as `unsupported` with the "not translated" note, like a blank text value already did. Inspect: the grader's `exact` check SQuAD-normalises the target, so a target such as "..." or "the" becomes "" and equals no answer; it was kept as a check that always fails. _checks now drops such a target for the `exact` scorer, so a sample left with no target is `unsupported`. `includes` and the model-graded scorers are unchanged. docs/answer-formats.md states the new rules; changelog fragment (Fixed). Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
|
@exai-bot /review |
exai-bot
left a comment
There was a problem hiding this comment.
Note
AI-generated review of 7c79ac37e7d8, requested by @antonwolfy, using the default review skill. It can be wrong: verify a finding before acting on it. React with a thumbs up or down on a finding to tell the bot whether it helped.
Model us.anthropic.claude-sonnet-5-5, effort default, 5 of 80 turns, 0.3 of 40 minutes, 115k in / 2k out tokens.
The change makes the promptfoo importer return unsupported for judged asserts with a blank or missing value and for contains* asserts with an empty list. It also makes the Inspect importer drop exact targets that SQuAD-normalise to nothing. I checked the new conditions against as_list, blank_value, validate_grading and the exact grader in reference_checks.py. The conditions are correct and match what eval reference refuses. The new tests cover each branch. I found no defects.
No issues found.
For a human reviewer
- Inspect's own
exactscorer would count an empty-normalising answer (e.g....) as equal to an empty-normalising target. Dropping the target follows dokimi's grader, which never passes an empty target, but it differs from the native scorer. Confirm that is intended.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #266 +/- ##
==========================================
- Coverage 92.83% 92.82% -0.01%
==========================================
Files 262 262
Lines 33016 33020 +4
Branches 5510 5512 +2
==========================================
+ Hits 30649 30651 +2
- Misses 1571 1573 +2
Partials 796 796
🚀 New features to boost your workflow:
|
Summary
Follow-up to the review of #214 (task-format importers). It settles two points there. First, a promptfoo assert with a blank judge value, or a
contains-anyassert with an empty list, imports cleanly, and theneval referencerefuses the whole file (review). Second, an Inspectexacttarget such as...imports as a check that no answer can pass (review). Neither thread got an author reply.On
main(3a1f287),questions importgives:validate_grading/ grade{type: llm-rubric, value: ''}{'type': 'judge', 'native': 'llm-rubric'}a judge check needs a criterion or a reference{type: factuality, value: ' '}{'type': 'judge', 'reference': ' ', 'native': 'factuality'}a judge check needs a criterion or a reference{type: contains-any, value: []}{'type': 'match', 'values': [], ...}match has no valuestarget: "...",--scorer exact{'type': 'exact', 'values': ['...']}passedisFalseforzzz,...and?eval referencechecks every question's grading block before it grades any (grading_by_id). So one of the first three asserts makes it refuse the whole file. The fourth fails safe, but it scores 0 without saying why.docs/answer-formats.mdalready says a blank promptfoo assert imports asunsupported, and onmainthat does not hold for these cases.Changes
task_formats/imports/promptfoo.py:_other_check: a judged assert (llm-rubric,g-eval,model-graded-closedqa,factuality,model-graded-factuality) whose value is missing or blank afterstrip()returns no check. It then imports asunsupported, with theassert `<type>` not translatednote, the same path as a blank text assert. A non-blank judge value imports as before._text_check: acontains*oricontains*assert with an empty list now imports asunsupportedthe same way.task_formats/imports/inspect_ai.py(_checks): the grader'sexactcheck compares SQuAD-normalised text and never passes an empty target. For theexactscorer, the importer now also drops a target thatsquad_normalizeturns into nothing (...,the). A sample left with no target isunsupported, as it already is formatch.includesand the model-graded scorers are unchanged.tests/test_answer_imports.py:unsupportedwith the note.llm-rubricassert:validate_gradingreturns nothing and the good judge check is kept....and["The", "Paris"]rows underscorer="exact"in the Inspect punctuation test, renamedtest_inspect_punctuation_only_target_is_unsupported_for_match_and_exact.docs/answer-formats.mdstates the empty-list, blank-judge and Inspectexactrules next to the existing blank-value rule.Risk
Only imports that
eval referencecould not use, or that could never pass, change:unsupported(listed, not counted) instead of producing a grading block thateval referencerefuses.exactscorer whose targets all normalise to nothing becomesunsupportedinstead of always failing. A sample with at least one real target keeps it (["The", "Paris"]imports asvalues: ["Paris"]).Other assert types, the
match,includesand model-graded Inspect scorers, and every non-blank value import as before.Testing
On a Linux review host, at
7c79ac3(onmain3a1f287):make ci-local: 28 passed, 0 failed, 7 skipped:test-latest, docsdeploy, pip-auditreport.external-catalog-smoke(needs docker and network),conda-forge-deps(no micromamba), semgrep secrets (runs on the PR).Package the result.tests/test_reference_checks.py::test_the_regex_limit_is_shared_by_every_pattern_of_one_check, a wall-clock bound (elapsed < 1.5 * REGEX_TIMEOUT). It measured 2.16 s and 1.79 s while other jobs loaded the host. It passes on its own, passed in a full-n auto --covrun of this commit, and passed in the thirdci-localrun. This change does not touch the regex check.mainit prints the outputs in the table. At this commit, all four import asunsupported, andvalidate_gradingreturns[]for each.main's code and pass here._text_checkfails thecontains-anycase and the mixed-file test._other_checkfails thellm-rubriccase, thefactualitycase and the mixed-file test.value is Nonefor a judged assert fails the same three tests.exactrule fails the Inspect test.exactbut keeping articles fails the Inspect test (onThe).includesmust keep...).ruff checkandmypypass on the touched modules, as dotests/test_docs_code_refs.py,tests/test_growth_ratchet.py,tests/test_audit_test_quality.pyandtests/test_import_architecture.py.ci-local's smoke.Same bug class, not in this PR
task_formats/imports/openai_evals.py: a modelgraded spec with whitespace-onlycriteriaand noidealimports as a judge check with criterion' ', whichvalidate_gradingrefuses. Thenot (criteria or reference)guard does not strip.eval/reference_checks.py:validate_gradingdoes not flag a hand-writtenexactvalue that SQuAD-normalises to nothing (...,the). Such a check validates and never passes.starts-withandregexwith a list value import as thestr()of the list ([]becomes the string'[]').Revert
A plain revert. Nothing is stored in a new format: questions that were imported keep the checks they were written with.
Checklist
pytestpassesruff,mypy, and schema checks passAGENTS.md.github/.licenserc.yaml)