Skip to content

test: pin review leftovers of #590, #595 and #472; read_json_input names an empty path - #753

Open
antonwolfy wants to merge 9 commits into
intel:mainfrom
antonwolfy:test/leftovers-2026-11-14
Open

antonwolfy wants to merge 9 commits into
intel:mainfrom
antonwolfy:test/leftovers-2026-11-14

Conversation

@antonwolfy

@antonwolfy antonwolfy commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-up to the reviews of #590, #595, #472, #706 and #637, which left these points open. Each test below was a mutant that passed the whole suite on main.

Changes

  • tests/test_cli_output.py: a probe leaf with --json and --jsonl reads --jso as no --json request and prints no document; catalog check --jso is no request either; repo validate and repo validate . --cache-dir without --json print nothing on stdout, the message on stderr, exit 2.
  • tests/test_novelty_routing_gaps.py: two skills named review, one in review/ and one in review/review/, are held by no single directory. catalog routing says no --keep-copies-under picks one of its copies and never names --against; skill routing says no --against or --keep-copies-under picks one of its copies.
  • tests/test_novelty_checks.py: "Do not use perf script but perf report --stdin" and "Never guess flags while you run perf report --stdin" are vetoed, with controls (or, when) that stay negated; "Avoid", "Avoiding" and "without" before perf report --stdin make no claim, and the same sentences with a neutral word are vetoed; one checks_summary call over seven runs asserts all six fields. The veto tests sit here, next to the other identifiers-veto tests, because tests/test_reference_checks.py has none.
  • tests/test_catalog_path_missing.py: a missing assets/a\;b.svg is named assets/a;b.svg whole when bare.
  • dokimi/docs/repo-evaluation-contract.md: a pinned snapshot's submodules are its .gitmodules paths and every gitlink, declared or not; a bare name matching only a submodule (mod/) is unresolved.
  • dokimi/dokimi/utils.py: read_json_input refuses an empty path first, as InputError --answers "": no file given (cannot read "": no file given without a flag). Exit stays 2. dokimi/dokimi/questions/artifact.py: load_questions hands the raw path to read_json_input before it makes a Path, so --questions "" is refused by name too (--questions "": no file given). tests/test_load_or_fail.py covers both forms, eval score reference --answers "" through cli.main, and load_questions("", flag="--questions").
  • Changelog fragment (Fixed), for the read_json_input change.

Risk

Only read_json_input and the way load_questions calls it change behaviour: an empty path, which was read as . and failed with Is a directory, is now refused by name; every caller still exits 2 with an InputError. A non-empty path is read unchanged. The other commits are tests and one doc sentence.

Testing

On a Linux review host, at 58c79ee (on main b4bcfa4):

  • make ci-local: 31 passed, 2 failed, 14 skipped (the skips are the jobs that do not run on a PR, the other matrix legs, conda-forge, semgrep, fuzz). 20418 tests passed, 19 skipped; changed-line coverage 100% (2 lines). The 2 failures are the host: Install gitleaks (the download returned HTTP 504 four times) and Scan commits (no gitleaks binary).
  • eval score reference --answers "": on main Error: --answers : Is a directory; here Error: --answers "": no file given, exit 2.
  • Mutants, each failing in a copy of the tree: _json_requested abbreviation test always true (2 tests fail); _LeafParser.error without and self._json_argv (3); if not all_vs_all for picks_flag (2); but dropped (1); while dropped (1); avoid\w* dropped (2); without dropped (1); checks_summary overruled ==, decided without not in vetoed, judge_agreed !=, checked_runs 0 (1 test, fails for each); ; dropped from _ESCAPE_RE (1); the empty-path refusal removed (3). ; dropped from _INNER_ESCAPE_RE is not pinned: inside double quotes a shell keeps the backslash of \;, so the code's current name there is wrong and no test fixes it. The _ESCAPE_RE mutant and _has_a_node with len(nodes) > 0 were run against the whole suite first: the escape mutant passed it, the _has_a_node one failed test_the_need_graph_caches_only_a_graph_with_a_node.
  • fix(repo): a pinned source reads a .. after a gitlink directory as a checkout does #706: with the gitlink part of Scan.submodules removed, test_a_submodule_without_a_gitmodules_entry_is_still_a_directory fails; with the bare-name submodule filter removed, both cases of test_a_bare_submodule_name_is_unresolved_like_its_full_path fail. On the code before fix(repo): a pinned source reads a .. after a gitlink directory as a checkout does #706 those tests pass, as the L0 verdicts were meant not to change.
  • Merged together with fix/run-wide-credentials, fix/url-extraction-delimited on main b4bcfa4: pytest -n auto 20429 passed, 19 skipped, mypy clean (420 source files), ruff check clean.
  • Not run: the other Python versions (3.11, 3.12, 3.14), a real runner, and gitleaks (the download failed).

