Repository navigation
feat(cli): sieval run --dry-run reports each task's report metric names - #225
Merged
Merged
Conversation
ethan-scitix
force-pushed
the
feat/report-metric-names
branch
from
October 23, 2026 12:20
28dce0d to
ab16974
Compare
A platform that judges a result against an author's criterion, such as a
smoke `score: {min: 0}` or a board column on `pass@1`, finds a misspelled
name only as a key missing from `report.json`, after the run. Which keys a
report can write is fixed by its code, so it is known before.
`tasks.<task>.metrics` in the dry-run JSON is `{names, patterns}`, or null
when unknown. `names` are the numeric keys the report may write; a
`{placeholder}` pattern such as `score_{category}` stands for keys built
from the data, which a run without that group does not write.
- `sieval.core.tasks.report_metrics`: `ReportMetrics`, and the lookup from
a task class to its declaration. A subclass inherits a declaration with
the report it describes; one with its own `report`, or a patched one, is
unknown until it declares. A generative task gains the runner's keys.
- `sieval/meta/report_metrics.py` declares every built-in task by the class
that defines `report`. It sits outside the grader walk because an
attribute in a task module would change every stage identity; all 84
tasks' stage code and legacy grader keys are unchanged.
- A plugin task declares `report_metrics = report_metrics(...)`.
- Every task test checks its report's numeric keys against the declaration.
- The text summary marks a task whose metrics are unknown.
Closes #223.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ethan-scitix
force-pushed
the
feat/report-metric-names
branch
from
October 23, 2026 12:24
ab16974 to
4185d5e
Compare
A plugin whose `report_metrics` is not a `ReportMetrics` raised a TypeError that the dry-run caught and reported as `metrics: null`, which a check reads as "unknown, do not refuse". Only a class that does not resolve is advisory now; a malformed declaration fails a new `report_metrics` check, also when a nearer `report` shadows it. - `ReportMetrics | "score"` refused: a str is iterable and added one name per character. - A `report` from another module reads as unknown whether patched or bound in the class body; documented, since the two look alike at runtime. - `_owners()` in the task conftest is cached; docs and docstrings trimmed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
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.
Type
Summary
A platform checks a result against criteria an author wrote, such as a smoke
score: {min: 0}or a board column onpass@1. A misspelled name shows up only as a key missing fromreport.json, after the run. This PR makes each task's report metric names known before the run, in the dry-run JSON.tasks.<task>.metricsis{"names": [...], "patterns": [...]}, ornullwhen unknown.namesare the numeric keys the report may write. A pattern such asscore_{category}stands for keys built from the data; a run whose data lacks that group does not write the key. It sits next to feat(cli): sieval run --dry-run reports each task's stage plan #220'sstagesandneeds_inference, and is also present next to a refused task'serror.report()on stub records would need a stub per task'sfeedback_resultshape, and it would miss the data-dependent andn > 1keys. So instead every task unit test wraps the task'sreport()and fails if the report writes a numeric key its declaration lacks.sieval/meta/report_metrics.py, keyed by the class that definesreport. A task module's source is part of its stage identities, so a class attribute there would change every stage identity and rerun every resumed directory frompostprocess.sieval.metais outside the grader walk.report_metrics = report_metrics("score", patterns=("score_{subset}",)), fromsieval.core.tasks.report_metrics. A subclass inherits a declaration together with thereportit describes. A subclass with its ownreportis unknown until it declares. So is areportdefined in another module than its class: a patch, or a shared function bound in the class body, which look the same at runtime (wrap it in adef). A generative task also gets the runner'sn_truncatedandn_scored_rollouts.report_metricsthat is not aReportMetricsorNonefails a newreport_metricscheck, also when a nearerreportshadows it, rather than reading asnull, which a check takes as "unknown, do not refuse". Only a class that does not resolve is advisory (null); the imports check reports it.ReportMetrics | "score"raises instead of adding one name per character., report metrics unknownon its line.Identity impact. None. For all 84 registered tasks,
stage_code()andlegacy_grader_keys()are byte-identical before and after this change, checked on this branch's base. A test also asserts that no built-in task class carries the attribute and thatsieval.metais outsideGRADER_PACKAGES._task_json. One parameter and one key are added next to #220's additions. No other change in that function.Related Issues
Closes #223. Follows #217 and #220.
Test Plan
Automated
ruff check && ruff format --check)ty check)pdm run pytest)pytest tests/unit tests/integration tests/acceptance -m "not stress and not benchmark" -n auto --cov --cov-fail-under=95, installed with every CI group, passes at 97.11% coverage on macOS, rebased on #224. The one consistent failure istest_exec_quotebench_anchor.py, which also fails onmainon macOS. In one loaded runtest_signals.py::test_sigterm_runs_shielded_cleanup_and_exits_143timed out once; it passes alone three times out of three.tests/performance -m "not stress"passes. After the review fixes, on Linux:tests/unit/taskswithtest_lazy_launch.py(1969 passed) andtests/unit/cli tests/unit/meta tests/unit/core/tasks(2233 passed, 1 skipped).ty check,sync_package_stubs.py --check,check_preflight.pyandpre-commit run -aare clean.tests/unit/tasks/conftest.py: every built-in task'sreport()is checked against its declaration in every test that runs it. Removingacc_normfrom HellaSwag's entry fails its test, naming the key.tests/unit/meta/test_report_metrics.py: every registered task is declared, every entry names a class that definesreport, every task but T-Eval declaresscore, generative tasks get the runner's keys, and the table stays outside every stage identity.tests/unit/core/tasks/test_report_metrics.py: pattern matching (whole name, non-empty placeholder, literal@), the rejection of a pattern with no literal part, inheritance, areportbelow the declaration, a patchedreport,None, table versus attribute precedence, a union with a barestr, and a malformed declaration below a nearerreport. 100% line and branch coverage ofsieval/core/tasks/report_metrics.py.tests/integration/test_lazy_launch.pyruns the real CLI. A declared plugin task reports its names on a fresh run, a resume and a refused resume. With a patchedreportits metrics arenull.tests/unit/cli/test_run.py:_run_dry_run, throughsieval.cli.validation.task_report_metrics_json, with a built-in task, one with patterns, an undeclared subclass, an unresolvable class and an entry with no class. The last three arenulland fail nothing. A malformed plugin declaration isnullbeside a failedreport_metricscheck naming the task, and the other tasks keep their metrics.Checklist
Required (all PRs)
type(scope): description)AI-Generated Code - <model> (<provider>)in module docstringcore/