Skip to main content

Command Palette

Search for a command to run...

Reviewing AI-Generated Code: What Changes and What Doesn't

Updated
3 min readView as Markdown

The first pull request I reviewed that was substantially AI-generated, I caught myself doing something I wouldn't do with a colleague's code: skimming it more generously because it "looked clean." Clean formatting and correct behavior are not the same thing, and that instinct to relax scrutiny the moment code looks polished is exactly backwards for AI-assisted output. It took a genuinely subtle bug slipping past that instinct for me to recalibrate how I review this code.

The bug that recalibrated my review process

A generated function for calculating a loan's remaining balance looked entirely reasonable: clear variable names, sensible structure, comments explaining each step. It also silently handled a negative payment amount by simply subtracting it from the balance, increasing the balance instead of raising a validation error, because nothing in the prompt had specified that payments couldn't be negative and the model filled that gap with a plausible-looking assumption instead of an error. Nothing about the code looked wrong. The wrongness was in an assumption baked into logic that was otherwise well-written.

What doesn't change: the fundamentals of code review

Correctness, edge cases, security implications, performance characteristics, none of these review dimensions change because of who or what wrote the code. A SQL injection vulnerability is exactly as dangerous whether a junior developer or a model produced it. I review AI-generated code against the same checklist I'd apply to any pull request, because the risks that checklist protects against haven't gone anywhere.

What does change: where I concentrate extra scrutiny

Plausible-looking assumptions. Generated code tends to fill gaps in an underspecified prompt with something reasonable-sounding rather than flagging the ambiguity, the way a human developer might ask a clarifying question. I specifically look for logic that handles an edge case in a way nobody explicitly asked for, and check whether that handling is actually correct or just plausible.

typescript

function calculateRemainingBalance(current: number, payment: number): number {
  return current - payment; // what happens with payment = -500?
}

Consistency with the rest of the codebase. Generated code often doesn't know about a project's existing patterns, error handling conventions, a shared validation utility, a specific logging format, and will confidently reinvent something that already exists elsewhere, sometimes slightly differently.

Test coverage that matches the code's actual behavior, not just its apparent behavior. I've seen generated tests that assert the happy path works and never touch the exact edge case where the generated implementation is weakest, because the same gap in specification that produced the weak implementation also shaped what the model considered worth testing.

Explanations that sound confident regardless of correctness. A generated comment explaining why code works reads with the same confident tone whether the explanation is accurate or not. I verify the explanation against the actual code rather than trusting the comment as confirmation.

The habit I've built

I read AI-generated code slower than I initially wanted to, specifically to counteract how much faster it is to produce than to properly review. The speed gain on the writing side is real. It doesn't transfer automatically to the reviewing side, and treating a clean-looking function as lower risk because it reads well is precisely the failure mode that let the balance calculation bug through in the first place.

The real discipline

Review AI-generated code with more attention to gaps and assumptions, not less scrutiny because it looks polished. The code still needs to be correct, and correctness was never about how confident or clean something looks on the page.

3 views