In the previous post I gave an AI a complete plan for an application and said
nothing about how to build it. What came back ran perfectly and scored four out of nine on the
qualities of quality code: no tests, no architecture, no type
checking worth the name, a rating column that would happily store the word oops.
I then did it again. Same plan — the identical file, not a rewritten one. Same AI. Same afternoon.
I added one short brief (a set of instructions), and the three guides it points to.
What was added, and what was not
The brief I added did not describe the application. It added no features and changed no requirements. Both runs were told exactly the same thing about what to build.
What it added was how. Five demands, and none of them is about the book-review app from the last post:
- Read the guides before writing code, and obey them. Three documents: one naming the qualities that make code quality, one of language-agnostic rules, one for the specific language and framework in use.
- TypeScript, everywhere. Front end and back end both — so the contract between them can be shared rather than duplicated and left to drift.
- A named architecture, chosen before the first file. Not "organize it sensibly" — pick a pattern, structure the whole application by it from the start, give every module a defined public API that the rest of the code must import through, and enforce it with a linter rather than discipline.
- Tooling before features. Get the type checker, formatter, linter and test runner green on an empty repository, and structure the server so a test can build it on its own: a function that takes the database as an argument and returns the app without listening on a port. Each test then creates a fresh in-memory database, sends the app real HTTP requests and checks the responses — so the first feature already has API tests, instead of tests being bolted on after the code exists.
- A definition of done that has three parts. A feature is not finished when it works. It is finished when it is clean, documented and tested — and it has to build and run as the production bundle, not just under the dev server.
That is the entire intervention: one page of how, plus the three guides it points to, handed over at the same moment as the plan.
Why I am not publishing mine
The three guides those five points refer to are ours. They took years to accumulate, they encode decisions we argue about internally, and they are not going up on the internet — at least not yet.
This matters less than it might seem, and I want to be direct about why rather than leave it looking like a withheld punchline.
The guide is not the mechanism. Having one is. Nothing in the result below depends on our
particular opinion about type versus interface. It depends on the AI being handed a written
statement of how code must be built, before it built any — and on that statement being specific
enough to check. Your version can disagree with ours on every technical point and produce the same
jump in quality.
And you already have the part that is hard. The nine qualities are published, in full, deliberately framework-agnostic and free. That is the lens — what to demand and why. The rules underneath it are the easy half: they are your team's existing opinions, which you already hold and have probably already argued about. Writing them down is an afternoon.
So: take the nine qualities, write your own five demands against them, hand them over with your next plan, and see what changes. That is a better outcome than copying mine, because a guide you wrote is a guide you will actually enforce.
What came back
Start with the shape, because it is visible before you read a single line.
The unguided run produced this — a flat pile grouped by technical role, every page reaching directly into a single file holding all twenty-three endpoints:
The guided run produced this:
Every slice there has one public entry point, imports only ever point in one direction, and a linter fails the check if either rule is broken.
Same requirement. Same AI. One brief's difference.
The same requirement, written twice
The tree tells you about one quality. The interesting part is what happened inside the code, where the two runs were solving identical problems.
Validating a rating
The plan says a rating is an integer from 1 to 5. Unguided:
Guided:
The first checks the range of whatever showed up. The second says what a rating is — a number,
whole, between one and five — and rejects anything that is not, before it reaches a query. The word
oops from the last post dies at the door here, along with "3abc", 2.5, true and everything
else that slipped through the first version.
It is also worth noticing that the second is shorter. Quality did not cost verbosity; it cost knowing that input from outside must be validated at the boundary — which is exactly the sort of thing a guide says and a plan does not.
Deleting something
Unguided:
Fire and forget. No confirmation, no pending state, and — because RTK Query's trigger does not reject unless you unwrap it — a failed delete is silently swallowed and the user believes it worked.
Guided:
Three things can happen after a click, and each one is handled. The user declines the confirmation, and nothing happens. The delete succeeds, and the caller moves on. The delete fails, and the user sees a message and can try again; while the request is running the button is disabled, so it cannot be submitted twice. The first run had one path: the one where everything works.
The component owns that interaction — ask, wait, report failure — and nothing else. It knows nothing
about what is being deleted. The caller passes onConfirm, which says what deleting means here:
which mutation to call and where to go afterward. That is separation of concerns, and the payoff is
that the interaction is written once and every delete in the application gets all three paths,
instead of each screen deciding for itself whether to handle a failed delete.
Nothing here is clever. That is the point. It is the boring, complete version of a thing the first run did in one line.
The scorecard
Both applications, both reviewed against the same nine qualities, by the same procedure:
| # | Quality | unguided | guided |
|---|---|---|---|
| 1 | Beautiful and pleasant | ✅ | ✅ |
| 2 | Follows standards | ❌ | ✅ |
| 3 | Modular | ⚠️ | ✅ |
| 4 | Bug-free | ⚠️ | ✅ |
| 5 | Finished | ❌ | ✅ |
| 6 | Clean | ⚠️ | ✅ |
| 7 | Documented | ⚠️ | ✅ |
| 8 | It works | ✅ | ✅ |
| 9 | Tested | ❌ | ⚠️ |
Four out of nine becomes eight and a half. The one remaining gap is test breadth on the client: the server has 17 integration tests running against a throwaway in-memory database, covering the 400s and 404s as well as the happy paths — but only two front-end components have tests of their own, five tests in total. They establish the pattern and stop. I left the mark honest rather than rounding it up.
Now look at the row where the two columns agree.
Both score full marks on "it works." Both applications run. Both build. Both do what the plan asked. If your acceptance test is a demo, these two are indistinguishable — and one of them is code you would send back.
That row is the argument of this entire series compressed into one line. It works was never a proxy for quality. It is one of nine, it happens to be the one you notice first, and it is the one the machine gives you for free.
Being honest about the experiment
Three things a careful reader should hold against this, stated here rather than left to be found.
The guided run was shown the standard it would be graded against. The guides it was told to read include the one naming the nine qualities. You can call that teaching to the test, and you would not be wrong. But that is the mechanism, not a flaw in measuring it: the finding is that writing the standard down and handing it over is what makes it happen. A bar nobody stated is a bar nobody hits. The unguided run was judged by the same nine and was never told them — which is precisely the situation most code is written in.
One added brief does not mean one difference. The two applications differ in dozens of ways: the guided run got a shared package used by both backend and front end, a layered backend and a sliced front end, all because the brief demanded them. But the plan did not change, and neither did the AI. The only input that differed was the brief and the guides it points to, so that is where I look for the cause.
One plan, one model, one application, one afternoon. An illustration, not a benchmark. I have not run this ten times across five models, and if I had, this post would say something more careful. The gap is wide enough that it does not need overstating.
What the brief actually cost
Here is the part that decides whether any of this matters in practice.
Writing that page of demands took under an hour. It is not specific to the book-review application — there is nothing in it about authors, ratings or SQLite. It applies unchanged to the next project, and the one after that. It is bounded work, done once, reusable forever, and it gets better every time something goes wrong and you add a line.
It is cheaper to say it up front than to fix it later. Skipping the guide does not save that hour, it moves it: the same decisions get made one review comment at a time, against code that already exists — and then made again on the next project, because nobody wrote them down. They also get harder. Giving a flat pile an architecture is a rewrite. Adding tests to code that was never built to be tested means rebuilding it first. Every gap in the unguided version was cheaper to prevent with one sentence in the guide than to fix afterwards.
That asymmetry is the whole economic argument, and it did not arrive with AI — it is the same trade that has always separated code you can live with from code you can only replace. What AI changed is the speed at which you reach the consequence.
You decide how the wall is built; it lays the bricks. Deciding was always the real job.
The plan says what to build. The guide says how.
The machine will do the first with or without you.
It will do the second only if you say so.
References
- The Qualities of Quality Code — the nine qualities used as the scorecard
- The Quality of AI Code — the claim this pair of posts measures
- Let AI Loose — the same plan, with no guide



0 comments
No comments yet — be the first.
Please log in to leave a comment. Log in