Skip to main content

03.10Rule

Code review gates for AI-generated code

How AR Labs gates AI-generated code: a pull request per task, a four-axis review by a second model in a fresh context, and a person's merge.

A gateway marked MAIN with a turnstile; a pull request ticket waits at a reader with four lamps, one per review axis.A gateway marked main with a turnstile between its pillars. A pull request ticket waits at a reader with four lamps, one for each review axis.RULE03.09NOTHINGREACHES MAINUNREVIEWEDDRAWINGENG-03.09SUBJECTthe code review gateSHEET09 OF 26 · AR LABSMAINAXESPRONE BRANCH · ONE PR · A SECOND MODEL · A PERSON MERGES
On this page
  1. The problem it prevents
  2. Three gates
  3. Rules around the gates
  4. The one exemption
  5. Where it came from

The code review gate is how AR Labs checks AI-generated code before it reaches main. A gate is a point work cannot pass until a condition is met, and this one has three: tests, an independent review and landing. All implementation work happens on a branch, and changes reach main only through a merged pull request. Before the pull request is opened, a different AI model reviews the change on four separate axes, in a context that has never seen the implementing session. A person reviews and merges. Adopt it if agent-written code reaches your main branch on the strength of a polished diff.

The problem it prevents

AI-generated code fails in recognisable ways, and a reviewer reading polished code tends to approve it. Published studies point the same way. Huang and colleagues ("More Code, Less Reuse", 2026) studied 3,858 pull requests written by AI coding agents: in the project they examined most closely, agent code carried nearly 1.87 times the redundancy of human code, and across the whole set reviewers responded to agent pull requests with more neutral or positive sentiment than to human ones. Liu and colleagues ("Debt Behind the AI Boom", 2026) ran static analysis on about 300,000 AI-authored commits on GitHub and found that 22.7% of the issues those commits introduced were still present at the latest version of the repository. The failure patterns the review targets are:

  1. Gaming the checks: removing tests, adding || true, loosening thresholds.
  2. Blindness to existing code: duplicating a utility under a new name.
  3. Plausible but wrong: it compiles and the tests pass, but the logic is wrong.
  4. Sprawl: large, unscoped pull requests and half-finished work.
  5. Prompt injection: user input placed into prompts, or tokens with too much privilege.

Review by the same session that wrote the code cannot catch these reliably. The writer rationalises its own gaps, and by the end of a long session its context window (the working memory a model reads from) is full. Matt Pocock makes the same point: review in a fresh context, or the reviewer is weaker than the author.

Three gates

FIG. 01
flowchart LR
  B["Branch per task"] --> A["Gate A: tests"]
  A --> R["Gate B: four-axis review"]
  R --> C["Gate C: landing"]
  A -->|"fail"| F1["Fix, re-run"]
  R -->|"critical finding"| F2["Fix, re-review"]
  C -->|"rejected"| F3["Address feedback"]

Gate A, tests. Every test the change could affect passes, within the ten-minute ceiling described in test-driven development.

Gate B, independent pre-flight review. A second model from a different family, reached through OpenAI's Codex CLI, receives the diff, the spec, the design constraints and the proof manifest, and nothing from the implementing session: no transcript, no reasoning, no notes. It reports a verdict on each of four axes:

Axis Question
Standards Does the code follow the project's design language?
Spec Does it do what the spec asked?
Architecture Does it fit the system's structure?
Evidence Is every acceptance criterion proved by a committed test, check script or screenshot, as the proof manifest claims?

The axes are reported separately because a change can pass one and fail another. Code that follows every standard but builds the wrong thing passes Standards and fails Spec. Code that is correct but whose outcomes are only claimed passes Spec and fails Evidence. An axis fails if and only if it carries a critical finding, and a critical finding blocks the pull request. Warnings do not fail an axis; they are written into the pull request for the person to judge.

The review file is produced by a script, never by hand. The script records which commit was reviewed and appends a fingerprint (a SHA-256 hash) of the file to the task's notes. The gate refuses a review of any commit other than the current one, and refuses a review file that has been edited after it was written. After a failed review, one fix round is allowed, followed by a second review. In that second round each critical finding from the first must be answered as fixed, still standing or withdrawn, so a problem cannot disappear simply because the second reviewer looked elsewhere. Anything still critical after round two goes to a person, who decides per finding whether to fix it, accept it with a note or file it as new work. There is no third round.

Gate C, landing. Once Gate B passes, the agent pushes the branch and opens the pull request. The task does not close then: Gate C passes only when the reviewed commit is actually on the target branch, checked against git history or the code host's merge record. The agent does not merge its own pull request. A person reads the diff and checks what review by a model cannot: whether the change serves the goal, whether the scope is right, and whether it fits everything else in flight.

Rules around the gates

One pull request per task. The unit of review is the smallest tracked task. Bundling a whole feature produces a diff nobody can review well. A task is split into more than one pull request only when it is unusually large, and then along a clean seam such as backend and frontend. Review-and-fix loops follow the same rule: a correction loop that bundled five follow-up tasks into one pull request for a single re-review produced a diff too large to review, so each follow-up now ships its own pull request or is fixed inside the original one.

Pull request bodies are written for a cold reader. The reviewer may come to it weeks later. The body opens with three plain paragraphs: what was broken, what changes, and what the reviewer needs to do. The mechanism, the checks and the review results follow.

Branch names carry the task ID and a readable slug, for example task/app-42.3-persist-session. The ID gives traceability; the slug tells a reader what the branch is without looking the task up.

Update the docs a merge made stale, in the same session, while the change is fresh: a merge that adds modules, entities or screens updates the project's module table and architecture notes with it. A batched rewrite later is expensive and usually reconstructed from history.

The one exemption

A change that cannot alter what the program does needs no branch, pull request or review; it is committed straight to the target branch. The test is categorical, not a judgement of size, because "small" is decided by the agent that wrote the change. A change qualifies only when every changed line is a comment or docstring, prose in a documentation file, or formatting that the project's formatter reproduces exactly. Comments that change toolchain behaviour do not qualify: build tags, doctests, type-checker suppressions and lint-disable pragmas are code. A one-line configuration edit is small, and it still gets a branch and a review. The test suite is run anyway, as a cheap check that the change was what it appeared to be.

Where it came from

The branch, implement, review, merge pattern matches what we found across published agent workflows, including GitHub's guidance on reviewing agent pull requests, Cloudflare's risk-tiered AI code review, Addy Osmani's writing on code review in the age of AI, and Matt Pocock's Sandcastle workflow, which keeps branch-per-task even in fully automated runs.