The Human Is Not the Runtime
We made the most dangerous module in the system harder to change, and throughput did not move. The gate got stricter. The humans just stopped being the thing it runs on.
A few days ago a small team I work with put an AI product into production, in US healthcare. Going live rewrote the risk maths in one move.
Before production, most mistakes are recoverable. Revert the commit, repair the data, rerun the eval, tighten the system, move on. Production in a regulated industry deletes that comfort — particularly around one critical core module: a high-impact piece of the system where mistakes are difficult to reverse and "we shipped a fix" is not a complete answer.
So we made one boundary non-negotiable: pull requests touching that module now get materially deeper review. Slower, stricter, no exceptions.
Which sounds routine right up until it meets how the team actually works. Agents write the code, open the pull requests, respond to review comments, run the tests, update the tickets. Dropping a heavyweight review gate into that puts a human directly into the runtime. Every iteration then waits on someone noticing a notification, rebuilding context, reading a diff, writing comments, and coming back later for the next revision.
That buys control by destroying flow. We didn't want to pay it.
The bottleneck is review transport, not review
Across the tooling that matters in 2026, agents can now carry most pre-merge stages under supervision — planning and decomposition, multi-file writing, test generation, bug reproduction and fix, opening the PR, and responding to review comments. Capability varies enormously by repo and task, but the direction is not in dispute. The place the loop conventionally stops is merge, which most teams keep behind an explicit human approval.
The consequence is arithmetic. If you make writing code faster and leave review at human speed, you have not built a faster system — you have built a longer queue. The bottleneck grows in exact proportion to the productivity gain that created it.
Read as separate warning signals rather than one causal story, they still point the same way: change arrival went up, review capacity did not, and the gap shows up as waiting. And waiting does not grow politely — queueing behaviour is nonlinear near saturation, so a modest rise in arrival rate against fixed capacity produces a disproportionate rise in how long things sit. The instinct in a regulated environment is to answer that by making review heavier, which pushes utilisation further up the curve.
The move that actually works is different: keep the review heavy and take the human out of the transport layer.
What I actually watched happen
Here is the loop, exactly as it ran, over and over, for days.
Push, review, revise, re-review — two sets of agents playing ping pong across a repository boundary while the two humans who own the thing read the trace.
This is the part that gets skipped in write-ups like this one, so let me be exact about it. On the critical module the approval and the merge are still a human action, and that is not a temporary state of affairs we intend to automate away.
The claim is narrower than "no humans in the loop." It is that the human is no longer the transport — no longer the thing that notices, carries feedback, remembers a re-review is due, and reconstructs context four times per PR. What is left for the human is the part that was always the point: reading the consolidated review and deciding.
Worth separating two things that get conflated. The Slack message in step 1 is genuinely useful context — intent, risk, what to look at. What it is not is a trigger. My harness takes its trigger from repository state and its context from the PR body and the module's documented invariants; the Slack thread is for the humans. Decoupling those two turns out to be the most important design decision in the whole loop.
My harness does not listen to Slack
The obvious architecture is event-driven. A PR requests review, a webhook fires, a service validates it, an agent starts, a result gets posted. Immediate and efficient, on the whiteboard.
In production it is an integration surface: an endpoint, authentication, signature validation, secret rotation, durable receipt, retry handling, ordering, and observability for all of it. If delivery is at-most-once, one lost event strands a PR indefinitely. If it is at-least-once — which is what serious event infrastructure actually gives you — duplicates are normal and every downstream side effect has to be idempotent anyway.
Exactly-once processing is real inside a single transactional boundary. What you cannot get is one transaction spanning a webhook, an agent run, repository state and a posted review — four systems that share no commit. Retries, deduplication keys and idempotent effects stay on your plate regardless. Effectively-once is the honest name for what you can actually build.
"Review requested" may already be false by the time the handler runs. The PR may have closed, gained three commits, changed reviewers, or already been reviewed. A correct handler queries current state anyway — which means the event is a hint about when to look, not an instruction to act. That is a real service (it cuts full scans and improves responsiveness) but it is not authority.
The sweep just starts from the authority. Its question is not "what event fired?" It is "which PRs require action from me right now?"
That reframing turns the workflow into a reconciliation loop, and this is the part worth stealing whether or not you care about code review. Desired state: no eligible PR is sitting unreviewed. Observed state: the current set of open PRs, head commits, review requests and prior reviews. Each sweep computes the difference and acts on it.
This is controller-style reconciliation, and it is worth being accurate about the analogy: a Kubernetes controller does not reject events. It watches, queues, retries — and periodically resyncs, precisely because the watch stream can lie by omission. The lesson is not "polling beats events." It is that the resync is what makes the system correct, and the watch is what makes it fast. Events improve responsiveness; reconciliation delivers convergence. If you only get to build one, build the one that converges.
Why this is quietly more robust
A slower trigger can make a faster system
Most teams do it the other way round — webhook first, reconciliation added later, usually after an incident. But the sweep is the component that makes the system correct; the webhook only makes it fast. One of those is a foundation and the other is an optimisation, and it is worth being honest that event-triggered reconciliation plus a periodic repair pass dominates either mechanism alone. I did not build the webhook because an hour of latency costs nothing on work measured in hours. That is a judgement about this workload, not a law.
Push transports an occurrence. Pull reconciles truth.
This is emphatically not a claim that polling wins everywhere. High-volume streaming, fraud signals, anything latency-critical — different problem, different answer, and an hourly sweep would be malpractice. But code review is durable, inspectable and slow, and the work stays visible until it is resolved. That is an unusually good fit for periodic reconciliation.
And the metric people optimise here is the wrong one. It is not milliseconds from review request to process start. It is how long an eligible PR stays unattended, including after partial failure. On that number, self-healing beats instant.
Two models is not one model twice
The review itself runs two models on one branch — Claude Opus 5 and OpenAI Codex over the same diff, independently, consolidated into a single comment. Strictly these are two independently configured review systems rather than two bare models: each brings its own harness, prompting and tooling, and Codex in particular wraps a model that can change under me. That distinction matters for what the pairing actually buys.
Run one model twice and you get two different answers. But randomness is not independence. The same model carries the same training distribution, the same architectural tendencies, the same learned conventions and the same blind spots into both runs. Sampling variation changes the path. It does not replace the map.
Two different models are not perfectly independent either — they learned from overlapping public code and the same engineering culture. But their errors are less correlated, and less correlated is the entire product you are buying.
Which means the consolidation step has real work to do. It must not flatten two reviews into a polite average, and it must not treat a majority vote as proof. Shared findings, unique findings and conflicts carry different weight and have to survive into the final comment with their provenance attached.
The published work on adversarial multi-agent verification points the same way: layered independent reviewers catch injected malicious code at materially higher rates than a single reviewer does. Worth stating the claim narrowly, though — ensembling does not create an oracle. It reduces correlated error. That is a smaller and more honest thing to promise.
The transcript is part of the control surface
Everything in this loop leaves evidence. Slack holds the conversation trail and the maintainer's statement of intent. Linear holds the ticket comments that tie the change to planned work. The PR holds the diff, the findings, the revisions and the final state. And a full working log records every action taken, across both interactive sessions and headless autoship runs.
In a regulated context that is not overhead. It is the point.
An uninstrumented review, human or automated, records a conclusion. Files were scanned, architecture was recalled, something was run locally, a judgement formed — and what survives is "LGTM" plus four comments.
An automated pipeline is simply much easier to force into leaving the path: which commit was reviewed, which inputs were read, which tool calls ran, what each reviewer returned, how the feedback changed the code. One caveat worth stating plainly: model prose is not a record of model reasoning. An explanation can be post-hoc or incomplete. What you can trust is the action trail — versioned inputs, tool calls, outputs, decisions — not the narration wrapped around it.
A human workflow can be instrumented to the same standard. In practice, under time pressure, it usually is not.
And more logging is not automatically more auditability. Records need stable identities, timestamps, model and policy versions, links to exact commit SHAs, access control, retention rules, and a hard line between a generated summary and the underlying action record. On sensitive data the accurate framing is minimisation and authorisation rather than an absolute: regulated data can be processed by systems explicitly approved to handle it, under the contractual, access, retention and security controls that come with that. Our policy for this workflow is that it does not go near a prompt or a log — which is a project decision, not a description of what the law permits.
Where this breaks
An autonomous review loop can fail while looking extremely busy. These are the five I actively watch for.
And underneath all five, the oldest failure in automated controls: treating the existence of the gate as evidence that what passed through it is safe. A green check proves a configured process ran. It does not prove the process asked the right questions.
Humans still own the threat model, the critical-module boundary, the review policy, exception handling, model selection, access permissions and final acceptance of residual risk. They sample the output, challenge repeated agreement, study every defect that escapes, and rewrite the rules when production teaches something new. Moving the human out of the runtime does not move the responsibility out with them.
The gate got stricter and nothing slowed down
The assumed trade-off between review rigor and velocity is much weaker than it looks when a human is executing every state transition — noticing, context-switching, reading, commenting, waiting, noticing again, rebuilding context, repeating. In this workflow most of the elapsed time was not analysis. It was handoffs and unattended queue time. Deeper automated review is not free either: it costs wall-clock, it produces false positives, and the convergence loop can run long. It is a better trade, not a free one.
What changed here is which layer the humans operate at.
Over several days the same sequence repeated: a PR appeared, the hourly sweep found it, two independent reviews became one comment, his agents revised the code, a later sweep evaluated the new head. Slack could have gone dark after that first context message and the loop would still have converged, because no human was holding the state.
The critical module now gets materially more scrutiny than it did before we went live. Being honest about the evidence: this is days of observation, not a measured throughput study with a baseline and a sample size. What I can say is that we did not see the slowdown that a gate like this normally causes, which is the outcome the design was aiming at.
And what came out the other end was not just a merged pull request. It was a merged pull request with a versioned trail of how it got there.
Two Models, One Branch — the consolidated two-model review method this loop runs on.
The Review Is Automated — the Decision Isn't — where the line between automated review and human decision actually sits.
The Agent Without a Face — headless autoship runs, and why the working log matters more when nobody is watching.
My Agent Filed Its Own Ticket — the same pattern one layer earlier, in the tracker.
The Verification Gap — why generation outran verification in the first place.