Reading a codebase in 48 hours

We scope from the code, not from a questionnaire. A client's description of their system is a description of the system they intended. The repository is a record of what actually happened to it, including the parts nobody wants to bring up on a first call.
Two days is enough to price a first sprint with confidence. It is not enough to understand a system, and we do not pretend otherwise. The goal is narrower: find the things that would make an estimate wrong.
It is worth saying what this is not. It is not a code quality review, and we do not deliver a list of things we would have done differently. That document is easy to produce, flattering to write, and useless to a founder who has to decide what to build next month.
What we open, in order
Step five surprises people most often. Time from clone to running application is the most predictive number in the whole audit, because it measures something no document captures: how much undocumented knowledge is required to work on this system. A repository that runs in twenty minutes has been kept honest by someone. One that takes two days and a call with a former contractor will impose that cost on every engineer who touches it, including yours.
Four signals that predict the rest
Test coverage on the revenue path. Not overall coverage, which is a vanity number. If the checkout or the billing logic has tests, someone has been careful where it counts, and changes there will be cheaper than they look.
The inverse is more useful still. An untested revenue path does not mean the code is bad; it means every change to it carries risk that has to be priced. When we widen an estimate, this is usually why, and we would rather explain it on the call than discover it in week two.
Dependency age. A framework two majors behind is not a style issue. It blocks libraries, it blocks hiring, and it eventually blocks security patches. It is often the real first sprint.
There is a threshold effect worth knowing. One major version behind is routine maintenance. Two is a project. Three or more and the documented upgrade path often no longer exists, at which point you are looking at a rewrite of the affected layer rather than an upgrade, and that changes the shape of the whole engagement.
Migration history. A tidy, sequential migration folder means someone owned the data model. A folder with three "fix" migrations undoing each other in the same week means the model was discovered rather than designed, and estimates in that area should widen.
Migrations are also the most reliable record of how a team behaves under pressure, because they are the one artefact that cannot be tidied retrospectively without breaking something. A clean migration history inside a messy codebase is a good sign. The reverse is not.
Deploy frequency. Teams that deploy daily have solved a set of problems that teams deploying monthly have not. It tells you more about how fast the next change can ship than any amount of code reading.
It compounds with everything else. Teams that deploy daily have small changes, fast feedback and a rollback they trust. Teams that deploy monthly batch their changes, which makes each release riskier, which makes them more cautious, which makes releases less frequent. By the time we arrive, deploy frequency has usually already determined how long the first sprint will take, independent of what is in it.
We are not looking for what is wrong with the codebase. We are looking for what would make our estimate wrong.
What we deliberately ignore
Formatting, naming, and the general question of whether we would have built it this way. None of it affects what the next sprint costs, and raising it on a first call is a way of demonstrating cleverness at a client's expense.
We also do not comment on framework choices. That decision was made years ago by someone with context we do not have, and re-litigating it produces nothing except a client who feels defensive about their own product. If the framework is genuinely the constraint, it shows up in the dependency and deploy data and can be raised as a number rather than an opinion.
We also ignore debt in areas the roadmap does not touch. Untidy code in a module nobody is going to change this quarter is not a problem this quarter. It goes in the risk list with a note, not in the sprint.
This is the discipline that keeps a two-day audit honest. Almost any codebase will yield a hundred findings if you go looking. Fewer than ten of them affect what the next sprint costs, and the value of the exercise is entirely in separating those ten from the rest.
What comes out of it
Three things, on one page: what the first sprint contains, the risks that could change the estimate with a rough size on each, and the price.
If the audit turns up something that makes the work a bad idea, that goes on the page too, which has cost us two engagements and saved both clients money.
That conversation is rarely dramatic. It is usually that the work the client asked for is not the work their problem requires, and the sprint they wanted to buy would have shipped successfully without helping. Finding that in two days rather than two months is most of what the audit is for.
The audit is free and it takes two days. The output is yours whether or not you engage us, because a written risk list is useful to you regardless of who does the work.
Several clients have taken the write-up to their own team and done the first sprint internally. That is a fine outcome. The audit costs us two days and it is the most reliable way we have of showing how we think, which is the only thing a scoping call is really assessing.



