5. CI quality gates: pragmatic, then strict¶
- Status: Accepted
- Date: 2026-06-23
Context¶
When CI was introduced, the codebase did not yet pass its own intended gates:
~597 ruff errors, 147 mypy --strict errors, ~49% coverage, and 4 broken tests.
Making every gate blocking immediately would have left CI red and blocked all
work; making none blocking would let quality keep drifting.
Decision¶
Introduce CI green from day one, then ratchet each gate to blocking as the debt was cleared:
- Start:
pytestblocking; ruff / mypy / coverage non-blocking (reported). - Clear the backlog incrementally — fix the broken tests, clean ruff to zero,
fix all
mypy --stricterrors, raise coverage to ≥80%. - Flip each gate to blocking once it passes.
End state — all blocking and green: pytest, coverage ≥80%, ruff,
mypy --strict, lint-imports. pip-audit runs advisory (non-blocking) to
avoid surprise breakage from new advisories. Actions are SHA-pinned with
least-privilege permissions.
Consequences¶
- CI was useful immediately and never blocked progress on pre-existing debt.
- Quality cannot regress below the current bar.
- Adding new rule sets (e.g. ruff
D/PL/C901) is deferred — they would add ~789 errors (mostly docstrings) and belong to a dedicated pass.
Addendum (1.0.0)¶
import-linter and lint-imports were replaced by one dependency walker,
tests/fusion/architecture/test_dependency_rules.py (ADR-0010), which runs with the tests.
mypy is strict on truejoin.domain, truejoin.ports and truejoin.application only
([[tool.mypy.overrides]] in pyproject.toml); CI runs uv run mypy truejoin.