Back to blog

We Planted the Same Bug in Two PRs. The Human-Written One Got Grilled — the Agent's Sailed Through in Under a Minute

Sep 12, 2026
Series · Day 8
Software Engineering in the AI Era
View all lessons →
We Planted the Same Bug in Two PRs. The Human-Written One Got Grilled — the Agent's Sailed Through in Under a Minute

Day 8 — Why Your HITL Review Gate Isn't Catching What You Think It Is

Ask any engineering manager if they have a human-in-the-loop gate on agent-generated PRs, and they'll say yes without blinking. Ask what it actually catches, and watch the blinking start. Almost everyone can point to the gate. Almost nobody can show you its catch rate. That gap is the whole problem, and most teams have never once measured it.

The stopwatch story

We ran a deliberate test: same planted bug, two PRs. One from a junior engineer, one from an agent. The junior's PR got the full treatment — questions about edge cases, a request to add a test, someone asking 'wait, what happens if this list is empty.' The agent's PR, carrying the identical defect, got approved in under a minute. Same bug. Same risk. Wildly different scrutiny. The only thing that changed was who — or what — the diff looked like it came from.

The agent's code was clean: consistent naming, a tidy commit message, no stray whitespace, a docstring exactly where you'd expect one. None of that had anything to do with correctness. All of it had everything to do with trust. And trust is what bought the fast approval.

Name the mechanism

Reviewers under time pressure don't re-derive correctness from first principles on every PR — nobody has the hours for that. They pattern-match: does this look like something a careful, competent person wrote? Formatting, naming conventions, commit hygiene, confident phrasing in the PR description — these are the proxies reviewers lean on, consciously or not, to decide how hard to actually look.

Agents happen to be extremely good at producing exactly those proxies. They don't get tired, don't leave TODOs out of laziness, don't drift in style halfway through a diff. The exact signals humans use to grant trust are the signals agents generate most reliably — regardless of whether the logic underneath is correct.

Why this inverts the safety promise

The whole premise of human-in-the-loop is: a human catches what the model missed. That only holds if scrutiny stays roughly constant, or ideally scales up with risk. What actually happens is the opposite — scrutiny scales inversely with how polished the output looks. Agent output tends to be the most polished and the least independently verified. It was generated, not hand-built and second-guessed by an author the way a junior's nervous PR usually is.

  • A junior's messy PR gets scrutiny it may not even need, because the messiness signals 'check me.'
  • An agent's clean PR gets a rubber stamp it hasn't earned, because the cleanliness signals 'trust me.'
  • The gate is weakest exactly where the failure mode is newest and least understood — confidently-wrong agent output.

The reframe

Stop asking 'where do we put a human checkpoint.' That's a process-design question, and you've probably already answered it — pre-merge review, staged rollout, whatever your flavor is. The question that actually matters is an audit question: do we have any evidence our humans are catching anything at all? A checkpoint that exists but never rejects, never overrides, never disagrees isn't a safety mechanism. It's theater with a sign-off button.

The concrete lever: log the disagreement, then grade it

You can't manage what you don't log. Every time a human changes, blocks, or overrides agent-generated output, record it as a structured event. Later, go check who was actually right — did the override catch a real bug, or was it a stylistic nitpick? That one loop turns 'we have a review gate' from a claim into a measurable catch rate, sliceable by reviewer, by repo, by agent, by task type.

json
{
  "event": "reviewer_override",
  "pr_id": "1842",
  "reviewer": "cong.chi",
  "agent_id": "claude-code-run-9f3a",
  "repo": "phoenixdx/billing-service",
  "override_type": "block",       // block | change_requested | silent_approve
  "diff_size_loc": 34,
  "reason": "missing null check on refund path",
  "resolved_outcome": "true_positive",  // true_positive | false_positive | unverified
  "timestamp": "2026-09-10T14:22:00Z"
}

Aggregate that over a month and numbers show up that you didn't have before. Say it shakes out like this: reviewer A blocks 1 in 40 agent PRs and is right 90% of the time; reviewer B blocks 1 in 400 and is right 20% of the time. Your actual ratios will land wherever they land, but the point doesn't change — that's not something to wave off as a training gap. It's a measured hole in your safety net, and now you know precisely where to look.

Breaking the trust-by-appearance trap

Logging overrides only tells you about the PRs someone chose to scrutinize. It says nothing about the clean-looking ones that sailed through untouched — which is exactly the blind spot this whole lesson is about. The fix is to take the choice away from the reviewer: stop letting them decide which diffs deserve a deep look.

  • Force blind, random deep-review sampling on a fixed percentage of agent PRs, chosen before anyone reads the diff — not the ones that 'look risky.'
  • Occasionally plant known bugs into otherwise-clean agent PRs (as in the stopwatch test) to measure actual catch rate, not perceived rigor.
  • Rotate which reviewer gets the sampled PRs so catch rate isn't just measuring one person's diligence.
  • Report catch rate on the sampled set separately from catch rate on self-selected reviews — the gap between the two is your trust-by-appearance tax.

A human in the loop who isn't measured is just a liability signature — a name on the approval that makes the org feel covered without a shred of evidence the coverage does anything. The design question for the rest of this series isn't how many checkpoints to bolt on. It's how to make the attention you're already paying for actually worth its cost.

Flashcards
Check yourself

Extend your knowledge

  • Pull a sample of your last month's merged agent PRs and manually check: how many got a substantive comment vs. a same-day approval with no comments? That ratio is your baseline trust-by-appearance signal.
  • Set up the override-logging schema above in your PR tooling (a GitHub Action or webhook is enough) before you add any new review process — you can't fix what you haven't measured.
  • Search for published industry research on code review metrics at scale — review latency, comment density, review depth — and adapt similar instrumentation to separate agent-authored from human-authored PRs.
  • Read up on 'automation complacency' / 'trust calibration' research from human-factors and aviation safety literature — the polished-output-gets-less-scrutiny pattern predates LLMs and has a body of study behind it.
Test yourself on this lesson

Discussion

Chat with Chi Cong (AI) about this article. Your conversation is private to you — you can publish a summary for others when you're done.

Ask me anything about “We Planted the Same Bug in Two PRs. The Human-Written One Got Grilled — the Agent's Sailed Through in Under a Minute” — trade-offs, decisions, or the story behind it.