BrainGrid
How-tos

The Three Artifacts That Actually Matter: Requirements, Acceptance Tests, Code

Requirements, acceptance tests, and code are the only three artifacts that carry signal in an AI build. Why acceptance tests are the one most builders skip.

BrainGrid Team
10 min read
The Three Artifacts That Actually Matter: Requirements, Acceptance Tests, Code

Every week the AI building community rediscovers a truth that has been sitting in software engineering textbooks since before most of these tools existed. This week it showed up in a Reddit comment. A builder who had wired up a full-stack loop with agents, and did not yet know "loop engineering" was even a term, worked out the whole thing from first principles and posted it as advice.

"You have to define 'done' for your application, plan all the work it takes to get there, and then do it. There are three major artifacts you need: Your requirements, Your acceptance tests, Your code. All other artifacts are ancillary."

He is right, and the reason he is right is more interesting than the list. The person who wrote that was not reciting a methodology. He arrived at it because his loop kept producing things that looked finished and were not, and he reverse-engineered the fix. What he found is the same three artifacts a disciplined team would name, in the same order. The surprise is not that they matter. It is which one almost everyone skips.

#Why only three artifacts carry signal

Open any real project and you will find dozens of artifacts. Chat logs, prompts, markdown files, tickets, design notes, a scratchpad of half-ideas, the PR description the agent auto-generated. It feels like they all count. Most of them do not. They are records of how you got somewhere, not statements of what has to be true. Strip them away and three things are left standing.

Requirements say what the software must do. Acceptance tests say how you will know it did. Code is the thing that makes the tests pass. That ordering is not decorative. Requirements come first because you cannot test against a target you never named. Acceptance tests come second because "done" has to be a checkable fact before any code exists, not a feeling you develop after the demo. Code comes last because it is downstream of both. This is the same sequence the community keeps landing on in its own words: the r/vibecoding thread puts it as "requirements to acceptance tests to code," and then delivers the line that should be taped to every agent's monitor.

"If you want deterministic results, you need deterministic verification."

That is the whole argument in eight words. Everything else in the pile is a detail.

#The one artifact everyone skips

Here is the hypothesis this post rests on: most AI builds have two of the three artifacts and pretend the middle one is optional. There is a requirement, usually a sentence typed into a chat box. There is code, generated in seconds. And between them, where the acceptance test should be, there is nothing but the builder's own eyeballs and a demo that runs.

That missing middle is why the loop feels like a slot machine. Without an acceptance test, "done" is decided by looking at the screen, and a screen is a terrible verifier. It shows you the happy path, in good lighting, with the one input you happened to type. It does not show you the empty state, the second user, the expired token, the row that belongs to someone else. So the agent ships, you glance, it looks right, and the gap between looks-right and is-right gets discovered by a real user three weeks later. The acceptance test is the artifact that would have caught it, and it is precisely the one that got skipped because it is the only one that requires you to think before the code appears.

Consider the difference in plain terms. A requirement without an acceptance test is a wish. "Users can reset their password" is a direction, not a definition of done. Turn it into an acceptance test and it becomes checkable: a user who requests a reset gets an email within a minute, the link works exactly once, an expired link shows a specific message and not a stack trace, and a reset invalidates every existing session. Now there is a fact to verify instead of a vibe to trust. Same feature, same requirement, completely different odds of shipping the right thing.

#The middle artifact is what makes the loop hold

This maps directly onto the loop that AI building keeps converging on: plan, build, verify, repeat. The three artifacts are not a separate framework bolted on the side. They are what each stage of the loop actually produces. Plan produces the requirements. The definition of done produces the acceptance tests. Build produces the code. And verify is the step where the code is measured against the acceptance tests, not against a human's patience.

A loop with all three artifacts converges, because every pass has a target and a way to check whether it hit. A loop missing the acceptance test never converges. It just runs, produces something plausible, and waits for you to approve it on faith. The reason a loop that works on a toy breaks on a real app is not that the model got worse. It is that a toy has few enough states that your eyeballs are an adequate verifier, and a real app does not. As autonomy goes up, the number of decisions nobody explicitly wrote down goes up with it, and eyeball verification falls further behind. The acceptance test is how you scale verification past the point where looking still works.

