· 4 min read B1

How I Review Code Written by AI

AI assistants write code very fast. But the code goes to production with my name on the pull request. This is the checklist I use to review AI-generated code, and the mistakes I see again and again.

Today I write a lot of code with AI assistants. Cursor, Claude Code, agents running in the terminal. They are fast. Sometimes they write in five minutes what I would write in one hour.

But there is something that didn't change: when the code goes to production, I am responsible for it. My name is on the pull request. If there is a bug in a payment flow at night, the AI will not wake up. I will.

So reviewing code became one of my most important skills. In this post I share how I review AI-generated code, the problems I find most often, and why I think this skill is now essential for any developer's career.

The new bottleneck is you

Before AI, writing code was slow, so we had time to think while we typed. Now code appears in seconds. The slow part is not writing anymore. The slow part is understanding and verifying.

I wrote about this idea in How to Build a Supervised Harness for AI Development: your attention is the real limit. If you accept code that you don't understand, you are not saving time. You are moving the time to the future, when you need to debug it in production.

My personal rule:

I don't merge code I can't explain.

If I can't explain to a colleague why a line is there, I don't accept it. I ask the AI to explain it, I read the documentation, or I rewrite it.

Before reading the code: check the task

Many review problems start before the code. If the instructions were unclear, the code will be "correct" for the wrong problem.

So first I compare the result with the original task:

  • Does it solve the problem I asked for, or a similar problem?
  • Did it change files that are not related to the task?
  • Is the size of the change reasonable? A small bug fix with 600 changed lines is a red flag.

AI tools love to "improve" things you didn't ask for: renaming variables, reformatting files, refactoring a function nearby. These changes make the review harder and hide the important lines. I ask for small, focused changes, and I reject big mixed ones.

Step 1: Look at the tests first

I always start the review with the tests, not with the implementation. The tests tell me what the code is supposed to do.

Things I check:

  • Are there tests? For new behavior, there must be.
  • Do they test behavior or implementation? A test that checks "method X was called twice" breaks with every refactor. A test that checks "the transfer moved 300 euros" is useful.
  • Do they test the difficult cases? Empty lists, null values, limits, errors, concurrency. AI often tests only the happy path.
  • Did the AI change existing tests to make them pass? This is the most dangerous shortcut. The code was wrong, the test failed, and the agent "fixed" the test. Always look at changes in test files very carefully.
  • Are there skipped tests? Look for skip, markTestSkipped, @pytest.mark.skip, xit, or commented tests.

In my harness I have a script that blocks some of these shortcuts automatically. But a human eye is still important.

Step 2: Check correctness

Now I read the implementation. The questions are the same as for human code, but some errors are more common with AI:

Invented APIs. The model uses a method or option that doesn't exist in your version of the library. It looks perfect and the name is logical, but it isn't real. Static analysis (PHPStan, mypy, TypeScript) catches many of these. Run it always.

Old versions. The model learned from code of many years. It may use deprecated functions or old patterns of your framework.

Wrong assumptions about your domain. The AI doesn't know that in your company a "transfer" can be partially reversed, or that amounts are always in cents. It guesses. Check business rules carefully.

Silent error handling. Look for try/catch blocks that catch everything and do nothing, or return null or an empty array. The code looks stable, but it hides problems.

try {
    $this->gateway->charge($payment);
} catch (\Throwable $e) {
    return null; // the AI wants the test to pass... the bug is now invisible
}

Off-by-one and limits. Pagination, date ranges, < vs <=. Classic bugs, very common in generated code.

Step 3: Check security

AI-generated code can be insecure in subtle ways. My checklist:

  • Input validation. Is user input validated before use?
  • SQL and command injection. Any string concatenation in queries or shell commands?
  • Authorization. Does the code check that the user owns the resource? This is the most frequent problem I find. The endpoint works, but any user can read any invoice by changing the ID. (I talk about this in REST API Design Best Practices.)
  • Secrets. Any API key, password or token in the code, the tests or the config?
  • Logs. Does it log personal data or tokens?
  • New dependencies. Did it add a package? Is the package real, maintained and popular? Models sometimes suggest packages that don't exist, and attackers register those names with malicious code. Always check new dependencies.

Step 4: Check the design

Code can be correct and still be a problem for the future. I check if it respects the architecture of the project:

  • Is the code in the right layer? In a hexagonal architecture, an SQL query inside a domain entity is a design bug, even if it works. (See Hexagonal Architecture Explained Simply.)
  • Does it follow the project's patterns? If the project uses command handlers, the new feature should use command handlers, not a new "service" style.
  • Duplication. AI often writes a new helper function when the project already has one. It doesn't know the whole codebase.
  • Over-engineering. Sometimes the opposite: three interfaces, a factory and a strategy for a simple if. AI can follow SOLID principles too literally.

One useful trick: give the AI clear rules about your architecture before it writes code. In Cursor I use rule files; in Claude Code, a CLAUDE.md. Better instructions mean less review work.

Step 5: Run it

Reading is not enough. I run the code:

  • The full test suite, not only the new tests.
  • Static analysis and linters.
  • The feature manually, at least once, in a local environment.
  • For APIs, a real request with real-looking data.

If the change touches performance-sensitive code, I check the database queries. AI-generated code loves the N+1 query problem: a loop that runs one query per item.

Ask the AI to review itself (but don't trust it completely)

A useful technique: ask a different session or a different model to review the code, without the conversation history. Give it only the task and the diff. A fresh reviewer finds problems that the writer doesn't see, because it doesn't share the same assumptions.

This is the "blind reviewer" idea from my harness. It works surprisingly well. But it is an extra filter, not a replacement for your review. The final decision is yours.

My checklist

  • The change solves the requested task, and only that task.
  • The change is small enough to review properly.
  • Tests exist, test behavior and include edge cases.
  • No existing tests were weakened, skipped or deleted.
  • No invented or deprecated APIs (static analysis passes).
  • Business rules are correct for our domain.
  • No silent catch blocks.
  • Input validation and authorization checks are present.
  • No secrets or personal data in code or logs.
  • New dependencies are real and trustworthy.
  • Code is in the right layer and follows project patterns.
  • No duplicated helpers, no unnecessary abstractions.
  • I ran it, and I can explain every line.

Why this matters for your career

Some developers are worried: "If AI writes the code, what is my job?" I think the answer is clear. Your job is to decide what is correct. That requires the skills that always made a senior developer: understanding the domain, knowing the architecture, thinking about security, seeing the edge cases, and saying "no" to bad code.

Junior developers can now produce a lot of code. But companies need people who can judge that code. Reviewing well is becoming one of the most valuable skills in our profession.

If you want to practice, here is a simple exercise: next time an AI writes a feature for you, before you accept it, write down three things that could be wrong. Then check them. After some weeks, you will review faster and better.

Summary

  • AI writes code fast, but you are responsible for it.
  • Don't merge code you can't explain.
  • Start the review with the task and the tests.
  • Watch for typical AI problems: invented APIs, modified tests, silent catches, missing authorization, fake dependencies.
  • Check that the code respects your architecture.
  • Run it. Reading is not enough.
  • Use a blind AI reviewer as an extra filter, not as the final judge.

AI changed how we write code. It didn't change who is responsible for it.

Share: X LinkedIn