Repository navigation
Conversation
Narrow the JSON-parse handlers to the errors json.loads raises, log the fallbacks in arms_run, mcp_protocol and the persona analyzer, and give every remaining catch-all a noqa reason; tests/test_noqa_reasons.py fails a bare one. Signed-off-by: Petrov, Nikolay A <nikolay.a.petrov@intel.com>
…ators Signed-off-by: Petrov, Nikolay A <nikolay.a.petrov@intel.com>
|
✅ OpenCodeReview: Review complete: 0 finding(s) across 4 selected item(s). CI at Review limit reached. This PR has had 6 reviews, so it will only be reviewed again when you ask. Review details
|
There was a problem hiding this comment.
🟡 Changes recommended
The gate can fail on ignored or generated files while allowing reasonless file-level Ruff and Flake8 suppressions to bypass its explanation requirement.
2 open issues
What changed in this PR
2 new must-fix findings.
This PR tightens exception handling across dokimi’s evaluation framework and supporting tools, making intentional catch-all behavior explicit.
Changes:
- Enables Ruff
BLE001,S110, andS112, adds a suppression-reason test, and documents the policy. - Narrows JSON parsing handlers to expected parse failures.
- Adds logging at previously silent fallback sites and explains retained catch-all handlers.
| File | Description |
|---|---|
dokimi/tests/test_noqa_reasons.py |
Adds suppression-reason checks and regression tests. |
dokimi/scripts/ci_local.py |
Documents the reachability-probe suppression. |
dokimi/pyproject.toml |
Enables the three exception-handling rules. |
dokimi/dokimi/treatments/arms.py |
Adds a reranker-fallback suppression reason. |
dokimi/dokimi/tool_preference.py |
Documents recorded-error handling. |
dokimi/dokimi/repos/l0/workflows.py |
Explains suppression for invalid YAML workflows. |
dokimi/dokimi/repos/l0/versions.py |
Explains suppression for YAML parsing failures. |
dokimi/dokimi/repos/l0/branches.py |
Explains suppression for YAML loading failures. |
dokimi/dokimi/repos/hits_judge.py |
Documents the unjudged-pair fallback. |
dokimi/dokimi/questions/validator.py |
Documents the unscored-question fallback. |
dokimi/dokimi/questions/refiner.py |
Documents gap-fill failure handling. |
dokimi/dokimi/questions/ragas_seed.py |
Documents document-fetch and extraction fallbacks. |
dokimi/dokimi/questions/quality_analyzer.py |
Documents the default-classification fallback. |
dokimi/dokimi/questions/panel_reviewer.py |
Documents error-bearing reviewer votes. |
dokimi/dokimi/questions/llm_gen.py |
Documents isolation of generation failures. |
dokimi/dokimi/questions/chunk_gen.py |
Documents URL and chunk failure handling. |
dokimi/dokimi/personas/analyzer.py |
Logs per-label issue-fetch failures and explains suppressions. |
dokimi/dokimi/novelty/retention.py |
Documents the failed-adjudication fallback. |
dokimi/dokimi/novelty/probes.py |
Documents rewording failure handling. |
dokimi/dokimi/novelty/needs.py |
Documents preservation of partial graphs. |
dokimi/dokimi/novelty/measure.py |
Narrows reply parsing catches and explains error fallbacks. |
dokimi/dokimi/novelty/client.py |
Documents parse-rejection handling. |
dokimi/dokimi/novelty/batching.py |
Documents retry and recorded-error behavior. |
dokimi/dokimi/novelty/atoms.py |
Documents parsing, batching, and verification fallbacks. |
dokimi/dokimi/metrics/example_runner.py |
Explains the execution-error suppression. |
dokimi/dokimi/mcp/url_client.py |
Documents failed connection checks. |
dokimi/dokimi/mcp/okf_client.py |
Documents skipping unreadable files. |
dokimi/dokimi/mcp/mcp_protocol.py |
Logs tool-listing failures and explains probe suppression. |
dokimi/dokimi/mcp/local_markdown.py |
Documents skipping unreadable Markdown files. |
dokimi/dokimi/mcp/context7.py |
Documents failed connection checks. |
dokimi/dokimi/llm.py |
Explains model, pricing, caching, and parsing suppressions. |
dokimi/dokimi/llm_pricing.py |
Documents unknown-price handling. |
dokimi/dokimi/llm_json.py |
Narrows four JSON parsing handlers. |
dokimi/dokimi/judged.py |
Documents cache rejection after parsing failures. |
dokimi/dokimi/harnesses/egress_proxy.py |
Documents tunnel-failure isolation. |
dokimi/dokimi/eval/validity_scoring.py |
Explains per-pair failure suppressions. |
dokimi/dokimi/eval/reranker.py |
Explains the optional dependency import suppression. |
dokimi/dokimi/eval/ragas_eval.py |
Documents optional RAGAS failure handling. |
dokimi/dokimi/eval/panel.py |
Documents failed judge-vote handling. |
dokimi/dokimi/eval/pairwise.py |
Documents per-question failure isolation. |
dokimi/dokimi/eval/cross_judge.py |
Documents exclusion of unscored answers. |
dokimi/dokimi/eval/arms_run.py |
Adds traceback logging before library-ID fallback. |
dokimi/dokimi/eval/answerer.py |
Documents reranker fallback and recorded answer failures. |
dokimi/dokimi/dashboard/aggregator.py |
Documents skipping unreadable snapshots. |
dokimi/dokimi/commands/subjects.py |
Documents per-descriptor error reporting. |
dokimi/dokimi/commands/orchestrate.py |
Documents traceback reporting and failure exit. |
dokimi/dokimi/commands/evaluate.py |
Documents optional RAGAS error reporting. |
dokimi/dokimi/commands/benchmark.py |
Explains validation and batch-failure suppressions. |
dokimi/changelog.d/20261112_230000_napetrov_blind-except-gate.md |
Describes logging and JSON parsing changes. |
AGENTS.md |
Documents the exception-handling and suppression policy. |
Review effort: Balanced
vchamarthi
left a comment
There was a problem hiding this comment.
Reviewed head b4f2479. 2 nits to fix before merge, 3 earlier findings still fail. Details are in the line comments. The gate and the narrowed JSON handlers hold on the head. Two gaps from the open threads still reproduce, and one comment in dokimi/pyproject.toml is out of date.
Verified
- Gate on the head: The six cases in
tests/test_noqa_reasons.pypass on the head. - Gate on main: On main the gate fails on
dokimi/metrics/example_runner.py:240, a bare# noqa: BLE001; the head gives that line a reason. - Json refusals:
extract_json_object('[' * 100000)andparse_json_object('[]')both raiseValueErroron the head. - Extractor dict check: Removing the
isinstance(result, dict)check inextract_json_objectfails 7 cases intests/test_fuzz_targets.py.
Fix before merge:
-
dokimi/pyproject.toml:200: Deferred-rules comment indokimi/pyproject.tomlstill lists BLE001 as not enabled, though the head selects it.Line 200 lists
BLE001 (blind except) 64among the deferred rules with sites to look at, and line 191 says BLE001 is not selected. Line 211 selects it on the head, and the kept sites now carry reasons. Expected: both notes drop BLE001. AGENTS.md says a block of three or more#lines is shortened when a line in it is edited, so the fix has to shorten the block.Also at:
dokimi/pyproject.toml:191.Suggestion: Drop BLE001 from both notes and shorten the block to two lines, as AGENTS.md asks when a block of three or more
#lines is edited.Patch, run on
b4f2479: the quoted text is gone; tests are no worse.Patch
--- a/dokimi/pyproject.toml +++ b/dokimi/pyproject.toml @@ -172,34 +172,8 @@ # The built-in review graders run on the task image's python3 too, 3.8 or newer (contract §4.5). "dokimi/repos/graders/*.py" = "py38" -# A correctness gate: rules that flag code that misbehaves (a swallowed -# KeyboardInterrupt, a naive datetime, a file handle never closed, an assert -# that never runs), not style. A family is taken whole where its rules are of -# that kind and its few style rules are cheap or ignored below; elsewhere the -# rules are listed one by one, so a ruff upgrade cannot add style rules to it. -# A whole family does gain rules with ruff releases (0.16.0 stabilized LOG004 -# and PLE0304, preview-only in 0.12), so ruff is pinned to one version here, in -# requirements-ci.txt (the tools lock CI installs) and in .pre-commit-config.yaml, -# and Renovate bumps all three in one PR that runs the new rules. -# -# Not enabled yet, with their violation counts at ruff 0.17.0. These three are -# autofixes across most files: they land in a PR of their own while few PRs -# are open, and per-file-target-version keeps UP from rewriting the py310 -# files above for 3.11: -# UP (pyupgrade) 1399, of which PEP 585/604 annotations 1185, imports 162 -# I (isort) 156 -# RUF100 (unused noqa) 22: most name rules not selected (BLE001, E402), so -# select those or list them in lint.external first -# Hand fixes deferred because an open PR rewrites the same lines (#29, one -# process runner for the spawn sites): -# PLW1509 (preexec_fn with threads) 1, PLW1510 (subprocess.run without -# check=) 15 -# Bug-prone, each site needs a look: -# PLW2901 (loop variable reassigned) 20, RUF043 (pytest.raises match= with -# unescaped regex characters) 24, ISC004 (implicit concatenation in a -# collection, i.e. a missing comma) 67, BLE001 (blind except) 64, -# PT011 (pytest.raises too broad) 53, RUF012 (mutable class attribute) 8: -# constants and test stubs, but Tool.parameters is also set per instance +# Correctness rules only (a swallowed KeyboardInterrupt, a naive datetime, an unclosed file), so a ruff release cannot add style: a family is taken whole where it is all correctness, else rule by rule. Ruff is pinned in three files, bumped by Renovate in one PR. +# Not enabled, counts at ruff 0.17.0: UP 1399 and I 156 are autofixes for a PR of their own (per-file-target-version keeps py310 files); RUF100 22 (E402 not selected: select it or list it in lint.external first); PLW1509 1 and PLW1510 15 wait on open PR #29; bug-prone, each site needs a look: PLW2901 20, RUF043 24, ISC004 67, PT011 53, RUF012 8 (Tool.parameters is per instance). [tool.ruff.lint] select = [ "F", # pyflakes
Earlier findings:
- still fails: #729 (comment):
# ruff: noqa: BLE001above a handler that silently passes now givesunexplained()==[], expected[1]. - still fails: #729 (comment):
# ruff: noqa: BLE001above a handler that silently passes now givesunexplained()==[], expected[1]. - still fails: #729 (comment):
dokimi/.tox/x/scratch.pywith a bare# noqa: BLE001now gives a gate failure; expected a pass, sinceruff checkskips.tox/.
…-gate Signed-off-by: Petrov, Nikolay A <nikolay.a.petrov@intel.com> # Conflicts: # dokimi/dokimi/novelty/needs.py
ruff reads `# noqa: E722 BLE001 S110` as three codes, but the reason gate split codes on commas only, so a gated code after a space-separated one was never checked and a bare except passed without a reason. Split the code list on commas and whitespace, as ruff does. Signed-off-by: Alexander Rybkin <alexander.rybkin@intel.com>
`# ruff: noqa: BLE001, S110` silences the rules for the whole file, and the reason gate only matched a line-level `# noqa:`, so a file-level directive let every blind except in the file through without a reason. Signed-off-by: Alexander Rybkin <alexander.rybkin@intel.com>
|
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #729 +/- ##
==========================================
+ Coverage 95.71% 95.74% +0.02%
==========================================
Files 415 415
Lines 55346 55368 +22
Branches 9514 9516 +2
==========================================
+ Hits 52977 53013 +36
+ Misses 1466 1453 -13
+ Partials 903 902 -1
🚀 New features to boost your workflow:
|
xaleryb
left a comment
There was a problem hiding this comment.
Re-checked at 391f575 merged with main: a gated code in a space-separated noqa list and a file-level ruff:/flake8: noqa now need a reason (both passed before); the full suite, ruff, mypy, bandit, docs check --strict and the growth check pass, and CI is green. Left as recommendations, not blocking: list files with git ls-files so trees ruff skips (.tox/) are not scanned, and drop BLE001 from lint.external when merging main.
antonwolfy
left a comment
There was a problem hiding this comment.
Review at 391f575. The gate and the narrowed JSON handlers hold up, and the noqa reasons I sampled match their handler bodies. One reason rewrite changes coverage behaviour; the other inline comments are nits.
What I ran, on a Linux review host at 391f575:
make ci-local: 35 passed, 2 failed, 14 skipped. Changed-line coverage passes. The suite ran 19758 passed, 19 skipped, 2 errors. Both errors are 60 s timeouts intest_audit_test_quality.py, a file the PR does not touch, and it passes alone (172 passed in 6 s). Thepre-commitfailure ischeck-added-large-filesondokimi/docs/reference/cli-interface.json(501 KB over the 500 KB limit), which the PR does not touch.- Reproductions with the LLM transport mocked, and mutation runs on the narrowed handlers: with
RecursionErrordropped from the fourllm_json.pyclauses, or_reply_verdictcatchingKeyErrorinstead ofValueError, or the three new log lines deleted, the related tests (238 and 90 cases) still pass. - Commits: all four non-merge commits carry a
Signed-off-by.
I agree with @vchamarthi's points on the RecursionError clauses in llm_json.py (no test fails without them) and on the stale deferred-rules comment in pyproject.toml, which still lists BLE001 as not enabled. New evidence: the same mutation on _reply_verdict, except KeyError:, also passes 90 related tests.
@xaleryb's point that trees ruff skips (.tox/) are still scanned waits for the author.
Checked, no issues
- Narrowed handlers: for
strinputjson.loadsraises onlyValueErrororRecursionError, so(ValueError, RecursionError)loses nothing; the base code behaves the same for a bad{...}block. noqareasons: about 40 reasons compared with their handler bodies across cli, eval, mcp, novelty, questions, repos and treatments; the only mismatch is the pragma below.- Gate:
test_noqa_reasons.pyruns in about 3 s offline and covers comma and space-separated code lists,NOQAin upper case, andruff:/flake8:file-level forms.
Bot points I checked that no longer apply at this head (2)
- Copilot's point on file-level
# ruff: noqaand# flake8: noqadirectives does not apply at this head:391f5755matches both prefixes and the new test pins bare and explained forms. - exai-bot's point on the file-level
# ruff: noqa: BLE001, S110, S112directive does not apply at this head: the gate now flags it without a reason.
…blind-except-gate Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com> # Conflicts: # dokimi/dokimi/llm.py # dokimi/dokimi/llm_pricing.py
A reply with no prose before its nesting reaches the direct json.loads parse. Dropping RecursionError from that clause left all 58 fuzz cases green. Thread: PRRT_kwDOVBg7g863UN0k Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Each new logger call (arms resolver, MCP tool listing, persona label fetch) gets a caplog test; deleting the call fails the test. Thread: PRRT_kwDOVBg7g863fUNI Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The reason on the reranker handler swallowed "pragma: no cover", so the line left coverage's exclusion. The pragma now comes first, the noqa reason after. The noqa gate lists the files git tracks or does not ignore, as ruff does, so mutants/, .tox/ and dist/ copies no longer fail it. Thread: PRRT_kwDOVBg7g863fUND Thread: PRRT_kwDOVBg7g863S32b Thread: PRRT_kwDOVBg7g863fUNL Thread: IC_kwDOVBg7g88AAAABmcksyQ Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The deferred-rules comment still listed BLE001 as not enabled, and lint.external hid stale BLE001 noqa comments from RUF100. Thread: PRR_kwDOVBg7g88AAAABX5yHKQ#1 Thread: IC_kwDOVBg7g88AAAABmcksyQ Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
… tree git ls-files --cached lists a file staged and then deleted on disk, and reading it raised FileNotFoundError in a local run. Thread: PRRT_kwDOVBg7g863fUNL Thread: PRRT_kwDOVBg7g863S32b Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
|
|
|
Thread: PRRT_kwDOVBg7g863iWL2 Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
antonwolfy
left a comment
There was a problem hiding this comment.
LGTM. Review at 2a6b122. The gate now lists files the way ruff does, the pragma ordering on the reranker handler is fixed, the new log calls and the direct-parse RecursionError clause are pinned by tests, and the stale BLE001 notes are gone. Two nits inline.
What I ran, on a Linux review host at 2a6b122:
make ci-local: 38 passed, 0 failed, 14 skipped. Changed-line coverage passes. The skips are the other Python legs, micromamba, fuzz and semgrep.ruff checkoverdokimi/dokimi,dokimi/testsanddokimi/scriptswith the project config: clean.- Mutation runs on the narrowed handlers and the new log calls, 1942 related tests per mutant: the direct-parse
RecursionErrorclauses,_reply_verdictcatchingKeyError, each deleted log call and each droppedexc_infoare all caught now. Both markdown-fence clauses inllm_json.pysurvive (inline). - Mutation runs on the gate (13 mutants): dropping the pragma strip,
.tox/,is_file(),--others,--exclude-standardor the word-count threshold fails a test. - Commits: every non-merge commit carries a
Signed-off-by.
Checked, no issues
- Pragma order:
# pragma: no cover # noqa: BLE001 - env dependentattreatments/arms.py:70is accepted by ruff and still matches coverage.py's default exclusion pattern. No other touched line carries a displacedtype: ignore,nosecor pragma. - Gate file list: in a fresh
git init, an ignoredmutants/, a.tox/copy and a file staged then deleted on disk are all skipped, and tracked files are listed. - Narrowed handlers: for
strinputjson.loadsraises onlyValueErrororRecursionError, andparse_json_objectraises onlyValueError, so nothing the base code swallowed escapes now. - Config:
BLE001is out ofexternal, and the comment block is two lines, as AGENTS.md asks.
Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
antonwolfy
left a comment
There was a problem hiding this comment.
LGTM. I pushed a commit per nit, up to 48dfc28, which fix the two nits from my review:
dbcb55a:dokimi/tests/test_fuzz_targets.py:77: the test is parametrized over a bare and a fenced deep reply, and narrowing either fence clause inllm_json.pytoexcept ValueErrornow fails it.48dfc28:dokimi/dokimi/mcp/okf_client.py:146: the noqa reason says "logged at debug", and so domcp/local_markdown.py:91andmcp/url_client.py:128.
make ci-local at 48dfc28: 38 passed, 0 failed, 14 skipped.

