A checklist for reviewing AI-generated code

AI-generated code turns up polished. It compiles and passes the tests it ships with, and it reads like the work of a careful colleague. But a model produces all of those signals whether the change is right or wrong, so none of them can tell you whether it's correct.

This article is about why reviewing generated code needs a different posture from the one you'd use on a colleague's work, and it ends in a five-step checklist you can run against the next AI-authored change you're asked to merge.

Polish

When a colleague sends a tidy change with clear names and a careful explanation, you may take that as a sign they have thought it through. It still needs review, but you have some context for their choices. An assistant can produce the same tidy result without getting the behaviour right. The naming and formatting won't help you tell the difference.

There's a second problem. When a model explains its own change, the explanation and the code come from the same source, so if the change is wrong, the explanation is usually a fluent argument for the same mistake. However persuasive it reads, it isn't independent evidence.

The hardest defects to spot sit in changes that pass every check you happened to run and read like the work of a careful engineer, yet fail in a way that only surfaces in production. Generated code can also fail in patterns a reviewer doesn't expect from human work: a method or option that doesn't exist in the version you run, say, or behaviour borrowed from a different library (or sometimes a whole refactor nobody asked for).

Studies

The studies measure different kinds of work, so I would be wary of using any one figure to predict a team's saving. In Peng et al. (2023), 95 professional developers worked on a defined JavaScript HTTP-server task. Those using GitHub Copilot finished 55.8% faster. That is useful evidence for a task with a clear scope and a result that can be checked relatively easily.

METR's early-2025 trial used 246 real issues from repositories familiar to its 16 experienced open-source developers. With AI tools, they took 19% longer. They had expected a 24% speed-up before starting, and afterwards they still estimated that AI had made them 20% faster. Review and repair took time that their estimates did not capture. That is a reason to measure elapsed time, including the checking, when deciding whether a tool helps. The result also has a date attached: in February 2026, METR said newer tools probably improved the result, but selection effects in its later data meant it could not give a reliable current estimate.

CodeRabbit looked directly at defects in its December 2025 analysis of 470 open-source pull requests, 320 of which were AI-coauthored. That set had roughly 1.7 times as many issues, and nearly twice as many gaps in error handling. Practitioner accounts through 2026 also describe reviewers struggling to keep up with the volume of generated changes. A team can produce more code than it has time to check.

55.8%faster on a defined HTTP-server task with Copilot (Peng et al., 2023)
19%longer on real issues in repositories they knew well (METR, early 2025)
~1.7xthe issues in the AI-coauthored set across 470 pull requests (CodeRabbit, December 2025)

These results are a reason to budget time for review, even when producing the first version gets quicker.

Allow time to review the code, however quickly it was generated.

Claims

For a generated change, I want evidence I can check outside the assistant's answer before I accept it.

The practical way to hold that rule is to treat every part of a generated change as a claim rather than a fact. The summary claims the change does what the ticket asked. Each block of the diff claims it's necessary. Each API call claims the method, option or behaviour exists in the version you run. The included tests claim they cover the behaviour that carries the risk.

Review is the work of turning each claim into evidence, or a correction, or a rejection.

And note what doesn't count. Asking a model (the same one or a different one) whether the patch is safe produces another response from the same category of source. A model's review of a patch can be a useful list of hypotheses to check, but it's a poor substitute for checking them.

Checklist

The five steps are ordered so that each adds evidence the previous step can't provide. Work through them in order.

1. Read everything

Ask of each change:

  • Why is this change here?
  • Is it required by the task, supporting it, or unrelated?
  • What behaviour existed before that no longer does?
  • What does this touch that the ticket never mentioned?

Classify each change as necessary, supporting or unrelated. An unrelated refactor is unrequested review scope, and every extra line dilutes the attention left for the lines that need it. So take it out of the change, and raise it separately if it has value.

2. Run tests

Run the tests and keep the result. If your review says they passed, someone reading it should be able to find that run. Then read the tests themselves and ask what is missing. A suite that tests the new behaviour may say little about existing behaviour that the patch could break, so a green result is only the beginning of the review.

3. Test failures

Try inputs and conditions the request didn't spell out. Send invalid data, make a dependency fail and run the operation twice. Check the result in each case, including any records left behind after a failure.

4. Check boundaries

Before accepting any change, ask four questions the ticket almost certainly didn't ask:

BoundaryQuestion
SecurityWhat can now be accessed, logged or leaked that could not before?
Data integrityCan this destroy, corrupt or orphan existing records?
ConcurrencyWhat goes wrong when two of these run at once?
CompatibilityWhat breaks for callers, consumers or old data?

These questions earn their place because a generated change won't account for them unless something in the prompt or the ticket demanded it, and most tickets don't.

5. Verify APIs

Check each API call against the documentation or type definitions for the version the project uses. Check the parameters too, then run it where you can. An assistant may suggest a method that doesn't exist, an option from a newer version or behaviour from another library. The call can look quite reasonable while still being wrong.

Review

In Module 1, we compare two ways of reviewing the supplied change. In the first, the reviewer reads the assistant's summary, skims the diff and accepts it after the visible tests pass. Anything those tests missed goes through too. Working through the checklist takes longer at review, but gives you a chance to find those problems and remove unnecessary changes before they reach production.

Use the risk of the change to decide when you've checked enough. A one-line copy correction won't need a concurrency investigation. Authentication, payments and stored data deserve much closer attention. You still need some evidence for every change you accept, but you don't need to spend the same amount of time on all of them.

The change you merge will usually be smaller than the change you were given, and that's fine, because rejecting scope is part of reviewing. The rule cuts the other way too: verification exists to separate correct work from defective work, so rewriting everything from scratch just because a model wrote it fails the same test.

Before finishing, add the commands and results to the pull request description, or wherever your team records its reviews. Include any extra tests and explain which changes you rejected. That saves the next reviewer from having to reconstruct what you did.

This article covers Module 1, verification before trust, the first of four sessions taught live on San Digital's AI-Assisted Engineering course.