Why I Replaced Unit Tests With User Guides for AI Agents
In early 2026, I scrapped six months of unit test infrastructure for an AI-driven build. Not because the tests were wrong. Because they were answering the wrong question. According to McKinsey's State of AI 2024 report, 72% of organizations now use AI in at least one business function, up from 50% in previous years. Most of those teams are still trying to QA AI-written output the same way they QA human-written output. That mismatch is costing them more than they realize.
This is a retrospective on what I set out to build, what broke, and the specific shift in methodology that fixed it.
What We Set Out to Build
The goal was a modular automation pipeline where an LLM would write, revise, and validate its own output across multiple reasoning steps. Think of it as a multi-stage orchestration system: one component researches, one scores, one drafts. Each hands off to the next. We wanted the system to self-correct without a human in the loop on every iteration.
The obvious QA mechanism was unit tests. Write assertions. Check outputs. If the reasoning node returns a malformed payload, the test catches it. Clean, familiar, fast to set up.
We built 47 unit tests across three components. They all passed on the first real run.
The output was still wrong.
What Went Wrong
The tests validated structure, not intent. A payload could be syntactically correct, pass every assertion, and still describe the wrong thing to the wrong person in the wrong tone. Unit tests have no mechanism for catching that class of failure. They never did, for human-written software either, but human developers carry implicit context that keeps them roughly aligned with user expectations. An LLM carries no such context between sessions.
This is where the architecture compounded the problem. Our first multi-agent build used a flat three-component structure: research, scoring, and writing all reported to a single orchestrator. It worked on five inputs. At fifty, the scoring module sat idle waiting on research that had nothing to do with scoring. We learned this the hard way. Splitting into discrete components with explicit handoff contracts between them cut processing time and made each module independently inspectable. That experience is now baked into how we think about any multi-stage pipeline: implicit data passing between reasoning nodes does not hold up under load.
But even after fixing the architecture, the QA problem remained. The tests told us the system was running. They could not tell us whether it was doing the right thing.
The deeper issue: unit tests encode the developer's assumptions about correct behavior. When an LLM writes the code, those assumptions may not match what the LLM actually produces. You end up testing the LLM's interpretation of your intent against your interpretation of your intent. The gap between those two things is exactly where bugs live.
The Shift: User Guides as the Source of Truth
The fix came from a question a colleague asked during a frustrating debugging session: "What would a user expect to happen here?"
We stopped writing tests first. We started writing user documentation first. Not specs. Not technical requirements. Actual prose that a non-technical user would read to understand what the system does, step by step, with annotated mockups of every output state.
Then we handed that documentation to the reasoning model as its primary instruction set. Not as a system prompt addendum. As the canonical source of truth it was required to satisfy before any output was accepted.
The results were immediate in a specific, measurable way: the number of revision cycles dropped. When the LLM had a human-readable description of the expected outcome, it could compare its own output against that description and identify the delta. It could not do that against a unit test, because unit tests are not written in the same representational space the model reasons in.
This connects to a broader pattern we've written about in the context of verifiable AI reasoning: the more explicit and human-readable your specification, the more a reasoning model can self-audit against it. Implicit expectations, whether encoded in tests or buried in system prompts, create ambiguity the model fills with its own priors.
What This Looks Like in Practice
The workflow has three phases, and none of them involve writing a test file first.
Phase 1: Write the user narrative. Before any code exists, write a plain-language walkthrough of what the system does from the user's perspective. Include what the user sees, what they input, what they receive back, and what they do next. Annotate every output state with a mockup, even a rough one.
Phase 2: Give the narrative to the coding model as its specification. The model's job is not to pass tests. Its job is to produce output that matches the narrative. Every iteration, the model compares its current output against the documented expectation and flags discrepancies before returning results.
Phase 3: Validate against the narrative, not assertions. Instead of running a test suite, you read the output as a user would. Does it match what the documentation says should happen? If not, the narrative is the debugging artifact, not a stack trace.
This approach works particularly well in n8n-based automation pipelines, where each node in a workflow has a discrete, describable function. Writing a user-facing description of what a node should produce is often faster than writing assertions for it, and the description travels with the pipeline as living documentation. If you're evaluating how to structure that kind of pipeline, the DevOps mental model for AI tooling is worth reading alongside this.
Where This Breaks Down
User-guide-driven development is not a universal replacement for formal testing. It has real failure modes.
First, it requires someone who can write clearly. If your team's documentation culture is weak, the narratives will be ambiguous, and an LLM given an ambiguous specification will produce ambiguous output. The quality of the spec sets the ceiling on the quality of the result.
Second, this method does not catch performance regressions, memory leaks, or infrastructure failures. You still need monitoring, load testing, and circuit breakers. We've written separately about the cost problem in LLM load testing, and nothing in this methodology addresses that class of problem.
Third, for systems with strict correctness requirements, such as financial calculations or medical data processing, human-readable narratives are insufficient as the sole validation layer. You need formal verification on top of this, not instead of it.
The honest framing: this methodology is best suited to systems where the primary failure mode is misalignment with user expectations, not systems where the primary failure mode is computational incorrectness. Know which problem you're solving before you choose your QA approach.
What We'd Do Differently
Start with a one-page narrative before writing a single line of specification. We wasted time writing detailed technical specs that the LLM interpreted inconsistently. A plain-language walkthrough, written as if explaining the system to a new user, gave the model more usable context than a formal requirements document. We would have saved at least two full iteration cycles by doing this on day one.
Version the narratives alongside the code, not separately. We kept documentation in a separate repository. When the system changed, the narrative lagged. The model then self-corrected against an outdated description and introduced regressions we didn't catch for days. Treating the user narrative as a first-class artifact in version control, committed with every meaningful change, would have prevented this entirely.
Build explicit handoff schemas between reasoning components before writing any component logic. We defined the inter-component contracts late, after each module was already partially built. Retrofitting those schemas forced us to rewrite two components from scratch. Define what each reasoning node receives and returns before you build it. The architecture becomes dramatically easier to inspect, and the narratives for each component write themselves from the schema.