This is where BrainGrid sits in the workflow. It is the plan-first platform that produces the first two artifacts before any code exists. You describe the feature, and the Planning Agent turns it into a requirement with acceptance criteria written to be checkable, the exact middle artifact most builds skip. Then the Builder Agent, working in a managed sandbox or in your own GitHub repo through your coding agent, builds against those criteria, and a feature is not done until each one is verified with evidence. The point is not the tooling. The point is that the acceptance test exists on purpose, upstream of the code, so the loop has something real to verify against instead of your attention span.

#The trade-off nobody advertises

Writing acceptance tests before the code is genuinely harder than not writing them. It front-loads the thinking. You have to decide what "reset works" means while you are still staring at an empty editor, which is exactly the moment your brain would rather skip ahead to the part where something runs. That friction is real, and pretending it away would be dishonest. The middle artifact costs you time up front, every time.

You pay for it either way. Skip the acceptance test and the cost moves downstream, into regeneration loops, into review sessions where you read code trying to guess what it was supposed to do, into the production bug that arrives with no test to reproduce it. Reviewing AI-generated code is its own tax, and a large part of it is the oversight premium: the cost of checking work against a standard that was never written down. The acceptance test is that standard, captured before the code, so review becomes a check instead of an archaeology dig. The bill comes due at planning time or at debugging time. It is smaller at planning time.

#What this means if you build with agents

If your current loop is "type a request, look at the result, ship if it seems fine," you are running on two artifacts and calling the demo your third. That works right up until the app has more states than you can hold in your head, which for anything real is around the fourth or fifth feature. The fix is not a better prompt or a smarter model. It is to write the acceptance test as a deliberate step, before the build, so the agent has a target it can check itself against and you have a fact you can trust instead of a screen you have to believe.

Three artifacts carry the signal. Requirements name the target, acceptance tests define the hit, code is downstream of both. Skip the middle one and the loop cannot converge, because there is nothing for it to converge toward.

#FAQ

#What is an acceptance test?

An acceptance test is a checkable condition that says whether a feature does what it was supposed to do. It describes behavior from the outside, a given starting state, an action, and the exact expected result, so that passing or failing is a fact rather than an opinion. In an AI build, the acceptance test is the standard the agent's output is measured against, which is what turns "the demo ran" into "the feature is verified."

#What is an example of an acceptance test?

Take "users can reset their password." A good acceptance test breaks that into specific, verifiable conditions: requesting a reset sends an email within one minute, the reset link works exactly once, an expired link shows a defined message instead of an error page, and completing a reset invalidates all existing sessions. Each of those either happens or it does not, with no room to argue, which is what makes them testable rather than aspirational.

#How do you write good acceptance tests?

Start from the requirement and ask what a skeptic would need to see to agree it is done. Name exact values instead of adjectives: the specific error message, the exact time limit, the precise state after the action. Cover the paths the happy demo skips, empty states, second users, expired tokens, and permission boundaries. The test to apply to every criterion is whether two people, or two agents, could disagree about whether it passed. If they could, it is not specific enough yet. For the full craft, see how to write acceptance criteria an AI agent can actually verify.

#What is the difference between acceptance criteria and acceptance tests?

Acceptance criteria state the conditions a feature must meet; acceptance tests are the concrete checks that confirm those conditions were met. In practice the line is thin, criteria are the definition, tests are the definition made runnable or verifiable. The important part for AI builders is that both live upstream of the code. They are the middle artifact that says what "done" means before the agent writes a line, not a QA step you improvise afterward. This is the core idea behind spec-driven development: the specification, requirements plus acceptance criteria, comes first, and the code is built to satisfy it.

#What is the difference between requirements and acceptance criteria?

Requirements describe what the software should do at the level of intent, "users can reset their password." Acceptance criteria pin that intent down into specific, testable conditions, "an expired reset link shows this message and does not error." Requirements come first and set direction; acceptance criteria come second and set the bar for done. Code is downstream of both, which is why getting the first two right is what decides whether the third is correct.

BrainGrid is the plan-first platform that turns your idea into requirements and acceptance criteria your agent can build and verify against. Try it at braingrid.ai.

About the Author

The BrainGrid team building tools to help developers ship better software with AI.

Want to discuss AI coding workflows or share your experiences? Find me on X or connect on LinkedIn.

Get Started

Ready to build without the back-and-forth?

Turn messy thoughts into engineering-grade prompts that coding agents can nail the first time.

Describe what you want to build