diff --git a/AGENTS.md b/AGENTS.md index 7e42ebb..6e4f663 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,7 @@ python -m pytest tests/ -q # unit tests python -m eval.harness --dataset eval/datasets/sample.jsonl --k 5 # retrieval eval gate python -m eval.harness --dataset eval/datasets/codemem.jsonl --k 5 # larger eval; covers conflict resolution python -m eval.ablation # vector-only vs 1-hop vs PPR -ruff check . # lint (line-length 100, py39) +ruff check . # lint (line-length 100, py39, pinned rule set) # ── External benchmarks (real numbers need torch + the dataset; see eval/external.py) ── python -m eval.external --dataset locomo10.json --format locomo --k 10 # LoCoMo diff --git a/pyproject.toml b/pyproject.toml index dbe07a8..66e357d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,13 +126,13 @@ all = [ "onnxruntime<1.24; python_version < '3.11'", "psycopg[binary]>=3.1", ] -dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "ruff>=0.15.22,<0.16"] +dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "ruff>=0.15.22,<0.17"] # Everything needed to run the FULL offline gate in CI (lint + all extras-gated tests) # WITHOUT pulling torch/sentence-transformers — no test needs the real embedder. test = [ "pytest>=8.0", "pytest-asyncio>=0.23", - "ruff>=0.15.22,<0.16", + "ruff>=0.15.22,<0.17", "python-dotenv>=1.0", "uvicorn[standard]>=0.29", "fastapi>=0.133.1,<1; python_version >= '3.10'", @@ -195,6 +195,13 @@ include = ["engraphis*", "scripts*"] line-length = 100 target-version = "py39" +# Pin the rule set explicitly instead of inheriting ruff's built-in default, which is not +# stable across minor releases -- 0.16 widened it from 59 rules to 413 and turned every +# routine linter bump into a repo-wide breakage. These are exactly the 59 rules ruff +# 0.15.x enabled by default, so behaviour is unchanged; widening is now a deliberate edit. +[tool.ruff.lint] +select = ["E4", "E7", "E9", "F"] + [tool.pytest.ini_options] testpaths = ["tests"] addopts = "-q" diff --git a/tests/test_release_infrastructure.py b/tests/test_release_infrastructure.py index a7322c4..7d70abc 100644 --- a/tests/test_release_infrastructure.py +++ b/tests/test_release_infrastructure.py @@ -115,7 +115,12 @@ def test_codeql_workflow_fails_when_sarif_contains_findings(): def test_ci_linter_is_bounded_to_the_verified_release_series(): pyproject = _text("pyproject.toml") - assert pyproject.count('"ruff>=0.15.22,<0.16"') == 2 + # A version bound alone never made the linter deterministic: ruff's *default* rule set + # is not stable across minor releases -- 0.16 widened it from 59 rules to 413, which + # would have turned `ruff check .` red on unchanged code. Pinning `select` explicitly + # is what actually bounds CI, so the bound and the rule set are asserted together. + assert pyproject.count('"ruff>=0.15.22,<0.17"') == 2 + assert 'select = ["E4", "E7", "E9", "F"]' in pyproject def test_release_repair_requires_tag_sha_successful_build_publish_and_pypi_identity():