← The archive Dispatch

Article · Field notes

The Person Looking for the Lie

18 Jun 2026 9 min read

The Person Looking for the Lie

Recently I saw a couple of devs deliver a huuuuge PR. And when I say huuuuge, I mean GitHub started behaving like I had asked it to render a Pixar movie in the browser. Roughly 200k changed lines.

Can you imagine reviewing that?

I tried. My 8-core Mac tried. The diff opened, paused, thought about its life choices, and then began coughing up chunks of files in no particular hurry. Somewhere around the point where I was scrolling through generated-looking tests for code I had not read, my review turned into one question:

Can the person who gave me this PR explain wtf is going on here?

If the answer is no, the review is theatre. It doesn’t matter that the tests are green. It doesn’t matter that the code is formatted. A change that large has already escaped the part of the process where a human can hold it in their head.

For changes like that, I want a different kind of review comment. Not “looks good.” More like: I tried duplicate submits, bad permissions, retries, timeouts, weird inputs, and missing product rules. Here’s what broke. Here’s what I still don’t understand.

KC Green's Question Hound sitting in a burning room and saying this is fine.
Sometimes green CI is just Question Hound with a coffee mug. Comic: On Fire by KC Green.

Clean code can hide an unreadable change

The old failure mode was a tired human making a mistake. Another tired human might catch it. Review worked, some of the time, because both people were operating in the same messy human way. You could see the scar tissue in the code. A weird variable name. A half-finished abstraction. A branch that smelled like someone changed their mind at 11pm.

The new failure mode arrives pre-tidied. Names, formatting, tests, commit message, the little paragraph explaining why the approach is sound. The agent gives you the code and the alibi in the same box.

So you skim. Of course you skim. The PR is too large, the tests are green, the commit message sounds reasonable, and nobody wants to be the person blocking “velocity” because their laptop is hot and their stomach feels weird.

But sometimes the tests pass because they share the same blind spot as the code. The agent writes the case it can imagine passing. Then it writes the implementation that passes that case.

This is the QA engineer walks into a bar joke in expensive clothing. He orders a beer. Orders zero beers. Orders 99,999,999,999 beers. Orders a lizard. Orders -1 beers. Orders gibberish. Everything looks covered. Then the first real customer walks in and asks where the bathroom is, and the bar catches fire.

The test suite proved the bar could handle weird beer orders. It did not prove the bar could run as a bar.

Someone squints at the order of operations and calls this TDD. Or, because we apparently need a new term every time a loop gets worse, agentic test-driven development. Huiiii. Real TDD lets the test put pressure on the design. This is the implementation writing its own alibi. The bug and the test shake hands and walk into your main branch together.

xkcd Code Quality 2 comic comparing unreadable code to a burning bus.
Old bad code had the courtesy to look like a burning bus. The agent version can park the same bus inside tidy abstractions. Comic: xkcd Code Quality 2, CC BY-NC 2.5.

The example from my own blog

In this blog, there is a post called Noah’s Daily Exercises. The goal is practical: generate exercises for Noah and Lara using an LLM. Maths, quizzes, drawings, creative writing, little physical challenges, all the stuff that makes a morning worksheet feel less like a photocopy from 1998.

The app only exists because I did this manually for a long time. I used to draw these worksheets by hand before school. Lovely when I had time and coffee. Less lovely when I had neither and still needed maths problems, a drawing prompt, and something vaguely educational that didn’t bore everyone to death.

So yes, using an LLM here makes my life easier. This sounds great BUT, as this little app grows inside the blog, a few product problems start popping up. One of them is not a code bug at all.

Imagine I ask an agent to add a “make today’s worksheet” button. The PR is small. The UI renders. The API calls return data. The tests check that the sections appear. Nice little change. Exactly the kind of thing I would approve too quickly if I were tired.

Here’s roughly what it does:

Click the button -> call the math, words, physical exercise, sketch, and challenge generators, then render the returned sections. Any refresh asks for a new sheet. Store nothing.

The button works. That is the trap.

First, I just created a reroll machine. The promise was “today’s worksheet.” The implementation says “keep refreshing until the maths looks easy and the physical exercise isn’t the one you hate.” No attacker required. A kid with a browser and a perfectly rational interest in doing less work is enough.

Second, the difficulty rules are vibes. Age nine. Times tables to five. Safe bodyweight exercises. Short hints. No equipment. All of that sits in prompts and helper code and the general intent of the thing. If the generator returns long division, twenty burpees, or a writing prompt that needs an adult parked beside him for forty minutes, the JSON can still be perfect. Perfectly wrong, but perfect.

Third, the sections don’t live in separate universes. Maths, words, physical work, sketches, and challenges might each look fine alone. A real morning doesn’t work like that. Ten hard maths problems plus a demanding writing hook plus a physical block after surf practice is a bad worksheet. The agent built five tidy boxes. I need one kid’s morning.

None of this shows up as a syntax error. None of it looks dramatic in a diff. The code works. The product behavior is wrong.

My red-team pass is three annoying questions

When I red team an agent change, I don’t start with “is this elegant?” I start with three more irritating questions.

What did it not imagine?

The empty list. The Unicode name. The kid who refreshes twice. The parent who opens the worksheet after a hard surf session and gets a monster set of exercises. Agents are pretty good in the middle of the input space. They get weirdly casual at the edges. I try to live there for twenty minutes.

What did it not build?

The daily lock. The difficulty cap as an actual rule, not a wish in a prompt. The parent review step. The timeout. The boring guardrail nobody added because the happy path was already green. Missing things don’t appear in a diff. You can’t comment on the line that isn’t there.

What did I mean but fail to say?

This one hurts because it’s usually my fault. I said “generate today’s worksheet.” I meant “generate one age-appropriate worksheet that a parent can commit to for the day.” The agent optimised for the words. The red teamer has to recover the meaning.

Concrete takeaway: your red team checklist

Under a risky PR, I want a comment like this:

I attacked: duplicate submits, retries, bad permissions, weird inputs, missing product rules, and whole-flow behavior.

I found: unlimited worksheet rerolls, difficulty rules living only in prompts, and no check for total load across maths, writing, and physical work.

I still don’t understand: whether “today’s worksheet” means one committed sheet per day or infinite generation until the kid likes the result.

If you can’t write that comment, you probably didn’t red team it. You skimmed it. Which is fine for a CSS tweak. It is not fine for a change where the blast radius is bigger than your attention span.

My checklist looks like this:

  • Explain the change in one sentence without rereading the PR description.
  • Run the duplicate-click, refresh, retry, and come-back-tomorrow paths.
  • Write down what the tests proved.
  • Write down what the tests avoided proving.
  • Find every rule that only exists in a prompt, comment, ticket, or someone’s head.
  • Try one bored-user path, one angry-customer path, one retrying-client path, and one bad-clock path.
  • Check that production failure would show up before a human complains.
  • Write down the risk being accepted because fixing it now is not worth it.

Red teaming is allowed to end with “ship it.” I don’t want every reviewer cosplaying as a corporate risk committee. In this case it’s my blog, so yes, I have to red team myself, which is a bit schizophrenic. But if I decide the worksheet can reroll forever for now, or the difficulty cap can stay in the prompt for another week, I want that written down in normal language.

The scanner won’t find “this teaches Noah to refresh until the worksheet is easy.” The agent won’t feel embarrassed that it generated the tests and the bug from the same blind spot. Somebody still has to look at the thing and say: I don’t buy it yet.


Want to chat? X / LinkedIn