Enable ruff
BLE001,S110andS112, so a newexcept Exceptionthat neither re-raises nor logs its traceback fails lint, as does anexceptwhose body is onlypass/continue.Changes
llm_json.py(4 sites) now catches(ValueError, RecursionError), the errorsjson.loadsraises, instead ofException: pass.novelty/measure.pycatchesValueErrorfromparse_json_object. A bug in these helpers is no longer read as "no JSON here".eval/arms_run.py: an unresolved library id logs a warning with its traceback before the arm falls back to the product name.mcp/mcp_protocol.py: a failed tool listing is logged withlogger.exception.personas/analyzer.py: a failed issue fetch per label is logged.# noqa: BLE001 - <what happens to the failure>. Examples: logged and skipped, stored on the row, re-asked, a connection check answers False.tests/test_noqa_reasons.py: ruff accepts a bare# noqa: BLE001, so this test fails a noqa for those three codes that has no reason of at least two words.AGENTS.md: the rule. Changelog fragment added.Notes
pyproject.tomlno longer lists BLE001: the block is two lines now (AGENTS.md), and BLE001 is out oflint.external.# noqastill silences everything, and neither ruff nor this test catches it. EnablingPGH004would close that. It may flag other lines, so it is not done here.Testing
ruff checkis clean over the tree, andtests/test_noqa_reasons.pypasses (6 tests).pyteston Windows, on main and on this branch:test_catalog_discovered_task_runs_through_tasks_cli_dry_run, which hit WinError 206 (path too long) because the worktree path is longer; it passes on main.resource,os.getgid,SIGKILL), all in files this PR does not touch. Linux CI is the authority for both.🤖 Generated with Claude Code