diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2267ed1..81dd58c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: # tests on main-as-is (verified via a no-op canary PR) — CI was # testing a dependency set production never runs. Bump these pins # together with a production upgrade, not before. - pip install pytest fastmcp httpx requests pynput 'pydantic==2.11.10' 'ruff>=0.15.22,<0.16' \ + pip install pytest fastmcp httpx requests pynput 'pydantic==2.11.10' ruff \ 'fastapi==0.129.0' 'starlette==0.52.1' numpy pyotp 'qrcode[pil]' - name: Lint (ruff) — F-4 gate, config in ruff.toml run: ruff check . diff --git a/requirements-dev.txt b/requirements-dev.txt index b8385ec..ed0f356 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,8 +12,7 @@ # Test + lint toolchain (matches CI) pytest>=9.1.1 -# Upper bound is deliberate: ruff 0.16 changed the default rule selection AND -# stopped honouring this repo's ruff.toml in CI — `ruff check .` went from clean -# to 3117 errors (E402 fired 535 times despite being in our ignore list), with -# no code change. Unpinning again needs a real 0.16 migration, not a drift. -ruff>=0.15.22,<0.16 +# No upper bound needed: ruff.toml now pins `select` explicitly, so a release +# that widens ruff's defaults can't silently change this repo's gate. +# Verified clean on both 0.15.22 and 0.16.0. +ruff>=0.15.22 diff --git a/ruff.toml b/ruff.toml index 3219345..6892bce 100644 --- a/ruff.toml +++ b/ruff.toml @@ -14,7 +14,19 @@ line-length = 120 extend-exclude = ["pilot", "swift-overlay"] # pilot is a separate repo; swift is not Python [lint] -# Ruff's default selection is E4/E7/E9 + F. Keep it; drop the house-style stylistic rules. +# Selection is EXPLICIT, not inherited. Relying on ruff's default `select` broke +# the repo on 2026-07-24: ruff 0.16.0 widened its defaults and `ruff check .` +# went from clean to 3117 errors with no code change — BLE001 x1029, I001 x402, +# UP006 x309, S110, DTZ005, ASYNC230 … none of which this project ever chose. +# Naming the set here means a future ruff release can add whatever defaults it +# likes without silently changing this repo's gate. Widen it deliberately. +select = [ + "E4", # pycodestyle — imports + "E7", # pycodestyle — statements + "E9", # pycodestyle — runtime/syntax errors + "F", # pyflakes — unused imports, undefined names, f-string bugs, redefinitions +] +# Drop the house-style stylistic rules from the selection above. ignore = [ "E402", # module-import-not-at-top — lazy/conditional imports + sys.path setup (intentional) "E701", # multiple-statements-on-one-line (colon) — compact `if x: return`