Concept
Acceptance criteria as the contract
Acceptance criteria define the behaviour code must satisfy. A single acceptance criterion pairs with a single test case that proves it.
Last updated
Acceptance criteria as the contract is RCF’s central rule: each criterion is written before the code and pins one-to-one to the test case that proves it, so the criterion, not the code, is what the agent’s output answers to.
Acceptance criteria connect the decisions above them to the code and tests below them. Their quality determines whether the chain can verify the intended behaviour.
What are acceptance criteria in AI development?
Acceptance criteria are short, verifiable statements of what a piece of software must do for a specific scenario. In AI-assisted development they do extra work, because the agent doing the coding doesn’t carry the team’s institutional memory and won’t infer intent from a hallway conversation. The AC is the contract the agent has to satisfy and the verification step can confirm, in that order. Everything that follows is mechanics.
What an AC actually is
A Given/When/Then sentence. Given a precondition, when an event happens, then an observable thing must be true. Three clauses. One specific behaviour.
Two things matter about that shape. First, it’s verifiable as written. The default is an automated test: if you can turn a Given/When/Then into a piece of test code, the criterion has a clean machine-checkable home, and most ACs land there. A few don’t. A k8s cluster following a naming convention, a deployed manifest matching a target shape, anything where the practical verification step is a human reviewer reading a real artefact against the rule. Those are real ACs too. The rule is verifiability, not test-automation. If the criterion can’t be verified at all, by a test or a human against an artefact, it isn’t one. It is not verifiable. Second, it’s observable. The then clause has to describe something a verification step can check from the outside: a response code, a stored value, a screen state, a naming pattern, a side effect on another system. If the only way to confirm the criterion is to read the source code, the criterion isn’t one. It is a code review note.
The one-to-one rule
Every acceptance criterion is verified by exactly one test case. Every test
case verifies exactly one acceptance criterion. The mapping is one to one,
by construction, and the test case carries the AC ID that names the
criterion it proves. The test suite is the container the test cases live
in: it hangs off a single user story and may hold cases for any or all of
that story’s acceptance criteria. This one-to-one is a claim about
test cases specifically. Code Nodes also reference acceptance criteria,
through implementsAcIds, but that link is deliberately
many-to-many and separate: several nodes can implement one criterion and
one node can serve several, none of which disturbs the one-case-per-criterion
rule.
The one-to-one rule makes test coverage attributable to individual criteria. It records which test case verifies which product behaviour.
A criterion without a case has no test evidence. Two cases for one criterion duplicate maintenance. A case covering two criteria makes it difficult to identify which criterion passed. One-to-one mapping removes that ambiguity.
A criterion is a contract
wish versus criterion · one to one
What this rule isn’t saying about testing
The rule governs the AC-to-case mapping. It does not require one test runner or put every kind of testing into the chain.
Unit tests are out of the AC chain. They’re standard engineering hygiene, expected alongside the source code at the team’s normal coverage target. They prove individual functions behave the way the code says they should. They don’t prove an AC is met, and they aren’t meant to. Different work, different layer. RCF doesn’t replace unit tests; it sits above them.
The form of the test case doesn’t matter. If it tests the criterion, it is an RCF test case. A timing assertion in an HTTP test is fine. A jmeter run defined in code is fine. A playwright browser journey is fine. A contract test against a third-party API is fine. What matters is that the case proves the AC and that the case carries the AC ID so traceability can resolve it. The one-to-one rule is about that mapping, not about which runner you use.
This layer is the layer that does traceability work. It isn’t the totality of testing on the project. Unit tests, smoke tests, exploratory testing, ad-hoc performance probes, internal QA runs, all of these can and should exist alongside the AC-mapped suites. They do not need to be part of the chain.
Tests written against existing code can miss the intended criterion. The theatre risk page describes the safeguards: an AC schema, separate test-writing and code-writing contexts, and human approval at AC review.
Why this matters more with AI agents in the loop
A developer may organise three tests around one criterion without recording the mapping. The team can retain that relationship in memory when it does the work itself.
An agent needs the mapping explicitly. An instruction to cover the criteria can produce plausible tests without complete coverage. The one-to-one rule requires a test case that carries its criterion’s ID and a criterion reference back to that case, making gaps identifiable.
How do you write acceptance criteria for AI coding agents?
Make each criterion observable, unambiguous, and binary: a Given/When/Then sentence whose then clause a test can check from the outside, with pass and fail as the only outcomes. Write it before the agent writes the code, give it exactly one test case that proves it, and hold the agent’s output to it.
What a good AC looks like
A good AC is specific, observable, and self-contained. Specific means it describes one behaviour, not a family of related behaviours. Observable means the then clause is checkable without reading the source. Self-contained means the test can be written from the AC text alone, without having to reconstruct context from the wider story.
Here’s a workable one:
AC-042-02. Given a signed-in user, when they upload a file over 5 MB or in an unsupported format, then the upload is rejected with an HTTP 400 response, an error code ofupload-too-largeorupload-format, and no partial state is persisted in the photo store.
The example names three required elements. The precondition is named (signed-in user). The triggers are named (over 5 MB; unsupported format). The expectations are concrete and checkable (HTTP 400, specific error codes, no partial state). Writing a test against that AC is mechanical work.
What a bad AC looks like
A common failure is to describe a general quality without defining an observable result:
AC-042-bad. The upload feature handles errors gracefully and provides good user feedback.
This statement does not define observable behaviour. Different engineers can interpret it differently and write passing tests that leave the error flow broken. Split it into criteria that name each error condition and its expected response.
Where ACs come from
Write acceptance criteria with the user story, ideally by the product owner or whoever performs that role. They commit to required behaviour before implementation. Criteria added after the code only reconstruct what was built.
ACs can change as the team learns. If a criterion lacks a precondition, update it and commit the correction before continuing. The commit records a deliberate change to the requirement, rather than an unrecorded adjustment to match the implementation.
AI can help draft a thorough set of criteria from well-written requirements and stories, including edge cases the author may miss. The drafts still need human review and revision. A separate treatment of AI-assisted upstream work is planned.
ID schemes and references
AC IDs are scoped to the story. AC-042-01 is the first criterion on US-042. The string is opaque (never renumbered, never reused) and load-bearing (test cases point at it, Code Nodes reference it, work items mention it). On a project of any size, ACs are the thing you look up by ID most often.
IDs should be easy to say, type, search for in the repository and recognise in test output. UUIDs make these routine uses harder and reduce the likelihood that the team will maintain the chain.
What you get when ACs are doing their job
This mapping supports three routine checks.
You can answer “is this requirement satisfied” in a single query. Pull the requirement’s stories, pull their ACs, pull the suites, check they’re green. Done.
Trace a function’s tests back through the chain to identify the requirement it serves. The chain records why the function exists; the source explains how it works.
An agent’s output can be checked against criteria a human approved. This addresses the AI trust gap by using an agreed contract. The theatre risk page describes the safeguards that keep approval tied to that contract.