The agent says it shipped. Prove it.
Every signal we call verification proves something narrower than its name. The discipline is knowing which rung you stopped on, and saying so.
The sequence below is composite, assembled from a pattern we have hit enough times to treat as a failure class. An agent finishes a task and writes the line we have all been trained to relax at: change made, checks pass, shipped. The diff exists, the types check, the build went green, and the commit is on main. And the page a person loads is the page they loaded yesterday.
Nothing in that report is a lie, which is what makes it expensive. The agent described the work it did, accurately, and that work is the one thing in the pipeline it can observe directly. The claim that the change was made and the claim that a person using the product gets the new behavior are two different claims, and between them sits a chain of steps that can each go wrong without surfacing an error the agent can see: a compile that succeeds, a deploy that never becomes the live one, a cache that keeps answering with yesterday's data.
An agent's account of its own work is the least reliable artifact in the pipeline, for structural reasons that have nothing to do with honesty. The agent sits at one end of the chain with perfect visibility into its own actions and none at all into the end state, and it is asked to summarize both. A human engineer who edits a file, runs the tests, and says done is making the same inferential leap.
The plausible pass
Crashes are the cheap kind of wrong: loud, traceable, self-reporting, fixed quickly because nobody can ignore them. The expensive kind is the change that passes. It compiles. The suite is green. The agent reports success and moves to the next task. And the feature sits inert in production until a person happens to look. A crash is fixed the day it happens. A pass like this one goes unnoticed while the team starts on something else, assuming the change is live.
Each signal in that chain proves something narrower than its name suggests, and we habitually credit it for the thing we actually wanted to know. What follows are three failure classes we have hit. They are written as classes because the case files are not ours to publish. The first: a change clears every local check and then fails every deploy that follows, because the platform enforces a constraint on the shape of the code that the local checker was never asked about.
The second class is watching a signal that merely correlates with success instead of the state of the thing itself. A line in a build log that usually appears when a deploy works is not the deploy working. We have sat through a production incident with a watcher reporting healthy the entire time, because it was reading a symptom rather than the deployment's own status. The remedy: read the deployment's own state, which either says READY or does not, instead of grepping for the log line that usually comes with it.
# correlates with shipping
grep 'build succeeded' build.log
# observes shipping
deployment.state == READY
-> GET <production url>
-> assert the new behavior is in the response
-> record which path was checkedThe third class is the one where the code really is live and people still do not see it. A caching layer between the database and the page can serve a day-old read across deploys, which makes "the new code is running" and "the new data is on screen" two separate facts, verified separately or not verified at all. This class is hard to catch because every step below it reports honestly. The live deployment contains the new code, and the page still shows yesterday's read.
Every rung costs more and proves more
- The type check: this file is well formed.
- The build: the bundle compiled.
- The deployment's own state: this particular build is the one serving traffic.
- A request to the production URL: the server answers, with the right status.
- The page rendered as a real user, in their session and their state: the thing is actually there.
We used to state that top rung as the definition: verification means observing the end state a user would see. That was an overclaim. Observing one URL once, as one user, does not establish that a change works across users, sessions, regions, caches, permission levels, or a week from now. It establishes that the change is present and behaving on the single path we walked, and nothing about any other path.
Three questions get run together, and most arguments about verification turn out to be arguments about which one someone meant.
- Release presence: is this build the one serving traffic? The deployment's own state answers this, and answers it completely.
- Functional correctness: does the change do the right thing for the people who meet it? The production walk-through answers it for one path; a test suite answers it for the paths somebody thought to write down.
- Ongoing health: is it still true an hour from now, under load, for a user whose session, region, and cache differ from ours? No rung on the ladder answers this. Monitoring answers it, or nothing does.
Most changes do not need the whole ladder. The report has to name the rung the work stopped on rather than let a reader assume the top one. How high a change climbs is a risk judgment made before the work starts, from blast radius and whether a silent failure would be noticed by anyone outside the team. A copy tweak on an internal page stops at the build. Anything touching payment, auth, or the first screen a new player sees gets walked in production.
Verification capacity sets the ceiling
The commercial version of this problem is throughput. In this studio, verification capacity is what sets how much change the team can absorb. A team running agents in parallel can produce more change in a day than the same team can responsibly read in a week. Review is the slow part by construction: a person has to reload the context the agent already had, then decide. If every agent output requires a human read before it counts, throughput is whatever those humans can read, however many agents are queued behind them. You can buy far more generation than you had and get none of the speed.
Automated verification is what breaks that ceiling. A wrong change caught by a machine at machine speed costs a retry instead of an hour of somebody's attention, and attention is the scarce input. Teams without that harness throttle their agents down to human reading speed, which erases the advantage they just paid for. We treat the harness as capacity infrastructure, in the same category as CI runners or a staging environment. It is invisible in the product itself, and it sets the ceiling on how much change the organization can absorb per day. Every hour spent making it cheaper to run raises that number.
The rule we hold across the studio: nothing counts as shipped until the production URL has been observed doing the thing, by a person or by a script behaving like one, and the report names the path that was checked. The agent's report is one input to that check. This has caught changes where every lower check passed and the production behavior never appeared, and it is also how we split the reading. Routine work merges on the harness alone, with nobody reading the diff: a fix inside behavior that already exists, a copy change, a dependency bump. Changes that set what the product does, what it charges, or who can see it get a human hour anyway, because a change that merely works is not yet a change worth keeping. The harness buys back the attention those changes need. What the check establishes is narrow: the change is present on the page at the URL somebody walked.
More from the notebook →