Orchestrata Ultimate › Gates › ruff
Gate: ruff
At a glance
| Purpose | Refuse a ruff lint violation in src/, tests/ or scripts/ under [tool.ruff] in pyproject.toml. |
| Where it runs | The scripts/gates.py battery (registered as ruff); CI's lint job (uv run ruff check src/ tests/, .gitlab-ci.yml); deploy/ship.sh verify stage (uv run ruff check src/ tests/ scripts/ claude/); per file inside the commit review (code-review.py's RuffChecker, run by scripts/gate.py review-staged); the pre-commit auto-fix step (ruff check --fix, never blocks). |
| Trigger | A battery run; a CI pipeline; a ship; every git commit that stages .py files. |
| Exact command | Battery argv: uv run ruff check src/ tests/ scripts/ |
| Blocks | ruff's own exit code: non-zero on violations, 0 clean. Inside the commit review a ruff finding at ERROR blocks the commit (commit_review.pl: code review blocks at ERROR). |
| Ruling / ADR | None names this gate directly. The commit-review layer is RUL-008; ruff run as <interpreter> -m ruff comes from ADR-0089. |
| Last recorded verdict | ok: true in the primary checkout's .cache/gates.json (file last written 2026-09-22 10:01 local). wt-MAP-PRECOMMIT has no .cache/gates.json. |
What it refuses
A ruff lint violation anywhere in src/, tests/, or scripts/ under the
[tool.ruff] configuration in pyproject.toml.
Why it exists
Ruff is the standard linter (CLAUDE.md commands: uv run ruff check src/ tests/);
its presence in the battery needs no incident. What is recorded is why the battery
pairs it with an autoformat pass (scripts/gates.py docstring, self-healing
behavior):
"lint:
ruff --fix+blackrun BEFORE the gates. The user-level autoformat hook only fires on Write/Edit tool calls, so any file written by a script (heredoc, codemod, generator) skipped it and failed the lint gate later."
So the battery's autoformat() runs
uv run ruff check --fix -q src/ tests/ scripts/ and uv run black -q src/ tests/ scripts/ first (skippable with --no-fix), and the gate then verifies what
remains.
How it runs
- Command (battery argv):
uv run ruff check src/ tests/ scripts/ - When it fires: the
scripts/gates.pybattery (registered asruff); the same check is CI's lint job and part of the everyday dev loop. - Inputs: fingerprint roots
_SRC = ("src", "scripts", "tests", "pyproject.toml")— pyproject carries the[tool.ruff]select/ignore config, so a rule toggled off re-runs the gate. - Caching: the verdict is cached in
.cache/gates.jsonagainst_fingerprint(roots): a sha256 over the relative path and bytes of every file under those roots whose suffix is.py,.toml,.pl,.json,.mdor.sh(_interesting(), read through the AST toolkit on 2026-10-23). There is no per-gate suffix mask: this page previously quoted aGATE_MASKScomment, andgit log --all -S GATE_MASKS -- scripts/gates.pyfinds no commit that ever contained one. A.pyistub change therefore does not invalidate the cached verdict (derived from the code, not measured).
The two commit-time ruff layers
- Auto-fix, never blocking.
scripts/hooks/pre-commitrunsruff check --fixon each staged.pyfile and re-stages it (|| true: a ruff failure here never blocks). Onorigin/master(a4cbc2bdf) the line is a plainuv run ruff check --fix "$FILE"(line 166). Commit8a2cb42ad(2026-10-23, branchfeat/maps-via-codetools, not pushed) changes it touv run --no-sync ruff check --fix. - The blocking check.
scripts/gate.py review-stagedrunscode-review.py, whoseRuffCheckercalls<interpreter> -m ruff check --exit-zero --output-format=concise <file>with a 30 s timeout (read through the AST toolkit). It reportsRUFF_NOT_FOUND(no ruff module for that interpreter),RUFF_CHECK_ERROR(non-zero exit with no parseable output) andRUFF_TIMEOUT, all at ERROR, so a review in which ruff never ran cannot look clean.
Typical failures and how to fix them
- Exit code: ruff's own — non-zero on violations, 0 clean.
- What a PASS looks like (real recorded battery output,
.cache/gates.json):0.1s | All checks passed! - What a failure looks like (representative): standard ruff findings —
path:line:col CODE message— for whatever survived the auto-fix pass. - Un-blocking: most cases fix themselves on the next battery run (the
--fix+black pass); the rest are real findings to fix by hand. Rule-level configuration changes belong inpyproject.toml, where they also invalidate the prolog-gate cache (itstool_rule_statusfacts read the same tables). RUFF_NOT_FOUNDin the commit review. The interpreter running the reviewers has no ruff. The pre-commit hook's comment records the earlier form of this: "a PATH without it made code-review.py report RUFF_NOT_FOUND as its only ERROR". Fix: run from the checkout's own.venv(the hook and~/bin/precommit-checkboth put.venv/binfirst on PATH).- Trap: a plain
uv runre-syncs the venv editable. The battery's argv isuv run ruff ...without--no-sync. Memoryuv-run-flips-venv-editable(measured 2026-10-22) records that a plainuv runin an orchestrata checkout re-syncs the project venv as an editable install, after which the pre-push source-provenance gate refuses every push..envrcline 47 exportsUV_NO_EDITABLE=1, which only a direnv shell gets; hooks and direnv-less worktrees do not. Whether the battery'suv run ruffflips the venv was not measured. If.venv/.../orchestrata_ultimate-*.dist-info/direct_url.jsonshows"editable": true, re-sync withenv -u PYTHONPATH -u PYTEST_ADDOPTS uv sync --dev --no-editable --frozenbefore pushing.
Wiring
- Invokers:
scripts/gates.py(battery), CI's lint job,deploy/ship.sh(verify stage),code-review.pyviagate.py review-staged(commit),uv run ruff checkin the dev loop. - Tests: exercised through the battery's own tests
(
tests/scripts/test_gates.py,test_gates_coverage.py) — ruff itself is an external tool, not project code.
Related
- Gates master index
- Development workflow
- review-staged — the commit review that runs ruff per file
- commit-precheck — the same review without committing
- ship-verify — ship's ruff and black checks
- ci-pipeline — CI's lint job
- source-provenance — the gate an editable venv trips
- mypy — the other imported-tool gate, with its own false-green history
- prolog-gate — reads the ruff select/ignore lists as facts
- RUL-008 — Review before every commit
- ADR-0089 — bare toolchain names fail the gate