Repository navigation
test(records): hold readers of with_docs/without_docs to dokimi.records - #203
Conversation
Settles the review point on intel#80 that "every reader goes through records.py" was too strong, with nothing to keep it true for the next reader. - The pipeline summary in orchestrator/pipeline.py read the evaluation dicts' "with_docs"/"without_docs"/"delta" keys; it now reads them through records.records(), Record.score and Record.delta. A test pins the summary numbers (means over the judged questions, a failed question skipped). - tests/test_records_guard.py scans dokimi/ with ast for x["with_docs"] loads and x.get("with_docs") calls outside records.py, against a baseline of (module, function) -> reason. A new read fails, naming dokimi.records; a baseline entry that no longer matches fails as stale, so it only shrinks. - AGENTS.md names the test next to the rule. 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 351a19fd1c99, requested by @vchamarthi, 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, 8 of 93 turns, 0.7 of 48 minutes, 202k in / 4k out tokens.
This PR adds an AST-based test that holds readers of with_docs/without_docs outside dokimi.records to a shrinking baseline. It also moves the pipeline run summary onto records(), Record.score and Record.delta, and adds a test that pins the summary numbers. The pipeline change is behaviour-preserving for judge-written rows. The judge already calls records(evaluations, kind="evaluations") on the same list, so the new RecordError path adds no new failure mode. I found no real defects. I did not run anything, but the baseline keys match the read sites I grepped.
1 finding is on the changed lines, as comments below.
For a human reviewer
- Whether the five baseline exceptions are acceptable to keep, mainly
eval.question_text.has_answer_to_judge, which reads persisted record dicts.
Not verified
I did not run the tests. That includes whether test_pipeline_summary.py gets through _read_question_inputs and _save_questions_artifact with the minimal cached question file it writes.
vchamarthi
left a comment
There was a problem hiding this comment.
Not approving yet: 1 item to fix before merge.
CI: 2 checks pass, 18 are still pending, 1 skipped at 351a19f. The pipeline change is correct; one point on the guard: it lets new reads through in the five baselined functions.
CI at send time: 0 failing, 12 pending.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #203 +/- ##
==========================================
+ Coverage 91.78% 91.98% +0.20%
==========================================
Files 223 223
Lines 27623 27711 +88
Branches 4549 4553 +4
==========================================
+ Hits 25354 25491 +137
+ Misses 1606 1572 -34
+ Partials 663 648 -15
🚀 New features to boost your workflow:
|
exai-bot
left a comment
There was a problem hiding this comment.
Note
AI-generated review of 351a19fd1c99, requested by @vchamarthi, 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, 7 of 93 turns, 0.6 of 48 minutes, 161k in / 3k out tokens.
Re-review of 351a19fd1c99: 1 new finding.
1 finding is on the changed lines, as comments below.
Review of intel#203 (vchamarthi, exai-bot): the baseline was keyed by (module, function) only, so a new `row.get("without_docs")` inside one of the five listed functions passed, and the stale check could not see a function that lost some of its reads. Each entry now holds the number of reads there (2, 2, 6, 2 and 15 today). A read beyond it fails as new; fewer reads than it counts fail as stale with the count to lower to. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…ion key Review of intel#203 (vchamarthi): `x.pop("with_docs")` and `x.setdefault("with_docs", ...)` read the key as `get` does; the scanner matched only `get`. No such read exists in the package today. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
exai-bot
left a comment
There was a problem hiding this comment.
Note
AI-generated review of 1b1e718ef26b, requested by @vchamarthi, 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, 10 of 93 turns, 0.8 of 48 minutes, 214k in / 4k out tokens.
Re-review of 1b1e718ef26b: nothing new.
Coverage
- Held back 1 finding the verifier refuted.
Held back 1 finding
| Grade | Category | Why held | Finding | Where | Evidence |
|---|---|---|---|---|---|
| - | - | refuted | Summary step can now abort the run with RecordError after the expensive steps | dokimi/dokimi/orchestrator/pipeline.py:384 | The pipeline's evaluations come straight from judge.evaluate_answers (pipeline.py:376, 647-686). judge.py ends that method with records(evaluations, kind="evaluations") over the same list, so a ma [cut] |
napetrov
left a comment
There was a problem hiding this comment.
The pipeline summary move onto dokimi.records and its test look good. Question on the guard: 283 lines of AST scanning plus a baseline of 27 reads (5 entries, 15 in generate_section_report alone) to hold one naming rule, and the docstring already lists what it misses (reads via the constants, in tests, .raw). Is this weight worth it versus a simpler grep-style check alongside test_import_architecture.py? Alternatively, move the remaining readers first so the baseline is near-empty and the guard stays small.
… AST Review of intel#203 (napetrov): 200 lines of AST scope tracking was a lot to hold one naming rule. A regex over `["with_docs"]` subscripts not assigned to and `.get/.pop/.setdefault("with_docs")` calls finds the same 27 reads on the same lines, and counting them per module keeps both properties the review asked for: a new read fails wherever it is, inside an already-listed module too, since its count goes up; and a count above what is left fails as stale. The baseline is four modules (2, 2, 6, 17). The file goes from 212 to 121 lines. Moving the remaining readers instead would mean changing `report/model_compare.py`, whose 17 reads are on the per-question score rows it builds itself, not on stored records. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
|
@napetrov fair. 0b3af09 replaces the AST scanner with one pattern: an
On moving the readers first: the 17 in |
exai-bot
left a comment
There was a problem hiding this comment.
Note
AI-generated review of 0b3af098b8ca, requested by @vchamarthi, 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, 6 of 93 turns, 0.6 of 48 minutes, 148k in / 3k out tokens.
Re-review of 0b3af098b8ca: 1 new finding.
1 finding is on the changed lines, as comments below.
| from collections.abc import Mapping | ||
| from pathlib import Path | ||
|
|
||
| PACKAGE = Path(__file__).resolve().parents[1] / "dokimi" |
There was a problem hiding this comment.
Nit (plausible, maintainability): Pattern also counts reads quoted in comments and docstrings
READ runs over raw source text, so a comment or docstring that quotes r.get("with_docs") counts as a read. Adding one in a listed module fails the guard as 'too many', and removing one fails it as 'stale'. Both are harmless and the message makes the cause findable. The test docstring could say that comments count, or the scan could strip comments first.
Summary
Follow-up to the review of #80 (point 1). #80 made
dokimi/records.pythe one reader of answer and eval records, andAGENTS.mdstates the rule, but nothing enforced it for the next reader. The author agreed a guard needs an allow-list and left it for a follow-up. This is that follow-up.Changes
tests/test_records_guard.pycounts, per module ofdokimi/dokimi/, the reads of the persisted condition keyswith_docsandwithout_docsoutsidedokimi.records. One pattern does it: anx["with_docs"]subscript not assigned to, or anx.get("with_docs"),.popor.setdefaultcall. Assignments and dict-literal keys are writes and don't match.READ_BASELINE, one entry per module with its read count and reason. More reads than the count fail, so a new read fails wherever it is, a listed module included, and the message says to go throughdokimi.records. Fewer reads than the count fail as stale, with the count to lower to, so the baseline only shrinks per read.eval.answerer(2) counts the answers it just built;eval.question_text(2) takes the record dict the judges pass asRecord.raw;report.generator(6) reads the statistics dict it computed;report.model_compare(17) reads the score rowsextract_scoresbuilt.ast(212 lines); per-module counts catch the same reads with one pattern.orchestrator/pipeline.py: the run summary (the per-condition and delta means) was the one site that read persisted records by their keys (e["with_docs"]["aggregate"]). It now reads throughrecords()andRecord.score/Record.delta.tests/test_pipeline_summary.pypins the numbers, and it passes on both the old code and the new.AGENTS.md: therecords.pybullet names the test.Risk
records()raises on an evaluation with noquestion_id, while the old comprehension skipped such a row. The judge writesquestion_idon every row, error rows included, so a run does not produce one.records.CONTEXT,"with_docs" in xtests, and.rawreads such asrec.raw.get("question_text"). A pattern can't tell those apart from other.rawattributes, such asTask.rawinrepos.Testing
On a Linux review host, at
8abd0e2(onmain506f7ba):make ci-local: 29 passed, 0 failed, 7 skipped (the Docker catalog smoke,test-latest, thecli-surfacepackaging step, conda-forge-deps without micromamba, docsdeploy, the pip-audit report, semgrep). 7,392 tests passed, 1 skipped; changed-line coverage 100% of 5 lines.r.get("with_docs")indokimi/utils.pyfails the guard and names the site. A third read inAnswerer.generate_answers, which is in the baseline with 2, fails it as new. Dropping one of that function's two reads fails it as stale.main92d92d3 (test(llm): pin provider-call budgets for judge, panel, answer and validation paths #170, tests only) before opening; with the ten follow-up branches merged together, the full suite (7,447 passed, 1 skipped), the growth check,mypyandruffpass.0b3af09:make ci-local29 passed, 0 failed, 7 skipped; 7,415 tests passed, 1 skipped; changed-line coverage 100% of 5 lines.Checklist
pytestpassesruff,mypy, and schema checks pass.github/.licenserc.yaml)