Reviewing code nobody wrote
Dennis Zaiser, technical founder
Code review used to be a conversation between two people who both understood the change. Now one side of it is an agent that has already moved on, and the number of changes has grown faster than anyone's attention. Review needs a different shape.
The bottleneck moved
When an agent can produce a feature's worth of changes in an afternoon, writing stops being the slow part. Reading is. A team that once reviewed a few changes a day now faces more than it can read closely, and the queue grows faster than it drains.
A reviewer facing more than they can read does what anyone would. They skim, trust the tests and approve what looks plausible. Looking plausible is exactly what generated code is good at: consistent style, sensible names, tidy structure. The defects that remain are the ones that look right, and those are the ones a skim misses.
Adding reviewers doesn't fix it. The volume of agent output grows with the number of agents you run, and the number of people who can read closely doesn't. The way out is to make each review cheaper and to send less to it, not to read faster.
No author to ask
In a review between people, the reviewer could ask why. The author remembered the trade-off, the case that didn't fit and the approach that was tried and dropped. With agent-written code there is nobody to ask. The session ended, its transcript is long and unread, and the next agent knows only what the code says.
So the reviewer reconstructs intent from the diff, which is the hardest way to do it. Over time a project collects code that nobody on it has read closely. Each change is understood a little less than the last, until nobody can explain how a part of the system works without reading it from scratch. That growing gap between what the code does and what anyone understands is comprehension debt, and it compounds.
Review the plan before the code
The cheapest place to catch a wrong approach is before it is built. A short plan says what will change, where, why, and how it will be checked. It takes a minute to read, and it catches the misunderstanding that would otherwise surface inside a large diff, after the tokens are spent and the code is written.
A plan also brings out the questions the agent would otherwise settle silently: which table to change, whether old data needs migrating, what to do with the case that doesn't fit. Answering them in the plan takes a minute. Finding the agent's answers inside the diff takes an hour.
Approving the plan does a second job: it gives the review a reference. Once a plan is approved, whoever reviews the result compares it with the plan instead of inventing a standard on the spot, and a change that wanders from the plan stands out.
Let the checks go first
A person's attention is the most expensive check in the process, so it should come last. Type checks, lint, tests and the checks specific to your project run before anyone looks. When they fail, the work goes back to the agent, not to the reviewer.
Better still, put the checks inside the build. A loop that repeats the build until the checks pass means the agent fixes its own failures while it still has the context, and the reviewer sees only work that already meets the mechanical bar. The person then spends their attention on what no check can answer.
Checks are also where your project's own rules pay off. A rule a script can verify, such as which modules may import which, or that every message on screen has a translation, is a rule no reviewer has to remember. Each one you add takes a little load off the person at the end.
Review against what was asked
With the checks handled, the review question changes. It is no longer “is this code good?” but “does this do what we decided, and nothing we didn't?” That question has an answer when the goal's definition of done sits next to the result, along with the outputs the agent was required to produce: the approved plan, a summary of what changed, the check results. The branch is there for the places where the detail matters.
Keep the roles apart. The agent that wrote a change shouldn't approve it. A second agent can review first and catch the obvious, with a different model or a different agent if you like, but the final approval belongs to a person.
Size matters as much as roles. A change small enough to review in one sitting gets a real review. A change that touches thirty files gets a skim, however good the reviewer. Ask agents for one item at a time, and split work that grows past what a person can hold in their head.
Make sending work back as easy as approving it, and make the reason travel. A send-back that says what is wrong, and returns the work to the step that needs it, turns review into steering rather than a yes or a no. Over time the reasons show where the process keeps failing, which is worth more than any single review.
Where ctxflows fits
In ctxflows, review is a node in the workflow. An approval stops the run for a person and shows what the decision needs: the outputs the earlier nodes produced, the results of the checks and the branch to inspect. The diff itself stays in your repository, because your code never enters ctxflows. A loop repeats the build until the checks pass, so the approval sees only work that already meets them.
An agent the engine started never approves its own work; the approval waits for a person. Send work back with a reason and the run returns to the node that needs it. Runs & actions keeps everything waiting on you in one place, answered from the web app, the built-in assistant or your own agent's session. Analytics shows the first-pass rate and rework per workflow, so you can see where reviews keep sending work back.