Why AI Review Needs a Stopping Rule
One of the core ideas behind OpenOrc is that a coding agent should not review its own work.
I use one model as the Producer and another as the Reviewer. The Producer plans and implements. The Reviewer independently attacks the plan and the resulting pull request.
That pattern has worked extremely well for me.
It has also taught me something I did not expect:
an AI Reviewer needs to know when to stop.
Not because review should be shallow.
Not because edge cases do not matter.
But because a sufficiently capable model can always find another possible objection.
There is always another race condition.
Another hypothetical failure mode.
Another abstraction that could be made more robust.
Another future requirement the design could anticipate.
If every plausible improvement becomes a blocking review finding, the review loop has no natural termination condition.
The loop was working too well
We ran into this while reviewing an OpenOrc backend task.
The early review rounds were useful. The Reviewer found genuine architectural mistakes. The Producer revised the plan. The Reviewer found another real problem. The design got better.
This is exactly why I use an independent Reviewer.
But eventually the character of the findings changed.
The important defects had been fixed. New findings started drifting toward increasingly remote concurrency scenarios and defensive mechanisms that were technically interesting but not necessary to satisfy the task’s actual contract.
Nothing was obviously wrong with the reasoning.
That was the problem.
The Reviewer was still doing exactly what we had asked:
Find problems.
And with enough reasoning capability, there is almost always another problem you can imagine.
At some point the review had stopped asking:
Does this design correctly implement what we need?
and started asking:
Can I imagine an even more defensible design?
Those are not the same question.
“Good enough” is part of engineering
“Good enough” can sound like a euphemism for lowering standards.
I think the opposite is true.
A useful engineering review needs to distinguish between:
material defect
→ must fix
reasonable tradeoff
→ may ship
possible improvement
→ follow up later
Human reviewers do this constantly.
A pull request may contain things they would personally design differently. It may have edge cases worth discussing. There may be robustness improvements that would make sense eventually.
That does not mean every observation should block the merge.
The reviewer’s job is not to prove that no better implementation exists.
It is to decide whether the implementation is safe and correct enough to cross the next authority boundary.
For an AI Reviewer, that threshold needs to be explicit.
We changed the Reviewer contract
Our original project instruction was mostly about protocol: when reviewing OpenOrc artifacts, return a structured ACCEPTED or CHANGES_REQUESTED result.
What it did not define clearly enough was what deserved CHANGES_REQUESTED.
So we added a stopping rule.
The important part is essentially:
Request changes only for material problems that should block implementation or merge: violations of requirements, incorrect architecture or semantics, security or isolation failures, data-integrity problems, broken authority boundaries, or concrete defects likely to cause incorrect behavior.
And just as importantly:
Do not prolong review for speculative edge cases, hypothetical future requirements, stylistic preferences, marginal robustness improvements, or implementation details that can reasonably be resolved during implementation.
The sentence that matters most is:
Judge the work against its actual required contract, not against a theoretically perfect design.
That gives ACCEPTED a real meaning.
Without a stopping rule, acceptance quietly means:
The Reviewer can no longer imagine another objection.
That is an impossible standard for any non-trivial system.
The Reviewer did not become weaker
The useful test came immediately afterward.
The Producer implemented the task and opened the pull request.
The Reviewer inspected the actual code and found two real defects.
Both were narrow implementation bugs involving how GitHub responses were being interpreted.
Both could cause the system to behave incorrectly in production.
The Reviewer requested changes.
The Producer fixed them and added regression tests.
The Reviewer checked the revised pull request again.
Then it returned:
{
"outcome": "ACCEPTED",
"findings": []
}
That is the behavior we wanted.
The new stopping rule did not make the Reviewer less critical.
It made the criticism better targeted.
It still blocked real defects.
It simply stopped treating every conceivable improvement as a reason to continue the loop.
Review is not theorem proving
This feels like a broader lesson for agentic software development.
We spend a lot of effort making agents more capable:
- stronger models;
- larger context windows;
- better tools;
- independent reviewers;
- longer-running sessions;
- richer repository access.
But more capability does not automatically produce better workflow behavior.
A Reviewer that misses obvious bugs is bad.
A Reviewer that can always invent another reason not to approve the work is also bad.
The purpose of ordinary engineering review is not to prove the absence of all possible defects.
It is to establish enough justified confidence to continue.
That means review needs two kinds of bounds.
A mechanical bound answers:
How many times may this loop run?
A semantic bound answers:
What kind of problem is important enough to justify another round?
The second one is easier to overlook.
It may also be more important.
Adversarial agents need termination criteria
The lesson probably extends beyond code review.
Any agent whose job is adversarial or evaluative can become pathological if its objective is simply to keep finding objections.
Security review.
Architecture review.
Compliance.
Research criticism.
Planning.
Decision support.
A capable evaluator can nearly always identify another uncertainty, another assumption, another thing that could be made safer.
At some point it needs a decision threshold.
Otherwise additional intelligence produces additional hesitation.
For OpenOrc, the change was simple:
the Reviewer is responsible not only for finding problems, but for deciding when the remaining problems are no longer material enough to block progress.
That sounds obvious in hindsight.
A surprising amount of engineering does.