Reading AI-generated code
Comprehension is the loop stage automation can't do for you, and reading code you didn't write is harder than reading your own — you must reconstruct intent from output instead of building it as you go. Worse, AI code is fluent by construction: clean, idiomatic, well-commented whether or not it's correct, and that polish actively suppresses your skepticism. The discipline is active reading against the spec you committed, hardest exactly where the code looks cleanest.
On this page
Reading AI-generated code
The bug that hid behind good formatting
You prompt for a function and get back forty lines: clear names, sensible structure, a couple of tidy comments. It reads well. You skim it, it looks right, you accept it and move on. Buried in it is an off-by-one on a boundary you didn’t trace — and it shipped because the code was pleasant to read, not despite it.
Predict, before reading on: why was this bug harder to catch than the same bug in a tangle of messy code? The messiness of bad code makes you slow down and scrutinize. The polish of AI code does the opposite — and that’s the trap this whole chapter is about.
Reading is harder than writing
When you write code, you build the mental model as you go — every line is a decision you made, so you understand it by construction. When you read code you didn’t write, that’s reversed: you have to reconstruct the intent and the model from the finished output, with no record of the decisions that produced it. That’s strictly harder, and it’s a different skill — the one senior reviewers have and juniors underestimate.
AI assistance turns this from an occasional task (reading a teammate’s PR) into the core of the job: most of the code you “write” is now code you read. So comprehension stops being a background skill and becomes the bottleneck. The practical form is active reading: trace the data through the function, evaluate the boundaries by hand, and map each part to what you expected — not a top-to-bottom skim for whether it “seems fine.” Skimming is how the formatting wins.
The fluency trap
Be precise about the danger. The model is optimized to produce output that looks like correct code — plausible by construction — which is a different target from being correct. Most of the time plausible and correct coincide; the trap is the gap, and the gap is invisibly smooth. The most dangerous code an AI gives you is not the obviously-broken kind (you’ll catch that); it’s the kind clean enough that you stop reading.
Concrete tells that something fluent deserves a harder look:
- Confident handling of a case you never specified — the model invented a behaviour for the empty/null/overflow case; invented behaviour is a guess wearing the same clean style as the rest.
- A comment asserting a property the code doesn’t guarantee — “safely handles concurrent access” over an unlocked dict. The comment is generated text, not a proof.
- The boundary that isn’t there — the happy path is immaculate and the edge case simply isn’t addressed, which reads as “fine” because nothing looks wrong.
The rule of thumb: read hardest where the code looks cleanest, because that’s where your scrutiny drops and the model’s confidence is least earned.
Read against the spec
The antidote to “does this look reasonable?” is “does this match what I committed?” Your preregistration (Ch 3) is the checklist: read the code against each invariant and each boundary test, diffing the code’s actual behaviour against the standard you set before you saw it. This is the concrete reason preregistration pays off here — without a committed spec, reading degenerates into style judgment and fluency wins; with one, reading is a finite list of properties to confirm.
Predict the real issue in each case (the fluent red herrings are right there with it):
AI code is fluent by construction — clean, idiomatic, well-commented — whether or not it's right. Read against your spec, not for style. Pick the real issue, not the red herring.
“The AI's dedup function is clean and passes the sample. Reading against your spec (fuzzy match on name + email), you see it builds a set() of exact tuples. The issue?”
“An AI-written average(nums) is clean and correct on every example. What do you check first?”
“An AI function carries the comment 'safely handles concurrent access', but the code uses a plain dict with no lock. The right read?”
In every one, the catch comes from reading against the spec or the boundary — never from how the code looks. Style is the distraction; the committed standard is the lens.
How this is graded
Technical Correctness is this chapter’s weighted dimension — comprehension is the ability to reason about correctness in code you didn’t type:
- Technical Correctness (weighted) — you can explain what the code does and name where it breaks, rather than asserting it “looks fine”; the re-read-to-answer tell is gone.
- Evaluation Rigor — you read against the committed invariants and boundaries, treating the spec as the lens rather than judging style.
- Trade-off Awareness — you spend your reading budget where risk concentrates (boundaries, seams), not uniformly or on cosmetics.
- Communication — narrating what the code does as you read it (“this is a streaming pass, which handles the large-input case”) is the proof to an interviewer that you actually comprehended it.
Industry variation
- Startups — you can’t read everything; read the risky 20% (the core invariant, the boundary) and let the cosmetic rest go.
- Big tech — reviewing AI output is now a core competency; Google’s code-comprehension round tests exactly this, and large-scale review culture assumes you own what you approve.
- Regulated (fintech, health) — reading is sign-off: approving AI-written code means you accept accountability for it, so comprehension is a compliance act, not a courtesy.
- Frontier labs — reading AI-written research code for subtle method bugs (a wrong axis, a leaked label) where the output runs fine and the error is silent.
Stretch: reading is necessary, not sufficient
Reading catches what you can see and hold in your head. It won’t catch the interaction you didn’t imagine or the case you can’t simulate by eye — for those you need to run the code against the standard. Before the next chapter: for the rate limiter, name one property you’d struggle to confirm by reading alone and would have to verify by executing.
Next: Chapter 6 — Verification under automation, where “it ran” and “it’s verified” turn out to be very different claims, and the loop’s solo stages close.