Pre-push CI gate for Python — ruff format can introduce mypy errors
Two CI bounces on R-Dash PR #45 exposed a 3-tool pre-push checklist that, run in order, catches what each single tool misses:
uv run ruff format --check .— catches line-length / wrap drift thatruff checkaccepts as lint-clean.uv run ruff check .— catches F401 unused imports, undefined names, etc.uv run mypy <changed-files>— catches type-narrowing regressions.
Critical caveat: when ruff format simplifies code shape (e.g. lhs: bytes = foo.private_bytes(...); return lhs collapses to return foo.private_bytes(...)), the type-narrowing assignment is dropped and mypy may report “Returning Any from function declared to return bytes”. Always re-run mypy on files reformatted by ruff format — never assume format-only changes are type-safe.
Cost when skipped: 2 CI bounces (~3 min each) before the trio passed in correct order.
Automation candidate: a .git/hooks/pre-push running the trio in order with non-zero exit on any failure catches both classes in 0 round-trips.
Reference: r-dash main commits 521d4d6 (ruff format) and f95a6ef (mypy bytes annotation fix); failed GHA runs 25967982404 and b98b86e CI.
Related
- pr-45-wave-17-fully-landed-on-main-via-squash-merge-b98b86e
- contract-test-specs-must-probe-live-api-shape-before-encodin
- adversarial-parallel-multi-agent-audit-before-any-complete-c
- aws-mcp-v400-signed-2026-05-08-bible-v19110-r50-cascade-live
- aws-mcp-v400-bible-v19110-upgrade-registry-dispatch-architec