
A coding agent can produce a plausible patch in a few minutes. A careful human review may take longer than writing the change used to take.
If every generated patch still needs line-by-line inspection, code generation has been automated but software delivery has not. The work has moved into the review queue.
I think the way out is to stop treating human inspection as the default proof of quality. Humans should define what good evidence looks like, then agents and deterministic tools should produce that evidence before a change can pass.
This is a narrower follow-up to my argument that quality has to become infrastructure. The question here is practical: what would have to be true before I was willing to accept agent-written code without reading it?
Review evidence, not implementation
In a conversation with Matt Pocock, Robert Martin describes working towards this exact goal. He wants agents to write and improve the code while he checks the surrounding evidence rather than the implementation itself.
The idea becomes concrete in the multi-agent section at 17:39. One agent implements a change, another reviews it, another attacks its tests, and a final agent proves the behaviour through the user interface. Each role gets a narrow task and a fresh context.
That separation helps, but another agent’s approval is still an opinion. The reliable part is the set of tools that can reject the work.
The decision should look like this:
Human defines intent and quality policy
|
v
Specifier -> implementer -> cleaner -> hardener -> QA
| | | |
+------------+-----------+--------+
|
deterministic gates
|
accept or reject
No agent can waive a failed gate. It can only change the code and run the checks again.
Give each agent one reason to reject the change
The roles in Martin’s pipeline are useful because they do not all optimise for the same outcome.
The specifier turns a human requirement into Gherkin scenarios and a QA procedure written from the user’s point of view. This gives the rest of the system an acceptance target before implementation begins.
The implementer writes the code and its first tests. Its job is to make the behaviour work, not to make the final claim about quality.
The cleaner starts in a fresh context. It receives the requirement and the diff, then looks for duplication, excessive complexity, missing tests and poor structure. Martin introduces the CRAP metric at 5:52. It combines cyclomatic complexity with test coverage to identify code that is both difficult and weakly tested. The original explanation of the metric is still useful.
The hardener tests the tests. Martin describes mutation testing at 6:50. It changes conditions and operators in the implementation, then checks whether the test suite fails. A surviving mutation shows that the tests executed the code without detecting the wrong behaviour. StrykerJS provides this for JavaScript and TypeScript.
The QA agent turns the written QA procedure into an executable system test. It drives the application through the same public interface a user would use and returns a normal process exit code.
The hand-offs matter. An implementation session develops assumptions as it works around failures. Reusing the same context for review carries those assumptions into the review. A fresh agent gets the requirement, the patch and its own reason to reject the change.
This is a useful exception to my usual preference for a single agent. The extra agents earn their coordination cost because each has different evidence and a distinct acceptance rule.
Put the quality policy behind one command
Agents follow long instruction files unevenly as their context fills. A failing command is harder to forget.
For a TypeScript web application with standard package scripts, a basic gate could start as a small shell script:
#!/usr/bin/env bash
set -euo pipefail
npm run lint
npm run typecheck
npm test
npm run test:e2e
The orchestration rule is simple: the agent has not finished until the script returns zero. A reviewer agent may explain the failure and a fixer agent may repair it, but neither can reinterpret a red build as acceptable.
That script is only a starting point. A mature gate can also enforce:
- unit and integration tests for the changed behaviour
- a minimum mutation score on affected modules
- coverage and complexity limits
- accessibility checks
- secret, dependency and static security scans
- allowed module dependencies
Architecture needs the same treatment as tests. A generated patch can pass every behavioural check while introducing a dependency from a low-level module back into the UI. A tool such as dependency-cruiser can express forbidden dependencies as rules and return a non-zero result when an agent crosses a boundary.
Once mutation and dependency tools have been installed and configured, they become more lines in the same gate:
npx depcruise src
npx stryker run
What matters is that every rule which can block acceptance has an executable result and stable output that an agent can act on.
Human attention moves to the quality system
Human responsibility moves to the quality system when routine code inspection disappears.
Someone still has to decide whether the acceptance scenarios describe the right feature. Someone has to set the mutation threshold, choose architectural boundaries and decide which failures require escalation. Those decisions are more valuable than checking another generated data mapper for naming and control-flow mistakes.
Human effort remains in a few places.
First, review intent before an agent starts. A perfect implementation of the wrong requirement is still wrong.
Second, audit a sample of accepted changes. If a spot check finds an issue, work out which missing test, rule or signal would have caught it and add that to the gate. The audit improves the system rather than repairing only one patch.
Third, keep mandatory human review for work where judgement cannot yet be expressed well enough. Authentication, permissions, billing, destructive migrations and changes to cryptographic code are poor places to begin an experiment in unattended acceptance.
Do not confuse coverage with confidence
It would be easy to turn this approach into a dashboard full of reassuring numbers.
One hundred per cent line coverage does not prove that assertions are useful. A low complexity score does not prove that module boundaries make sense. Five agents can repeat the same misunderstanding if the requirement is ambiguous.
That is why the checks need to disagree with one another in useful ways. Acceptance tests check requested behaviour. Mutation testing checks whether the tests notice broken behaviour. Dependency rules check structure. Browser tests check the system through a public interface. Production monitoring then checks assumptions that escaped all of them.
The measure I would watch is escaped defects per accepted change, split by risk class. I would also record how often a human audit finds a material problem. Agent count, generated lines and review comments say little about whether the system is safe enough to trust.
At 22:29 in the interview, Martin reports that his full sequence can turn a five-minute agent task into roughly an hour of automated work. He compares that with about half a day of human work. That is an anecdote from his own projects, not a general benchmark, but the direction makes sense. Agents spend more compute so humans spend less attention.
Start with a bounded trial
Pick one low-risk class of change, such as content edits, isolated UI work or a well-tested internal tool. Create one required verification command. Give implementation and review to separate agent sessions, then reject completion unless the command passes.
Run that process for 20 changes. Audit a sample, record escaped defects and add a gate for each repeatable failure. If the evidence remains weak, keep human review. If the audits stay clean, widen the unattended scope by one risk class.
Keep engineers close enough to the code that somebody still understands it. The experiment succeeds when the team can stop reading every generated line while still catching defects before release.