How do you know when your AI feature is wrong?
ENGINEERING
SEPTEMBER 1, 2026

How do you know when your AI feature is wrong?

6 min read
BACK TO BLOG

Most teams ship an AI feature and have no answer past spot-checking. What an evaluation harness actually contains, and the failure it usually misses.

The feature works. You have used it, the team has used it, the demo went well, and the output looks right almost every time you look at it. That last clause is the problem. "Almost every time you look at it" is not a measurement, and the cases you look at are the cases you designed for. The ones that will hurt you are the ones nobody thought to type. This is written for the engineer who already shipped, not for someone deciding whether to. Most of it is unglamorous. ## What is actually wrong with spot-checking? It samples from the wrong distribution. When you check your own feature you generate inputs the way its author generates inputs — you know what it is for, so you ask it things it is for. Real users arrive with truncated pastes, two questions in one sentence, a document from a vendor whose export is subtly malformed, and the assumption that it can do something adjacent that it cannot. Spot-checking also has no memory. You fix a prompt so case A behaves, and case B — which you fixed three weeks ago and have not thought about since — quietly regresses. Without a suite you find out about that from a customer, and the customer will not phrase it as a regression. They will phrase it as "your product is unreliable", which is a much more expensive sentence. ## Separate the retrieval failure from the generation failure If your feature does anything with your own data, this is the highest-value thing on the page. Most reports of "the model got it wrong" are not generation failures at all. The right document never made it into the context window. The model was then asked a question it had no way to answer and did the thing models do, which is produce something fluent. You cannot fix that by editing the prompt, and teams spend weeks trying. So measure the two separately, and measure retrieval first because it has a correct answer. For a set of real questions, record which chunk *should* have been retrieved, then check whether it appeared in the context at all. That is a deterministic assertion with a yes or no answer — no model call, no judgement. When retrieval is landing, and only then, is a generation score meaningful. ## What actually goes in a harness Less than the word implies. Four parts: **A fixture set.** Inputs paired with what must be true of the output. Not ideal answers — *properties*. "Contains a valid ICD-10 code", "cites at least one retrieved source", "does not state a dosage", "refuses". Properties survive model upgrades and prompt rewrites; a golden string does not. **Graders, deterministic first.** If the output should be valid JSON, parse it. If it should contain a real product code, look the code up. Reach for a model-as-judge only for the subjective residue, and when you do, calibrate it: label a sample by hand and check the judge agrees with you. An uncalibrated judge is a second unmeasured system sitting on top of the first one. **A runner that scores by category**, so a drop tells you *where*. A single aggregate number tells you something changed and nothing else. **A CI gate.** The suite runs on the branch, and a drop below the line blocks the merge. Everything above is a document until this part exists. ## The change that helps most is letting it refuse A system with no abstention path will fabricate, because fabricating is the only move available to it. Give it somewhere else to go. If retrieval confidence is under the threshold, or the required field is not present in any retrieved chunk, return "I do not have that" rather than generating. Then make abstention a first-class outcome in the harness — you want to know both how often it refuses and how often it refuses something it should have answered, because a system that refuses everything scores beautifully on correctness and is useless. ## Do you need an evaluation framework? Probably not, and this is where most teams lose a month. What you need first is a file of real failures. Every time somebody says "that answer is wrong", the input goes in the file with a note on what was wrong with it. That file, after a few weeks of production, is worth more than any framework, because it is drawn from the distribution that is actually hitting you rather than one you imagined. Then write a script that runs those inputs and asserts the properties. Plain code, in your repo, in your language. Adopt a framework later if the script gets unwieldy — many teams find it never does. The dataset is the asset. The harness is plumbing. ## Where I learned this I designed and built a multi-tenant clinical platform — 95 TypeScript source files, 29 test files, 36 migrations. It is built and owned by me and has no live client, so I am not claiming a deployment; what I am claiming is the constraint I built under, which was that a wrong answer reaching a patient was not a bug you ship and fix on Thursday. That constraint changes the engineering. Output has to be measured and gated rather than hoped over, abstention has to be designed in from the start instead of retrofitted, and the interesting question stops being "is the model good" and becomes "what does the system do when the model is wrong". That second question has an answer you can build. The first one does not. ## If you want another pair of eyes The awkward part of evaluation work is that the person best placed to design the harness is the person who wrote the feature, and they are also the person least able to imagine how it breaks. **[Run the free website check](/website-audit)** — that is a public, unauthenticated endpoint that takes an arbitrary URL from a stranger and drives headless Chromium at it, which is an SSRF liability unless the boundary is real. 36 tests cover that boundary — the inputs it must refuse, and the public ones it must keep serving. Poke at it; it is a fair sample of how I build the parts nobody sees. If the eval question is the live one, I do a fixed $2,500 review — your prompts, your retrieval, your failure modes — and you get a harness design and a prioritised fix list in about a week, with no retainer after it. [Tell me what you shipped](/contact). If the answer is that your spot-checking is adequate for the stakes you are operating at, I will tell you that instead.
SHARE
6 min read
Read More

MORE ARTICLES

Two ECS failures that produce no useful error
Engineering
Engineering

Two ECS failures that produce no useful error

A readiness probe blocked by the task's own IAM role, and readonlyRootFilesystem silently killing ECS Exec. Both look like broken infrastructure.

Don't put a model where you need a reproducible answer
Engineering
Engineering

Don't put a model where you need a reproducible answer

Three systems where I deliberately chose regex and a lookup table over an LLM, and the two questions that decide which one a problem needs.

CLAUDE.md as production infrastructure
Engineering
Engineering

CLAUDE.md as production infrastructure

What a coding agent's context file has to contain when the repos it touches are live, and the day I found the file preventing disasters had no backup.

A fact register: stopping an LLM inventing your statistics
Engineering
Engineering

A fact register: stopping an LLM inventing your statistics

Four invented statistics shipped to my own live website. The fix was not a better prompt — it was an allowlist of every number the copy may contain.