How to review a codebase you didn't write
Inheriting a codebase you did not write is now normal, and the reviewer is often the person who prompted it. Here is an order of operations that finds the expensive things first.
Reviewing generated code is a different job from reviewing a colleague's pull request. A colleague's diff is small, and they can explain it. Here you have the whole system at once and no author to ask.
So the goal is not to read everything (you will not) but to find the small number of places where a mistake would be expensive, and look hard at those.
Do these first: five checks in twenty minutes
Before reading a single line of logic, establish whether the basics hold. Any of these failing is a bigger finding than anything you would discover by reading code.
Does it build from a clean checkout?
Clone into an empty directory and follow the README. If it does not build without undocumented steps, nothing else you learn is reliable: you are reviewing a system nobody else can reproduce.
Is every secret out of the repository?
Search the history, not just the current files, for keys and tokens. Generated code frequently inlines a key during development and a later commit removes it from the working tree but not from history.
What happens on the auth routes?
Find every endpoint and ask which ones check who is calling. The common generated failure is not a missing login page. It is a login page plus one API route out of thirty that forgot the check.
Where does user data live and leave?
Which tables hold personal data, and every place it is sent outward: logs, analytics, third-party calls, error reporters. Generated error handling is a frequent accidental exfiltration route.
Is anything actually tested?
Not coverage percentage. Just: do tests exist, do they run, do they fail when you deliberately break something. A suite that passes with the logic removed is worse than none.
Then: map before you read
The instinct is to open main and start reading. Resist it. You will spend an afternoon in files that do not matter.
Instead, build a map. You are answering four questions:
- 01What are the parts? Services, pages, routes, jobs, tables.
- 02What calls what? The edges matter more than the boxes.
- 03Where does data enter and leave the system?
- 04What is duplicated? Are two things doing the same job?
Question four is where generated codebases differ most from human ones. Humans duplicate when they are rushed; models duplicate when they cannot find the existing implementation, which is often.
You do not have to start from a drawing.
Point it at a repository that already exists (a local folder, a git URL, or an upload) and the same graph comes out the other side.
Doing this by hand on a large repository takes a day or two. Graphlit does the import automatically, which is the point: the map is the expensive part of the review, and it is also the part a machine can do.
The questions that expose real problems
Once you have a map, these five questions find more than line-by-line reading will.
| Question | What a bad answer means |
|---|---|
| Which parts talk to the database? | If the answer is "lots", there is no data layer and every schema change is now a search-and-replace across the codebase |
| How many ways can a user be authenticated? | More than one means at least one is probably weaker, and you have found the way in |
| What happens when this external call fails? | Generated code is optimistic by default; unhandled failure paths are the most common cause of a confusing outage |
| Which code is unreachable? | Orphans mean changes routed around old code rather than replacing it, a reliable sign of drift |
| What is duplicated? | Two implementations means a fix applied to one and not the other, which is a bug with a delay fuse |
What not to bother with
Reviewing generated code has its own list of wasted effort:
- Style and formatting. It is consistent, because a machine wrote it. Run a formatter and stop thinking about it.
- Micro-optimisation. Generated code is rarely fast and almost never the bottleneck. Measure before caring.
- Naming debates. Real cost, wrong time. You are looking for correctness and structure.
- Reading every file. In a large generated codebase this is neither possible nor useful. Follow the map to the risky parts.
Write down what you found
The review's real output is not a list of bugs. It is the map, and the rules you discovered while making it.
If you finish an audit and the only artefact is a fixed bug list, the next person repeats your entire afternoon. If you finish with a diagram of the parts and a written statement of which parts may talk to which, you have converted one-off effort into something durable, and if those rules are machine-checkable, into something that stays true. See architecture drift for why that last property matters.
Common questions
How long should a codebase audit take?
The five fast checks take under an hour on most projects. Building a useful map takes one to two days by hand for a medium codebase, or minutes if it can be derived automatically. Reading everything is not a realistic goal and not the objective.
What are the most common problems in AI-generated codebases?
In rough order of frequency: a missing authorisation check on one endpoint among many, duplicated logic where the model could not find the existing implementation, unhandled failure paths on external calls, and secrets committed to git history.
Can I review code if I'm not a developer?
You can do the structural checks: does it build from a clean checkout, are there secrets in the repository, is there a list of endpoints with stated permissions, do tests exist and fail when something is broken. Those find real problems. The logic itself needs someone who can read it.
Should I rewrite AI-generated code that works?
Usually no. Rewriting discards working behaviour along with the bugs. Map it, enforce the boundaries you care about, and replace parts only where you have a concrete reason. A rewrite is the most expensive response to a comprehension problem.
Draw it. Then keep it true.
Graphlit turns an architecture drawing into a typed graph, builds against it, and proves the code still matches. Free to start.