Audits
What a build audit actually finds
[PLACEHOLDER COPY] Inheriting a half-finished codebase feels like a legal problem. It is mostly a reading problem. This is the order we read it in, and what the answers tell you.
9MILLSMay 27, 20264 min read
TAKEAWAYS
- An audit answers three questions: what works, what is load-bearing, and what is unknown.
- Commit history tells you more about a project's health than the code does.
- Missing deployment knowledge is a more serious finding than messy code.
- Most inherited builds are worth finishing. Very few are worth finishing as written.
Somebody hands you a repository. The team that wrote it is gone, or unreachable, or reachable but no longer interested. You have paid for it and you do not know what you have. This is one of the most common situations we get called into, and the anxiety attached to it is usually out of proportion to what we end up finding.
An audit is not a code review. Nobody benefits from a list of style complaints about a codebase they already own. What an audit has to produce is a decision: finish this, partly finish this, or start again — with enough evidence attached that you can act on it without taking it on faith.
The order we read it in
We do not start with the code. We start with the evidence around the code, because it is faster to read and it tells you where to look.
- Can it be run at all? A build that will not start on a clean machine is the first finding, and often the largest one.
- Commit history. Rhythm, message quality, and who was actually working reveal more about a project's state than any single file.
- Dependencies and their ages. Abandoned libraries and pinned old runtimes are future work with a due date attached.
- Where secrets and accounts live. Who holds the keys is a business question disguised as a technical one.
- The data model. This is where the real design lives, and where the expensive mistakes are.
- Only then the application code, and only the parts the first five steps flagged.
Reading in that order means that by the time we open the code, we already know which parts of it matter. A messy component in a screen nobody uses is not a finding. A subtle assumption in the billing table is.
What we usually find
A working core, surrounded by unfinished edges
The most common shape by a wide margin. Somebody built the central thing competently, then ran out of time, money, or interest before the surrounding work was done. The signup flow works; the password reset does not. The list view works; nothing paginates. There is a create form for everything and an edit form for nothing. This is good news. Unfinished is much cheaper than wrong.
Deployment knowledge that left with the team
More serious, and more common than people expect. The application runs in production, but nobody remaining knows how it got there. There is a server somebody configured by hand two years ago, a build step that only ever ran on one laptop, and a domain pointed at an account with an unfamiliar email address on it. Nothing is broken until something needs to change, at which point everything is. We treat undocumented infrastructure as a critical finding regardless of how clean the code is.
Security assumptions that only held in development
Authorisation checks in the interface but not in the API behind it. Permissions enforced by hiding a button. Uploaded files readable by anyone who guesses a path. Personal data logged in plain text because it was useful while debugging. These are rarely acts of carelessness — they are usually decisions that were correct while the only user was the developer, and were never revisited.
Nearly every serious finding is a reasonable decision that stopped being reasonable when someone else started using the software.
Tests that describe an older product
A test suite that no longer passes is easy to interpret. A test suite that passes while testing behaviour the product abandoned months ago is worse, because it produces confidence without providing any. We read what the tests assert before we read whether they are green.
What the audit produces
The output is deliberately short, because a long report is a way of avoiding a recommendation. It says what exists and works, what exists and cannot be trusted, what is missing before this can be launched, and what it would take to finish. It says plainly whether finishing is the right call, and it says so even when the answer is that we are not the right people for the work.
- An inventory: every component, and whether it is keepable, fixable, or replaceable.
- A risk list, ordered by what would hurt most if it happened next week.
- The shortest credible path to a launch, with the sequence made explicit.
- The things we could not determine, named as unknowns rather than smoothed over.
That last item matters more than it looks. Every audit has unknowns — a service nobody has credentials for, a data set we were not given, a behaviour that only appears under load we cannot reproduce. An audit that reports no unknowns has not been honest about its own limits, and every estimate built on top of it inherits that dishonesty.
The overwhelming majority of inherited builds are worth finishing. Very few are worth finishing exactly as written. The gap between those two sentences is what the audit measures, and once it is measured it usually turns out to be a matter of weeks rather than the disaster it felt like when the repository first landed in your inbox.
Written by
9MILLS
Published May 27, 2026