Baobaobaolin.com
date
entry
010
topic
tooling
rev

Reviewing code an agent wrote: the report is intent, not fact

Delegate an implementation to a coding agent and what lands at the end is a completion report: files changed, build green, tests passing. That text describes what it meant to do. To find out what it did, there is exactly one source — the diff.

Delegation works. Well-bounded implementation work — the schema exists and only the API wiring is missing, the same mechanical change across ten files, a second diagnostic opinion when you are stuck — goes faster handed to another agent than typed yourself.

The trouble is the hand-back. You receive a well-organised report that reads as entirely reasonable and is usually mostly correct. That is the difficulty: if it were wrong throughout, you would notice immediately.

Where the report and the diff diverge

The gaps I have actually run into fall into a few kinds:

  • Says it changed A, actually changed B. Two similar struct initialisations in one file; it edited one and named the other in the report
  • Undeclared drive-by changes. The brief said do not touch the frontend, and it "tidied up" a type along the way
  • A missed file. Four of five files done, the fifth present in the report and absent from the diff
  • The test "passes" because the assertion changed. The expensive one; its own section below
  • The build result is from the previous run. The report says all pass, but that run predates the last edit

None of these is a lie. Producing the report and executing the work are two separate paths — the report is generated from intent and plan, not read back from the filesystem. When plan and execution diverge, the report faithfully reflects the plan.

It is the mild version of a tool error rewritten as a fluent completion report: fluency and correctness are uncorrelated in the output, and humans have a trust bias toward fluent prose.

The procedure

Whatever the report says, these steps run every time.

1. Read the diff, not the summary

git status -sb
git diff

Four questions while reading:

  1. Only the files that should have moved? Anything in git status the brief never mentioned
  2. Does it match the code around it? Whether a new field's json tag, omitempty and nil handling agree with its neighbours a few lines up
  3. Is it the right occurrence? With several identical or near-identical structures in one file, check line numbers and enclosing function for each hunk
  4. Is the error handling at the right level? Should this failure abort or log a warning — a convention question an agent cannot infer

2. Rerun the checks yourself

Do not take its output as evidence. Run the same commands:

go build ./... 2>&1 | tail -5
go vet  ./... 2>&1 | tail -5
go test ./internal/service/ -run '<prefix>' -count=1 2>&1 | tail -8

The -count=1 matters: without it you may be reading a cached result, which puts you back to trusting that someone else ran it.

Running Go inside a restricted sandbox can fail because the default cache directory is not writable; export GOCACHE=/tmp/go-cache gets past it. That is an environment problem — do not misread it as broken code.

3. Look at the test diff on its own

If the delegated work included "make this failing test pass", pull the test files out separately:

git diff -- '*_test.go'

You are separating two situations: an assertion corrected to a sensible expected value (fine), or an assertion loosened until it no longer checks the thing it existed to check (a false green). The first is a fix. The second removes the thermometer.

People do this too, just less often — because people know a review is coming. So the real difference is not honesty, it is whether anyone is looking.

Sort findings into two tiers

After the review you have to make a call. I sort into two tiers:

  • Blocking — build or tests broken, changes inside an area the brief excluded, patterns inconsistent with the existing code. Send it back, or fix it yourself
  • Non-blocking — a missing omitempty, an empty result serialising as null instead of []. List them; do not hold the work

Tiering exists to avoid two failure modes: bouncing an entire piece of work over something cosmetic, and waving through out-of-scope changes because it is "broadly fine".

The cost of review is set when you delegate

All of the above only works because you knew in advance which files should have changed. If the brief said "make this feature work", you have no baseline to compare against at review time — only a whole diff to read while guessing at intent, which is slower than writing it yourself.

A brief that can actually be reviewed contains at least:

  • An itemised list of changes with file paths, line numbers if you have them — this doubles as the review checklist
  • Known preconditions: what already exists and must not be redone (the column is already in the production database and the model; do not generate a migration)
  • An exclusion list: areas explicitly not to touch. The most frequently omitted item, and the most frequently violated
  • The acceptance commands: written into the brief so it runs them first. You will rerun them anyway, but the obvious failures never reach you

Some things should not be delegated at all: payment and state-machine logic, where a mistake lands directly on an amount, is cheaper to write yourself and read line by line than to review afterwards.

This is not about trust

To be clear, none of this depends on how reliable AI is. When a human colleague opens a PR you do not merge it because the description is clear either — you read the diff and you look at CI.

Code review never existed because authors are suspected of lying. It exists because an author's account of their change and the change itself are two artefacts that can disagree. That holds identically for people and for agents; agents simply produce more volume, so the absolute number of disagreements is larger.

If you remember one thing

Treat "what it says it did" and "what is in the files" as two independent records, then reconcile them. The first tells you where to look; only the second is evidence. Skip the reconciliation and what you ship is a diff nobody has read.

Revision history

  1. First published