The paper Whitepapers
kodebeat / lab / review pass

Reviewing code that no human wrote: you still own it

Machine-written bugs arrive neatly formatted, well commented, and written the way your codebase writes things. Your instincts were trained on human mistakes, which look wrong. So every check below replaces reading with something mechanical. Each unchecked line is one you have not answered yet.

Seven checks, about five minutes. Everything else is escalation: switch to full audit to see it, each item labelled with the condition that triggers it.

Two stances — if you generated this yourself, every upstream fix is yours to make before opening the PR: split the diff, rerun the session for what it skipped, tighten the prompt. If someone handed it to you, the same findings become requests — quietly fixing them yourself is how the author never learns what their tooling drops.

Set it up once — anything here you run twice by hand should become a gate: types that make invalid states unrepresentable, property and integration tests in CI, a mutation-score gate on changed paths, and a shared prompt config that caps what arrives — minimal diff, no abstraction it wasn't asked for, uncertain APIs flagged, and a closing list of assumptions and stubs. It is set up once in the repo, outside any single review.

00

Before you start reading

—

Four preconditions. A no on any of them means the review can't reach a real verdict, and the fix belongs upstream of you.

Standing rule — leave the line-level nitpicks alone. Linters and the model already handle style, and every comment you spend there is attention not spent where tools can't reach. And when reading can't settle a question, run that one path rather than debating it in comments.

01

Hunt for what isn't there

—

Absence is invisible when reading — you can't notice a line that was never written, or a convention the model didn't know to follow. Every check here replaces reading with something mechanical.

Standing rule — read the end of a long generated file harder than the start. Quality drifts as the model runs out of attention: error handling that was careful in the first function and half-hearted by the eighth, validation that quietly stops appearing, stubs marked "similar to above".

02

Make the tests prove themselves

—

Ignore the model's own verdict on its tests. "These are thorough" and "these are only for coverage" are both guesses, and neither is evidence.

Standing rule — manual testing never substitutes for a test. It doesn't run tomorrow, when someone else edits this.

03

Attack the happy path

—

Treat this as a menu: pick the one or two lines that describe this code and ignore the rest. A pure function has no concurrency; a CRUD endpoint has no float precision. Each one names an assumption the happy path depends on and never states.

04

Get a hostile second opinion

—

Asking a model to review a diff gets a summary of the diff. Asking it one hostile question at a time gets findings. Paste a prompt into your coding assistant with the diff in front of it, one angle per run.

  • List every implicit assumption this change makes about its inputs, callers and environment. For each, state what breaks if the assumption is false, and whether anything in the code enforces it.
  • Enumerate every operation in this change that can fail: I/O, network, parsing, allocation, external calls. For each, show the failure behaviour: swallowed error, wrong state, resource leak or crash. Flag any path that leaves the system inconsistent.
  • Trace every attacker-controllable input into this change. Identify injection (SQL, shell, path, template), missing validation or sanitisation, and unsafe deserialization. Give a concrete malicious input and its impact for each.
  • Find every authorization check and every secret or credential in this change. Flag missing, bypassable or over-broad access control, and any secret exposed in code, logs, error messages or responses.
  • List the external dependencies this change relies on. Flag unpinned versions, known-vulnerable surface, surprising transitive pulls, licence risk, and any place their output is trusted without validation.
  • Find where this change gets expensive at scale: N+1 queries, unbounded loops or allocations, blocking calls on hot paths, missing pagination or caching. Say where it falls over under production load.
  • List the data invariants this change must preserve. Find code paths that can violate them, plus nullability, migration and rollback hazards. Give a sequence of operations that leaves data corrupt or orphaned.
  • Compare this change against the contract its callers rely on. Flag breaking changes to signatures, return shapes, defaults, error codes or serialized formats, and everything downstream that depends on the old behaviour. Rank by likelihood of silent breakage.
  • Point out where this change is easy to misread or misuse: misleading names, hidden side effects, surprising defaults, silent type coercions, dead code, and comments that no longer match the code.

Standing rule — models invent plausible bugs. Reproduce each finding with a failing test or a manual repro before you raise it, drop the ones you can't, and rerun the prompts after the fixes land.

0/0done
— checks outstanding