The solution
At Ramp, a monorepo of machine learning workflows had grown from a convenient shared space into what the team called 'a bit of a swamp': a requirements.txt with unpinned transitive dependencies that drifted between machines, inconsistent formatting, no automated tests, and type annotations that were either missing or subtly wrong. Engineers grew wary of touching the code for fear of breaking something, and velocity, the original goal, had slowed to a crawl.
Rather than rewrite the repository, the team adopted four tools in place: poetry for locked, reproducible dependencies; ruff for formatting and linting; pytest for testing high-leverage shared utilities rather than chasing full coverage; and mypy for gradual type checking. The trick that made adoption possible on a live codebase was not fixing everything first. They ran an auto-formatter once across the whole repo in a single commit, then added that commit's hash to .git-blame-ignore-revs so it wouldn't pollute blame history.
For linting and typing, instead of fixing hundreds of pre-existing errors before turning on CI, they machine-generated '# noqa' and '# type: ignore' comments for every existing violation, then enabled hard enforcement for anything new. Ruff's 'RUF100' rule and mypy's 'warn_unused_ignores' flagged any suppression comment that went stale once the underlying code was actually fixed, so the ignore list could only shrink, never silently rot.
The result was a codebase that was never 'clean' by fiat but became enforced going forward from day one, with the debt shrinking as developers naturally touched old files.
What it achieved
Grandfather old violations, enforce only new code
Why it worked
A full rewrite or big-bang cleanup would consume weeks before any enforcement could start, so the team enforced going forward instead of retroactively.
Machine-generating the initial suppression comments turned an unbounded manual cleanup into a one-time, automatable step.
Flagging unused suppression comments meant debt could only decrease, since fixing an old violation surfaced a now-pointless ignore comment CI would catch.
Squashing the reformat into one commit and excluding it from git blame preserved the ability to see who last touched a line for a real reason.
What can be applied
You don't need a clean codebase before enforcing standards on it. Silence every existing violation once, enforce strictly on new code only, and the backlog shrinks as people touch old files anyway.
Aftermath
The team reported the codebase reached a state where quality was maintained going forward: poetry's lock file gave consistent environments across developer machines and CI, ruff caught real bugs like duplicate dictionary keys before merge, and mypy caught signature-change regressions across call sites that unit tests didn't cover. The post frames the goal as restored confidence to make sweeping changes, not the tooling itself, and notes the team was still looking at shifting more of this burden from contributors to tooling.
FOLLOW THE EVIDENCE
The sources
- Increasing velocity by modernizing a Python codebase builders.ramp.com