Skip to content

chore: fix ruff lint findings, restore green CI lint gate - #18

Merged
man4ish merged 1 commit into
mainfrom
chore/fix-ruff-lint-findings
Sep 1, 2026
Merged

chore: fix ruff lint findings, restore green CI lint gate#18
man4ish merged 1 commit into
mainfrom
chore/fix-ruff-lint-findings

Conversation

@man4ish

@man4ish man4ish commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

What

ruff check . (CI's "Lint & Test" job) has been failing on main across the last several merged PRs — 161 pre-existing findings, entirely unrelated to any of the recent security/config/docs work. This restores a green, meaningful lint gate.

Before / after

Findings
Before 161
After 0ruff check .All checks passed!

Findings by rule code (before)

Code Count Category
UP006 52 List/Dict/Set/Tuple → builtin generics
I001 30 import sorting
BLE001 17 blind except Exception
UP035 15 deprecated typing imports
F401 11 unused imports
RUF010 8 unnecessary str() in f-string
RUF013 8 implicit Optional (x: str = None)
SIM117 5 nested with statements
UP045 4 Optional[X]X | None
F841 4 unused local variable
SIM102 1 collapsible if
UP007 1 Union[X, Y]X | Y
SIM118 1 key in dict.keys()key in dict
TRY004 1 wrong exception type for a type check
E722 1 bare except:
S112 1 try/except/continue with no logging
EXE001 1 shebang present but file not executable

What was auto-fixed vs. manually fixed vs. noqa'd

Auto-fixed by ruff check . --fix (safe fixes only) — 121 findings, zero behavior change:
UP006, I001, UP035, F401, RUF010, UP045, UP007 — all pure import reordering / typing modernization (Listlist, Optional[X]X | None, dropping now-unused imports, f"{str(e)}"f"{e!s}").

Manually fixed (real, minor issues) — 15 findings:

  • RUF013 (8, 4 call sites): param: str = Noneparam: str | None = None in index/vector_store.py and rag/engine.py.
  • SIM117 (5): nested with statements in tests collapsed into one parenthesized with (...) — same context managers, purely mechanical.
  • SIM102 (1): collapsed a nested if in api/main.py's guard_requests middleware into one condition.
  • SIM118 (1): for node in self.edges.keys()for node in self.edges in index/graph_store.py.
  • E722 + S112 (1 site, rag/query_router.py): a bare except: continue around a per-line JSON parse was narrowed to the actual exception types (JSONDecodeError/UnicodeDecodeError/AttributeError/KeyError) and now prints before continuing, so a parse failure is no longer silently swallowed.
  • TRY004 (1): RAGEngine._embed()'s type check now raises TypeError instead of ValueError (the correct exception for a type-validation failure) — updated the one test asserting on it (test_engine_embed_invalid_type) to match.
  • EXE001 (1): scripts/run_eval.py had a shebang but wasn't executable; chmod +x to match, consistent with scripts/check_and_reindex.sh.
  • F841 (4): four tests bound a mock to a name (mock_file, mock_pload, mock_retrieve ×2) and never asserted on it. Rather than delete the unused variable, added the assertion the surrounding test was clearly missing — each now verifies the mocked call actually happened, matching the pattern already used by sibling assertions in the same tests (e.g. mock_mkdirs.assert_called_once_with(...) right next to it).

Scoped # noqa: BLE001 — 17 sites, each with an inline reason, no blanket ignore:
Every one of these is except Exception at a deliberate error-isolation boundary — converting an arbitrary failure into a safe fallback (empty list, inline error string/token, HTTP 500, skip-and-continue) so one bad chunk/tool-step/subsystem/request doesn't crash a larger operation:

  • api/routes/rag.py (3): engine-access wrapper, top-level /rag/query HTTP handler, SSE stream generator
  • ingestion/doc_loader.py (1): per-file read during the indexing walk
  • rag/engine.py (3): optional CrossEncoder load, LLM call, LLM streaming
  • rag/query_router.py (4): per-source search (vector/graph/plugin) + streaming
  • rag/tool_executor.py (4): per-step dispatch + per-tool search (vector/graph/plugin)
  • scripts/build_index.py (1): per-chunk embed during batch indexing
  • scripts/run_eval.py (1): per-query eval

Narrowing any of these to specific exception types would risk missing the failure modes the boundary exists to catch, defeating its purpose — that's why they're noqa'd with a reason rather than "fixed."

Verification

$ ruff check .
All checks passed!

$ pytest -q
199 passed in 0.5s

Confirmed 199 passed — same count as before this change — so none of the auto-fixes (import reordering, typing syntax) or manual fixes altered behavior.

CI

This should turn .github/workflows/ci.yml's "Lint & Test" job green again for the first time in several merges.


⚠️ Not merging automatically per instructions — this diff touches 29 files (mostly mechanical, but worth a look given the volume). Waiting for review/confirmation before merge.


🤖 Generated with Claude Code

ruff check . had 161 pre-existing findings on main, unrelated to any
recent work, that had been failing CI's "Lint & Test" job across the
last several merges. Fixes all of them so the lint gate is meaningful
again.

Before/after: 161 -> 0.

Auto-fixed via `ruff check . --fix` (safe fixes only) -- 121 findings,
no behavior change, import reordering and typing modernization only:
- UP006 (52): `List`/`Dict`/`Set`/`Tuple` -> builtin generics (`list`/`dict`/...)
- I001 (30): import block sorting
- UP035 (15): drop deprecated `typing` imports made redundant by UP006
- F401 (11): unused imports
- RUF010 (8): `f"{str(e)}"` -> `f"{e!s}"`
- UP045 (4): `Optional[X]` -> `X | None`
- UP007 (1): `Union[X, Y]` -> `X | Y`

Manually fixed (real, minor issues) -- 15 findings:
- RUF013 (8, 4 sites): implicit-Optional params (`x: str = None`) made
  explicit (`x: str | None = None`) in index/vector_store.py and
  rag/engine.py
- SIM117 (5): nested `with` statements in tests collapsed into one
  parenthesized `with (...)` -- purely mechanical, same context
  managers
- SIM102 (1): collapsed a nested `if` into one condition in
  api/main.py's guard_requests middleware
- SIM118 (1): `for node in self.edges.keys()` -> `for node in
  self.edges` in index/graph_store.py
- E722 + S112 (1 site, rag/query_router.py): bare `except: continue`
  around a per-line JSON parse narrowed to the actual exception types
  (JSONDecodeError/UnicodeDecodeError/AttributeError/KeyError) and
  given a print so a parse failure is no longer silently swallowed
- TRY004 (1): `_embed()`'s type-check now raises `TypeError` instead
  of `ValueError` (the right exception for a type check) -- updated
  the one test asserting on it to match
- EXE001 (1): `scripts/run_eval.py` has a shebang but wasn't
  executable; chmod +x to match, consistent with the other script
  in scripts/
- F841 (4): unused mock variables in tests -- rather than delete them,
  added the assertions their surrounding tests were clearly missing
  (`mock_file`/`mock_pload`/`mock_retrieve` were bound but never
  checked; asserting on them now actually verifies the mocked call
  happened, matching the pattern already used by sibling assertions
  in the same tests)

Scoped `# noqa: BLE001` (17 sites, each with an inline reason) for
`except Exception` at deliberate error-isolation boundaries -- these
convert an arbitrary failure into a safe fallback (empty list, inline
error string/token, HTTP 500, skip-and-continue) so one bad chunk/tool
step/subsystem/request doesn't crash a larger operation. Narrowing
these to specific exception types would risk missing failure modes
these boundaries exist to catch, defeating their purpose. Sites:
api/routes/rag.py (3), ingestion/doc_loader.py (1), rag/engine.py (3),
rag/query_router.py (4), rag/tool_executor.py (4),
scripts/build_index.py (1), scripts/run_eval.py (1).

Verified: `ruff check .` -> "All checks passed!" (zero findings) and
`pytest -q` -> 199 passed, both after the full set of changes above.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XaLTXgv4NNGzg2snnnYRZV
@man4ish
man4ish merged commit 0c02625 into main Sep 1, 2026
3 checks passed
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.

1 participant