04 - Reviewing AI-Generated Code
📋 Jump to Takeaways🎁 The code compiles, the tests pass, and Claude sounds completely sure of itself. So why is it still your job to distrust every line of it?
Claude writes code fast, and most of it is good. But "most" is the problem. The one function in ten that's subtly wrong is written in the exact same confident tone as the nine that are right. Reviewing AI code is a different skill than writing it, and it's the one that separates engineers who ship from engineers who ship bugs.
Trust Calibration
The model's tone tells you nothing about correctness. It's equally fluent when it's right and when it's guessing. Your job is to decide how hard to look, and that depends on blast radius, not on how confident the output sounds.
Low scrutiny: a new test, a comment, a log line, a throwaway script
Medium scrutiny: a refactor with tests, a new endpoint, a config change
High scrutiny: auth, payments, migrations, deletes, anything touching prod dataCalibrate by what breaks if it's wrong. A typo in a log message costs nothing. A flipped condition in a permission check costs you a weekend and maybe a customer. Spend your attention where the damage is.
Plausible but Wrong
The dangerous failures aren't syntax errors. Those don't compile. The dangerous ones look exactly like working code: a hallucinated method that doesn't exist on the type, an off-by-one, a wrong default, an edge case silently skipped.
// Looks fine. Ships a bug.
func lastPage(total, perPage int) int {
return total / perPage // 100 items, 10 per page → 10. Correct.
// 101 items, 10 per page → 10. Wrong: drops the last page.
}The fix is (total + perPage - 1) / perPage, but you'll only catch it if you actually think through the boundary. The model won't flag it for you, because to the model this reads as complete.
Watch for scope creep too. You ask for a bug fix and get the fix plus a "helpful" refactor of three nearby functions you never asked about. Each extra change is unreviewed surface area.
Never Merge What You Can't Explain
This is the one rule that matters. If you can't explain what a line does and why it's there, you can't own it, and you shouldn't ship it.
❌ "The tests pass, so it's probably fine."
✅ "This retries on 429 with backoff because the upstream rate-limits per minute."You don't have to have written it. You do have to understand it well enough to defend it in review and fix it at 3am when it pages you. If a line is opaque, ask Claude to explain it, and if the explanation doesn't hold up, delete it.
Read the Diff
Don't review the summary. Read the diff. The summary is Claude's description of what it intended to change, which is not the same as what it actually changed.
git diff # every line before you stage
git diff --stat # which files got touched, catch surprise editsThe --stat view is your scope-creep detector. If you asked to change one file and five files show up, something went sideways. Read the changed lines, all of them, the way you'd read a coworker's PR. The bar isn't lower because a model wrote it. It's higher, because the model had no stake in the outcome.
Claude Reviewing Claude
You can have Claude review its own output, and it helps. A fresh pass catches bugs the writing pass missed. Claude Code ships a review capability for exactly this.
/code-review # reviews the current diff for correctness and qualityBut a second AI pass is a smoke detector, not a fire marshal. It raises signals worth checking. It does not absolve you of reading the code, because both passes share the same blind spots. Use it to widen coverage, never to replace your own review.
Verify Behavior Not Just Tests
Green tests mean the code does what the tests check. They say nothing about whether the tests check the right thing, and Claude may have written both the code and the tests to agree with each other.
npm test # passes ✓, but does the feature actually work?
npm run dev # click the actual button, watch the actual resultRun the real flow. Hit the endpoint, click the button, check the row landed in the database. Behavior is the source of truth. A passing suite written alongside the code it tests is a nice signal and a terrible guarantee.
Key Takeaways
- Confident tone is not correctness. Calibrate scrutiny by blast radius, not by how sure the output sounds
- The dangerous bugs are plausible: hallucinated APIs, off-by-ones, wrong defaults, skipped edge cases
- Watch for scope creep. A bug fix that also refactors three other functions is unreviewed surface area
- Never merge a line you can't explain. If you can't defend it in review, you can't own it in production
- Read the diff, not the summary.
git diff --statcatches surprise edits across files - A second AI review pass (
/code-review) widens coverage but shares your blind spots. It's not a substitute for you - Passing tests prove the code matches the tests. Run the real flow to prove the feature works
🎁 What if you need to migrate 200 files across a codebase, and the risk isn't one wrong line but a half-finished change that leaves the build broken for everyone?