Skip to content
OSOKORO

How to review a diff you did not write

Why AI-generated changes fail differently from human ones, the order to read them in, and the three failures that survive a careful read.

Published Aug 22, 20265 minutes to read

Reviewing your own change and reviewing a generated one are different activities, and using the habits of the first on the second is how bad code gets approved quickly.

The difference is where the errors are. A human's mistakes cluster around what they found difficult. A model's mistakes cluster around what was underdetermined — the places your request did not say what to do and something plausible got chosen. Those places do not look difficult. They look finished.

Read the file list first

Before a single line. Which files does this touch?

This is the highest-yield thirty seconds available, and it is the step people skip because it feels like not-reviewing. A file you did not expect is the whole signal: the model went somewhere while working out what you meant, decided something needed changing, and changed it.

You do not need to read the change to know that needs explaining.

Then read the deletions

Diffs are read top to bottom out of habit and that puts additions first. Additions are the safe part. You asked for something and there it is; if it is wrong, it is wrong in a way tests and use will find.

Deletions are where the damage is. A removed guard clause, a dropped null check, a deleted case in a switch, an error branch that used to exist. Each one makes the change look tidier and each one is invisible unless you go looking, because nothing downstream complains until the condition it handled occurs.

Filter the diff to removals and read those on their own. It takes a minute and it catches the class of mistake most likely to reach production.

Then ask what the change assumes

Every generated change encodes decisions your request did not specify. What happens on empty input. Whether the operation is idempotent. Whether a failure retries or gives up. Which timezone. Whether that number is cents or dollars.

The model picked something reasonable-looking for each. Reasonable-looking is not the same as what your system does elsewhere, and consistency is the thing generated code is worst at — it has no opinion, so it takes the local convention of whatever file it happened to read.

Concretely, the questions worth asking every time:

  • What does this do with nothing — empty list, empty string, null?
  • If it runs twice, is that the same as running once?
  • Which error path did this choose, and does the rest of the codebase choose that one?
  • Are the units right? This is where money bugs live.

Three failures that survive a careful read

The plausible-but-unused abstraction. A helper introduced to serve two call sites where one would have done, or a parameter added "for flexibility". Harmless individually, and it accumulates into a codebase nobody can navigate. Ask whether the abstraction earns its place; if you cannot name the second real caller, it does not.

The confidently-wrong comment. Models write comments describing what the code was meant to do. When the code and the comment disagree, the comment is usually the one that reflects your request and the code is what actually shipped. A comment that restates the line below it is noise; a comment that contradicts it is a bug report.

The silently narrowed scope. You asked for something handled everywhere; it was handled in the three places the model read. The diff is correct in what it contains. It is the absence you cannot see, and it is why the file list matters — the wrong file list is often the only visible trace.

Make the boundary explicit up front

The best review is a smaller diff, and you get one by saying what not to touch.

Ask for the plan before the edit. Read it, correct the part that is wrong, then let it write. One cheap turn that saves a review of a change built on a misunderstanding — and it gives you something to hold the diff against, so you can tell whether the result matches the plan without reading every line.

Then bound it: "change only this file; do not tidy anything else." Models are helpful in a way that is occasionally destructive, and unasked-for tidying is the most common source of surprise files.

Where the tooling helps and where it does not

Codoro proposes multi-file edits as one approved diff, runs allowlisted build and test commands against them, and supports optimistic undo. Approving at the task boundary rather than per edit is deliberate — per-edit approval turns you into a slow autocomplete.

What no tool does: tell you which of the four questions above matters for this change. That is the part that stays yours, and it is the reason "the tests pass" is a floor rather than a review.

Worth naming the incentive too. Each agent turn re-sends the whole accumulated conversation as input, so a task that spirals is expensive as well as hard to review. A per-run cap — $2.00 by default, editable, with a $25.00 daily backstop — mostly protects your money, and it also caps how large a diff can get before you look at it. When it fires, the run pauses and offers a cheaper model rather than switching silently, because a diff half-reasoned by one model and half by another has an invisible seam in it.

Status

Codoro is in preview for macOS with no public download yet. The review habits above apply to any agentic tool; the approved diff, the allowlisted checks and the caps are how this one implements them.

Read next

All writing