I use AI coding tools every day. I also review everything they produce as carefully as code a person handed me, and slightly more carefully in a few specific places.

Both of those are true at once, and I think the second is what makes the first defensible. The tool is not accountable for what ships. The person who merged it is.

Where the failures actually are

After a couple of years of this, the mistakes cluster. Generated code is usually syntactically fine and often structurally reasonable. What it gets wrong is narrower and more predictable than people expect:

Plausible APIs that do not exist. A method name that sounds exactly right for the library, with arguments in a sensible order, that was never in the library. This fails loudly, so it is the least dangerous kind.

Silently outdated patterns. Code written against an older major version. Pydantic v1 validators in a v2 project. A deprecated React lifecycle method. This runs, until it does not.

Missing edge cases. The happy path is handled beautifully. The empty list, the null, the duplicate, the concurrent write are simply not considered.

Over-broad permissions. Generated infrastructure and access-control code reaches for the configuration that definitely works rather than the one that is correct. A wildcard IAM policy. A CORS origin of *. It works, which is the problem.

Confident wrong comments. A docstring that describes what the function was probably meant to do, attached to a function that does something slightly different.

The checklist

I run through this every time. It takes a few minutes.

1. Does every API it used actually exist?

Check the imports and the method calls against the real documentation, not against whether they look familiar. This catches the hallucinated ones immediately.

2. Is it the right major version?

Ask what version of each library the code assumes. Compare with what the project actually has. This is the single highest-yield check in the list.

3. What happens with nothing, one, and many?

Empty input. A single item. A large collection. A duplicate. If the code handles an empty list by indexing [0], you have found the bug.

4. What does it do with untrusted input?

Any user-supplied value gets validated. Any database query gets parameterised. Generated code is usually fine on SQL injection now, and notably worse on authorisation, which brings us to the next one.

5. Is the permission check on the object, not just the role?

Generated access control almost always verifies role and almost never verifies ownership. is_admin is checked. Whether this admin may touch this record often is not.

6. Are the permissions as narrow as they can be?

Read the IAM policy, the CORS config, the database grants. Replace every wildcard with the specific thing. This is tedious and it is where real vulnerabilities live.

7. Do the tests test behaviour, or restate the implementation?

Generated tests have a habit of asserting exactly what the code does, including its bugs. A test that would still pass if the requirement changed is not a test, it is a snapshot.

Write at least one test yourself, from the requirement, without looking at the implementation.

8. Do I understand every line well enough to defend it?

If I cannot explain why a line is there in a code review, it does not go in. It does not matter that it works. Code I do not understand is code I cannot maintain, and it becomes someone’s problem later, possibly mine.

What it is genuinely good at

I want to be fair here, because the useful position is not scepticism, it is calibration.

Generated code is excellent at things that are well understood and tedious: boilerplate, a data class from a schema, a first-pass migration, a regular expression, converting between two formats, the fifteenth CRUD endpoint that looks like the previous fourteen. It is good at reminding you of a standard library function you had forgotten.

It is weakest exactly where the judgement is: the data model, the security boundary, the performance trade-off, and anything where the right answer depends on context it cannot see.

Which is a reasonable division of labour, as long as you keep the second half.

How I talk about it

I say plainly that I use these tools. Pretending otherwise would be strange in 2026, and the interesting question was never whether someone uses them. It is what their review process looks like.

That is the part worth being able to describe.

Related

Next step

Working on something this touches?

If this post lines up with a problem you have, I would rather hear about the problem than the post. Tell me what you are building.

  • Replies: Within two working days
  • Based in: the United States
  • Open to: full time, contract, remote or hybrid

Pages

Projects

Writing

Actions