--- title: "feat: Activate pre-commit hooks (black, ruff, isort)" type: feat status: active date: 2026-04-24 --- # Activate Pre-commit Hooks ## Overview `.pre-commit-config.yaml` exists but is explicitly disabled ("intentionally minimal and does not enable hooks by installing them"). Activating black, ruff, and isort would enforce CODE_STYLE.md conventions automatically and eliminate style-only review comments. ## Problem Frame - Code style is documented in CODE_STYLE.md but not enforced automatically - Contributors may submit PRs with inconsistent formatting - Review time is spent on style nits instead of logic - No CI check for formatting violations ## Requirements Trace - R1. Pre-commit hooks run black, ruff, and isort - R2. Hooks are enforced in CI (fail build on violations) - R3. Hooks use the same versions as pyproject.toml dev dependencies - R4. Initial run reformats existing code without breaking tests ## Scope Boundaries **Included:** - Update `.pre-commit-config.yaml` - Add CI workflow step for pre-commit - Run initial format across codebase **Excluded:** - Adding new linters or rules - Changing CODE_STYLE.md conventions - Fixing logic bugs found by ruff (separate PR) ## Key Technical Decisions - **Use pre-commit.ci or GitHub Action** — pre-commit.ci is zero-config but may not work on Gitea. Use a GitHub Actions step as fallback. - **Single large format commit** — Run once, commit formatting changes separately from config changes so reviewers can see the diff. - **Skip tests during format** — Formatting should not change behavior, but run tests after to verify. ## Implementation Units - [ ] U1. **Update .pre-commit-config.yaml** **Goal:** Enable black, ruff, and isort with versions matching pyproject.toml. **Requirements:** R1, R3 **Dependencies:** None **Files:** - Modify: `.pre-commit-config.yaml` **Approach:** - Remove the "does not enable hooks" comment - Add repos for black, ruff, isort with pinned versions - Set ruff to match CODE_STYLE.md rules - Configure isort profile (black-compatible) **Test scenarios:** - Happy path: `pre-commit run --all-files` completes successfully - Error path: A file with style violations fails the hook - Integration: Versions match pyproject.toml dev deps **Verification:** - `pre-commit run --all-files` runs without config errors --- - [ ] U2. **Add pre-commit CI step** **Goal:** Block PRs that violate formatting rules. **Requirements:** R2 **Dependencies:** U1 **Files:** - Modify: `.github/workflows/pytest.yml` (or create separate lint.yml) **Approach:** - Add a job that runs `pre-commit run --all-files` - Use the same uv setup as the pytest workflow - Install pre-commit via uv **Test scenarios:** - Happy path: Clean code passes pre-commit CI - Error path: Violations fail the CI job **Verification:** - Pushing a formatting violation fails the check - Pushing clean code passes --- - [ ] U3. **Run initial format across codebase** **Goal:** Bring all existing code into compliance so future PRs only touch their own changes. **Requirements:** R4 **Dependencies:** U1 **Files:** - Modify: All Python files (mechanical reformatting) **Approach:** - Run `pre-commit run --all-files` - Commit formatting changes separately - Run full test suite: `uv run pytest tests/ -q` **Execution note:** This is a mechanical change. Characterization tests should pass unchanged. If tests fail, the formatter broke something — investigate before committing. **Test scenarios:** - Integration: All existing tests pass after formatting - Edge case: No logic changes introduced by formatting **Verification:** - `uv run pytest tests/ -q` passes - `git diff` shows only whitespace/import changes --- ## Risks & Dependencies | Risk | Mitigation | |------|------------| | Massive format commit obscures git blame | Use `.git-blame-ignore-revs` to ignore the format commit | | Ruff finds existing logic issues | Fix or suppress in separate PR; don't mix with activation | | Contributors without pre-commit installed | CI catches it; add setup note to README | ## Documentation / Operational Notes - Add pre-commit setup to README quickstart - Document `.git-blame-ignore-revs` usage ## Sources & References - Config: `.pre-commit-config.yaml` - Style guide: `CODE_STYLE.md` - Dependencies: `pyproject.toml`