Repository navigation
fix(report): report generate exits 1 on an eval file with no evaluations - #268
Conversation
`report generate` with `{}`, `{"evaluations": []}` or `[]` as `--eval`
printed "Loaded 0 evaluations" and then ended in a ZeroDivisionError
traceback from the failure-analysis rate in the report generator. It now
prints `Error: --eval <path> holds no evaluations`, exits 1 and writes no
report, as the command's other unreadable-eval cases do.
The pipeline (`EvaluationPipeline._generate_report`) also feeds the
generator, straight from its own run, and nothing stops that run from
judging no answers (an empty `--questions-from` set), so the generator's
Rate cell now shows `n/a` when the failure summary's total is 0.
The tests that used an empty eval to reach a later error (unwritable
output, unreadable or invalid questions) now use a one-record eval.
Settles review point B3 of intel#191.
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 89d4b771bb6c, 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, 9 of 93 turns, 0.7 of 48 minutes, 130k in / 3k out tokens.
The PR makes report generate exit 1 with a clear message on an eval file with no evaluations, and guards the Rate cell against a zero total in the generator. The generator guard is correct. The CLI guard is broader than the crash it fixes: it also rejects a --format json run that worked on main.
1 finding is on the changed lines, as comments below.
For a human reviewer
- Product call: should an eval with zero evaluations be an error for every output format, or only for the markdown report that crashed?
Not verified
I did not run the full test suite or make ci-local. I checked the JSON-format claim by calling the generator directly, not through the CLI.
The empty-eval check in report generate covers every output format. --format json never crashed on it and used to write a zero-stats report; the changelog now says that it is refused as well, and the empty-eval test runs for both formats. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
vchamarthi
left a comment
There was a problem hiding this comment.
No blocking findings. The refusal and the n/a guard behave as the description says.
Checked on 619256b against its merge base, report generate with --questions holding {"questions": []}:
--eval holds |
base | head |
|---|---|---|
{"evaluations": []} |
ZeroDivisionError, exit 1 |
Error: --eval <path> holds no evaluations, exit 1 |
{} |
ZeroDivisionError, exit 1 |
same message, exit 1 |
{"evaluations": [], "meta": 1} |
ZeroDivisionError, exit 1 |
same message, exit 1 |
[] |
must hold a JSON object, exit 1 |
holds no evaluations, exit 1 |
[1], {"evaluations": null} |
existing messages | unchanged |
tests/test_report_cli_inputs.py and tests/test_questions_artifact.py pass (133 passed). The other averages in generator.py are already guarded, so generator.py:472 was the only unguarded division.
Not repeated: the --format json point from the earlier review, which the description and 619256b already answer.
Coverage: read the whole diff and probed the CLI on the shapes above. Not checked: CI results on this head, a full pipeline run that judges zero answers, and the mutation results in the description.
| # Every --format: a report of no evaluations has nothing to show, and an empty | ||
| # eval means the run that wrote it judged nothing. | ||
| evaluations = eval_data.get("evaluations", []) if isinstance(eval_data, dict) else eval_data | ||
| if isinstance(evaluations, list) and not evaluations: # {}, {"evaluations": []}, [] |
There was a problem hiding this comment.
question: report generate now refuses an empty eval that report eval still accepts
report.py:128 (cmd_report_generate): the new check exits 1 for {"evaluations": []}, but report eval on the same file exits 0, writes p_full.md and prints Questions: 0 ... Delta: +0.0. The reason given for the refusal (an empty eval means the run judged nothing) holds for both commands.
How to check: {"evaluations": []} as --eval: report generate exits 1 with holds no evaluations; report eval --product p --eval <file> exits 0 and writes a zero-stats report (base: the same for report eval, pre-existing).
Is the split intended? If so, a line in the PR description saying why eval keeps writing an empty report would help. If not, the same check belongs in report eval, or in #250 if that PR is where the report commands are unified.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #268 +/- ##
==========================================
+ Coverage 92.83% 92.85% +0.02%
==========================================
Files 262 262
Lines 33016 33020 +4
Branches 5510 5511 +1
==========================================
+ Hits 30649 30660 +11
+ Misses 1571 1567 -4
+ Partials 796 793 -3
🚀 New features to boost your workflow:
|
|
…ons (intel#268) * fix(report): exit 1 on an eval file with no evaluations `report generate` with `{}`, `{"evaluations": []}` or `[]` as `--eval` printed "Loaded 0 evaluations" and then ended in a ZeroDivisionError traceback from the failure-analysis rate in the report generator. It now prints `Error: --eval <path> holds no evaluations`, exits 1 and writes no report, as the command's other unreadable-eval cases do. The pipeline (`EvaluationPipeline._generate_report`) also feeds the generator, straight from its own run, and nothing stops that run from judging no answers (an empty `--questions-from` set), so the generator's Rate cell now shows `n/a` when the failure summary's total is 0. The tests that used an empty eval to reach a later error (unwritable output, unreadable or invalid questions) now use a one-record eval. Settles review point B3 of intel#191. Signed-off-by: Anton Volkov <antonwolfy@gmail.com> * fix(report): refuse an empty eval for --format json too, and test it The empty-eval check in report generate covers every output format. --format json never crashed on it and used to write a zero-stats report; the changelog now says that it is refused as well, and the empty-eval test runs for both formats. Signed-off-by: Anton Volkov <antonwolfy@gmail.com> --------- Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
Summary
Follow-up to the review of #191, where
report generatewas found to still end in a traceback for an eval file that parses but holds no evaluations (review; no reply). Onmain, with--questionsholding{"questions": []}:--evalholdsmain{"evaluations": []}ZeroDivisionError: division by zerotraceback fromrate = f"{count / total_q:.0%}"(dokimi/report/generator.py:472)Error: --eval <path> holds no evaluations, no report written{}[]Error: <path> must hold a JSON object[1](a non-empty list)Error: <path> must hold a JSON objectThe table is for the default
--format markdown. With--format json,mainnever crashed on an empty eval: it exited 0 and wrote a report of zero stats. This PR refuses it with the same message, because a report of no evaluations has nothing to show, and an empty eval means the run that wrote it judged nothing.summarise_diagnosesreturnstotal: 0for no records, so the.get("total", 1)default never applied.Changes
cmd_report_generate(dokimi/commands/report.py): an eval that is{},{"evaluations": []}or[]printsError: --eval <path> holds no evaluationsto stderr and exits 1 before the questions are read and before any report is written, for both--format markdownand--format json. This is the exit code andError: ...style of the command's other unreadable-eval cases. A non-listevaluations(null,5) still goes to the existingRecordErrormessage.ReportGenerator._format_markdown(dokimi/report/generator.py): when the failure summary's total is 0, the Failure Analysis table's Rate cell showsn/a.report generatecan no longer get there, butEvaluationPipeline._generate_report(dokimi/orchestrator/pipeline.py) also calls the generator, on its own run's eval file. Nothing in that path refuses a run that judged no answers: an empty--questions-fromor cached question set passes the schema, which has no minimum item count.tests/test_report_cli_inputs.py): each empty shape exits 1 with exactly that message and writes no report, in both formats, a one-evaluation eval writes the report, and a direct generator test with zero evaluations showsn/ain every Rate cell. Five existing tests, two in that file and three intests/test_questions_artifact.py, used{"evaluations": []}to get past the eval and now use a one-record eval. They test an unwritable output, unreadable, invalid or empty-question questions files, and reading a legacy questions set. Two of thetest_questions_artifact.pyones would otherwise have kept passing on the new eval error instead of the error they test.Risk
report generatenow refuses an empty eval file. With--format markdownthat input only ever reached the traceback. With--format jsonit used to exit 0 and write a zero-stats report, and now exits 1: a script that writes an empty eval and asks for JSON fails where it used to pass.[]gets the new message instead of "must hold a JSON object", and it still exits 1. Pipeline reports for a run with no evaluations shown/arates instead of crashing. Every report with at least one evaluation is unchanged.Testing
On a Linux review host, at
619256b(onmain3a1f287):make ci-local: 28 passed, 0 failed, 7 skipped (agent-quality.yml:external-catalog-smokeneeds docker and network;ci.yml:test-latest,docs.yml:deployandpip-audit.yml:reportare off on a PR;cli-interface.yml:cli-surface / Package the resultuses an expression the local runner does not evaluate;conda-forge.yml:conda-forge-depsneeds micromamba; the org-level semgrep secrets check runs on the PR). 9306 tests passed, 4 skipped; changed-line coverage 100% (5 lines measured).cli.py report generatewith{"evaluations": []},{}and[]as--eval, with--format markdownand with--format json: exit 1, the oneError: --eval ... holds no evaluationsline on stderr, no traceback, no report file. With[1]: exit 1,must hold a JSON objectas before.main's code, the three empty-shape cases and the directn/atest fail (two with theZeroDivisionErroratgenerator.py:472). The one-evaluation test passes there: it pins behaviour that already worked.cmd_report_generatefails all three empty-shape cases.--format markdownfails the three--format jsoncases.n/aguard fails the direct generator test.if not total_q) fails the one-evaluation test and the direct generator test.Revert
A plain revert. Nothing is stored and no schema changes.
Checklist
pytestpassesruff,mypy, and schema checks passreport generate's exit-1 cases)AGENTS.md.github/.licenserc.yaml) (the changelog fragment is exempt)