Skip to content
· 6 MIN READ · SOFTWARE ENGINEERING · AI · DEVELOPER EXPERIENCE

The Second Test Suite

A sentence of English stopped a line that would have erased my content. My own attention only catches what a screen can show.

This repository has no test framework. It has never had one, and it has still caught more of my mistakes than any project I have written tests for.

I have written more consequential English in this project than TypeScript. Not documentation — nobody reads it as documentation. A file of rules, in prose, that gets enforced on work I am not watching, at a level of detail I could not sustain by reviewing. It is the highest-leverage artefact in the repository and it is not code.

A seed script in this project was about to grow a line reading body: project.body ?? null. It looks like a default. What it does, on every run of yarn db:seed, is overwrite every hand-written project writeup with nothing.

It never ran. What stopped it was not a test, because there are none. It was not review, because I never saw the line — it existed for about a minute, between being written and being rewritten. It was a sentence in the rules file, ten days old, a rule I had set and the agent had written down while building the thing the rule describes:

It does not delete, so it will not eat rows created through the dashboard.

The agent read its own note back, checked the line it was about to add against it, and stopped.

That sentence is not unusual. It is one line of the second of three layers, and the three are worth separating because they fail differently.

  1. yarn verify — three suites, about a hundred and seventy checks, covering everything a machine can assert. A forged session cookie is refused. No form is nested inside another. Two rows never share a position. A reorder does not move updatedAt.

  2. CLAUDE.md — everything a machine cannot. A stale NOW block is worse than none. Position is not content. Mono means data. No invented statistics. A missing value is an em dash, not a plausible sentence.

  3. My eye. The last resort.

Layer one cannot express taste. Layer three does not survive a long afternoon. Layer two is prose, and it is the only one of the three that scales to work I am not watching.

Layer three earns its place, and the way it earns it is stupid.

Eleven words, typed while looking at a screen: "on project edit page, selecting categories does not have any indicator." That was my entire contribution. What it turned out to be was every filter chip in the application carrying a selected state that did nothing at all — four of them, in four files: the project editor, two admin lists, and the public work grid.

The cause is a cascade rule almost nobody has needed to know. The design system's classes are plain, unlayered CSS. Tailwind's utilities live in @layer utilities. Unlayered CSS beats layered CSS no matter how specific the layered rule is — so bg-foreground on a selected chip lost, silently, to the class's own background: none.

A selected chip and an unselected one computed to the same value: rgba(0, 0, 0, 0), both. It had shipped, and it had passed review, because there is nothing in a diff to see. The code says bg-foreground and it means it.

I found it by saying a sentence a five-year-old could have said. The agent found the cause in about a minute once it was pointed at it. Neither half of that was optional.

Except that layer three has a shape, and the shape is not flattering.

Everything I caught was visible. A chip with no selected state. A page that had drifted from the design. A whole case-detail page that was simply missing. A cover restating the title of the page it sat on. All of it found the same way: by looking at a rendered screen and saying a plain sentence about it.

Everything I missed was invisible mechanics. The seed line is the example that got close enough to matter — a default that reads as a default and behaves as a delete.

That is not a lapse I can fix by concentrating harder. It is a property of eyes. A rendered page is the only artefact I review at full attention, and a whole class of mistake never appears on one.

Which is what the second test suite actually is. Not insurance, not documentation, not a style guide — the layer that covers precisely what a person looking at a screen cannot see.

The version of this era I keep reading has the engineer prompting and merging. That is not the trade.

The typing did shrink — genuinely, and more than I expected. What replaced it was not free time. It was checking: the logic, the interactions, the edge cases, whether the thing that was built is the thing that was meant. More time, not less.

The other half of the trade is stranger and nobody mentions it. Planning got cheaper. Describing what I actually want, in detail, before anything exists, used to be a tax paid against a slow build — you could think for a day and still wait a week. Now the build is the fast part, so thinking in detail up front is the cheapest move available.

So the work did not shrink. It moved to the two ends and left the middle: intent at the front, verification at the back, and a rapidly filled gap between them that I no longer type by hand.

Which leaves the question the title was avoiding.

My own instinct was that this makes me a product owner: thinking in product rather than in code. Right instinct, wrong word. A product owner sees the visible, and I was good at that here — but a product owner would not know that ?? null in a seed script eats content, or that a reorder must not touch a timestamp the site derives its freshness from, or that an unlayered class beats a layered one. None of those are product judgements. They are the reasons layer two has anything in it, and only someone who can read the code knows to write them down.

So: product thinking chooses what to build. The engineering is knowing what will quietly go wrong, and saying so in advance, in English, in a file something else will read.

Every rule in layer two started as something that went wrong once. Which means the file is not a style guide. It is a list of things I have already paid for.