Revert

A plain revert restores the old behaviour: an empty path reads as . again, and the tests and the doc sentence go. Nothing is stored.

Checklist

  • Tests added/updated and pytest passes
  • ruff, mypy, and schema checks pass
  • Docs updated (or N/A) — see the docs-drift checklist in CONTRIBUTING.md
  • Self-reviewed per "Before opening a PR" in AGENTS.md
  • No ad-hoc run artifacts committed
  • New files carry the SPDX license header (or are exempt in .github/.licenserc.yaml)

… a leaf usage error

Settles the open mutants of the review of intel#590 (B3.4): the abbreviation check being always true, and `_LeafParser.error` ignoring the flag.

No shipped leaf has `--json` next to another `--js*` option, so the ambiguity is pinned on a probe leaf with `--json` and `--jsonl` (`--jso` is no json request and prints no document), and on `catalog check`, whose `--jsonl` alone must not read as `--json`.

`repo validate` and `repo validate . --cache-dir` without `--json` reach `_LeafParser.error`: stdout stays empty and the message is on stderr with exit 2. The `repo validate . --bogus` case was already pinned.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…ng` and `skill routing`

Settles the open mutant of the review of intel#595 (B1.1b): the `picks_flag` choice of `_conflict_hint_for` when no directory holds just one copy.

Two skills named `review`, one in `review/` and one in `review/review/`, are held by no single directory, so no flag picks either. `catalog routing` says `no --keep-copies-under picks one of its copies` and never names `--against`; `skill routing` says `no --against or --keep-copies-under picks one of its copies`.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…s veto

Settles the open mutants of the review of intel#472 (B4.1): dropping `but`, or `while`, from the clause split of `_negated_before` passed the suite.

"Do not use perf script but perf report --stdin" and "Never guess flags while you run perf report --stdin" are vetoed for `--stdin`, because the negation sits in the clause before the word and does not reach the command after it. Two controls with `or` and `when`, which end no clause, stay negated and pass.

The tests sit in `tests/test_novelty_checks.py`, next to the other veto tests: `tests/test_reference_checks.py` has none for the identifiers check.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…entifiers veto

Settles the open mutants of the review of intel#472 (B4.2): dropping `avoid\w*`, or `without`, from `_NEGATED` passed the suite.

"Avoid perf report --stdin", "Avoiding perf report --stdin is wise" and "Profile it without perf report --stdin" make no claim about `--stdin` and pass. The same sentences with a neutral word ("Try", "Using", "with") are vetoed, so the verdict of each depends on the word alone.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
Settles the open mutants of the review of intel#472 (B4.3): `overruled` comparing with `==`, `decided` not leaving the vetoed runs out, `judge_agreed` comparing with `!=`, and `checked_runs` fixed at 0 passed the suite.

One call over seven runs with known verdicts asserts all six fields: a vetoed run the judge had passed, a run a sufficient check rescued, one it confirmed, one where the verdict and the judge differ but sit on the same side of the lenient collapse, a judge-decided run with checks, and a run with no checks and an errored one, which are left out.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…d inside double quotes

Found by a mutation sweep of `bundle_paths.py`: dropping `;` from `_ESCAPE_RE`, or from `_INNER_ESCAPE_RE`, passed the whole suite.

A missing `assets/a\;b.svg` is named `assets/a;b.svg` whole, both bare (`_ESCAPE_RE`) and in double quotes (`_INNER_ESCAPE_RE`); without the escape the bare one is cut at the shell operator and the quoted one keeps its backslash. The tests sit next to the escaped-comma test.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…d a bare submodule name is unresolved

Settles the review comments on intel#706 about the L0 verdicts of a pinned repository with an undeclared, uninitialised submodule.

On main, a gitlink at `third_party/mod` with no `.gitmodules` and a README claim `mod/` is `unresolved`, as the declared case is: `Scan.submodules` takes every gitlink and the bare-name lookup skips a name that only a submodule matches. `test_a_bare_submodule_name_is_unresolved_like_its_full_path` pins both cases, and breaking the gitlink part of `Scan.submodules` fails `test_a_submodule_without_a_gitmodules_entry_is_still_a_directory`.

The contract now states it: a pinned snapshot's submodules are its `.gitmodules` paths and every gitlink, declared or not, and a bare name that matches only a submodule stays `unresolved`.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…reads `.`

Settles the review comment on intel#637 (`--answers ""` names no path in its error): `Path("")` is `.`, so `eval score reference --answers ""` said `Error: --answers : Is a directory` with nothing after the flag.

`read_json_input` now refuses an empty path first, as an `InputError` that quotes it: `--answers "": no file given`, or `cannot read "": no file given` without a flag. Exit stays 2, and every caller of the shared reader gets the same message. A unit test covers both forms and a CLI test runs `eval score reference --answers ""` through `cli.main`. Changelog fragment (Fixed).

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
@antonwolfy
antonwolfy requested a review from a team as a code owner November 14, 2026 13:48
@exai-bot

exai-bot commented Nov 14, 2026 •

Copy link
Copy Markdown

✅ OpenCodeReview: Review complete: 0 finding(s) across 9 selected item(s).

CI at ee2bfb9: 26 passing, 3 skipped.

Review details
  • Commit reviewed: ee2bfb9 against merge base b4bcfa4
  • Coverage: 9 files in 1 groups
  • Engine: OpenCodeReview v1.13.5-exai.4.8f73eada, us.openai.gpt-6.1-sol
  • Usage: 187k tokens (129k from cache), 31s
  • Tool calls: 29 (21 file_read, 6 code_search, 1 ci_status, 1 local_check_results)
  • Empty JSON input handling and evaluation contract regression coverage: 9 files

@codecov-commenter

codecov-commenter commented Nov 14, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.73%. Comparing base (b4bcfa4) to head (ee2bfb9).
⚠️ Report is 8 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #753      +/-   ##
==========================================
+ Coverage   95.71%   95.73%   +0.01%     
==========================================
  Files         414      415       +1     
  Lines       55310    55365      +55     
  Branches     9509     9517       +8     
==========================================
+ Hits        52941    53003      +62     
+ Misses       1466     1461       -5     
+ Partials      903      901       -2     
Files with missing lines Coverage Δ
dokimi/dokimi/questions/artifact.py 97.58% <100.00%> (ø)
dokimi/dokimi/utils.py 95.03% <100.00%> (+0.02%) ⬆️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

load_questions turned "" into Path('.') before the shared reader saw
it, so --questions "" said 'Is a directory'. The raw value now goes to
read_json_input.

Drops the double-quoted \; case from the path-missing tests: inside
double quotes a backslash before ; is literal in a POSIX shell, so the
test pinned the wrong name.

Signed-off-by: vchamarthi <123653452+vchamarthi@users.noreply.github.com>
@antonwolfy antonwolfy self-assigned this Nov 14, 2026
@vchamarthi

Copy link
Copy Markdown
Contributor

Pushed 1 commit to test/leftovers-2026-11-14 (58c79ee..ee2bfb9).

  • load_questions passes the raw path to read_json_input before Path(path).
  • Removed test_a_missing_escaped_semicolon_inside_double_quotes_is_named_whole.
    Run: the full suite with main merged in, 20463 passed.

Seen in files outside this PR, not changed here:

  • dokimi/dokimi/external/bundle_paths.py:80: _INNER_ESCAPE_RE swaps \; inside double quotes, so cp "assets/a\;b.svg" /tmp/out names assets/a;b.svg; expected assets/a\;b.svg.

The PR description needs these corrections:

  • "tests/test_catalog_path_missing.py: a missing assets/a\;b.svg is named assets/a;b.svg whole, bare and inside double quotes." should read: tests/test_catalog_path_missing.py: a missing assets/a\;b.svg is named assets/a;b.svg whole when bare.

@antonwolfy

Copy link
Copy Markdown
Contributor Author

Pushed 1 commit to test/leftovers-2026-11-14 (58c79ee..ee2bfb9).

@vchamarthi (#753 (comment)): No code change. The description line now reads: "tests/test_catalog_path_missing.py: a missing assets/a\;b.svg is named assets/a;b.svg whole when bare." I also corrected two other lines that ee2bfb9 made untrue: the mutant list no longer claims a test for ; dropped from _INNER_ESCAPE_RE (I ran that mutant on a copy of the head: test_catalog_path_missing.py passes, 90 passed), and Changes/Risk now name the load_questions change.

The bundle_paths.py:80 report holds: _words('cp "assets/a\\;b.svg" /tmp/out') returns assets/a;b.svg, and the same for \, inside double quotes (assets/a,b.svg); a shell keeps the backslash there. It is outside this PR, so it is tracked in #773.

@antonwolfy

Copy link
Copy Markdown
Contributor Author

Ready for another look at ee2bfb9; CI is green.

Follow-up issues opened:

This branch has not been deployed

No deployments
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.

4 participants