When we take over an existing product, we don’t write code in the first week. The first two weeks of every engagement are an audit and triage: a full review of the codebase, infrastructure, deploy pipeline, and dependencies, ending in a written picture of where things stand. No sugarcoating, and no ninety-day plan full of rewrites either.
Owners are often nervous about this step. They expect the audit to be a verdict on decisions they made under pressure years ago, or a sales document engineered to justify a big rebuild. We treat it as a map, nothing more. And after enough of these engagements, we can tell you the map usually shows the same terrain. Here’s what week one turns up, over and over, and what each finding means for the roadmap that follows.
A note on method, because it changed recently: most of the mechanical work in this audit is now done with Claude Code and a library of custom skills we’ve built for it. Dependency sweeps, dead-code detection, schema drift, coverage mapping - the parts that used to take a developer a week of grepping now take a morning. The findings below still take a human to interpret; that’s now most of the week.
The findings that appear almost every time
Outdated everything, with known vulnerabilities. The single most common finding: a Ruby version at or past end-of-life, a Rails version two or more majors behind, and a Gemfile.lock full of dependencies with published CVEs. Tools like bundler-audit and brakeman make this the fastest part of the audit to run and the easiest to score by severity. It matters because it’s silent; the app runs identically the day before and the day after an exploit for your gem version is published.
Deploys that depend on one person, or one laptop. We ask a simple question early: “If your current developer disappeared today, could anyone deploy tomorrow?” The answer is usually no. Deploy steps live in someone’s shell history, credentials live in someone’s password manager, and there’s no CI pipeline that could rebuild the process from the repository alone. This finding jumps straight to the top of every roadmap we write, because it caps how bad every other problem can get.
Little or no automated testing around the money paths. Coverage is often near zero, and where tests exist they skip the flows that matter most: checkout, signup, billing, permissions. Nobody can change those areas confidently, so nobody changes them, so improvements stall exactly where they’re worth the most. We target 80-90% coverage on apps we run long-term, but week one just establishes the number and flags the riskiest gaps.
Database performance debt. Missing indexes on columns the app filters by constantly, N+1 queries on the highest-traffic pages, and a few endpoints doing work in the request cycle that belongs in a background job. This category is a gift, honestly: these fixes are small, safe, and visibly speed up the product, which makes them ideal for the early-wins phase in weeks three and four.
Secrets in the repository. API keys, database passwords, and third-party tokens committed to git history, where every past contractor’s laptop still has a copy. Rotating exposed credentials is cheap and unambiguous, so it happens immediately rather than waiting for the roadmap.
A single point of failure nobody chose on purpose. One database server with unverified backups, one cron box that quietly runs the business, one production server that predates everyone’s memory. The pattern was never selected; it accreted. Week one’s job is just to name it, with a severity and a cost to fix, so the owner can decide with open eyes.
What we’re actually producing
The deliverable at the end of the audit has three parts, and they map directly onto how our first month runs:
- A severity-ranked findings list. Security exposure and single points of failure first, performance and maintainability after. Each finding carries a plain-language explanation of the risk. If a finding can’t be explained to a non-technical owner, we haven’t understood it yet.
- A pragmatic roadmap. Stability first, then velocity. We tell you what needs to happen now, what can wait, and what genuinely doesn’t matter. Some findings stay on the “accepted risk” list forever, and that’s a fine outcome when it’s chosen deliberately.
- An early-wins queue. The audit always surfaces a handful of fixes with outsized payoff: the slow page everyone tolerates, the intermittent error nobody could reproduce, the report that takes a person a day and should take a query. Weeks three and four go here, so results show up before the first invoice is due.
What the findings don’t mean
An ugly audit is not evidence that your app needs a rewrite, and we say this as the people who would get paid for one. Nearly everything on the list above is repairable in place, in prioritized order, while the product keeps serving customers. Our longest client relationship is heading into its tenth year; the case study is on the site.
It’s also not a judgment. Every codebase we audit was built under real constraints by people doing their best inside them. The audit exists so the next set of decisions gets made with information the last set didn’t have.
If you own an app you can’t see into, that’s a solvable problem with a fixed scope and a two-week timeline. Tell us about it and we’ll tell you what an audit of your situation would cover.