Acceptance Criteria Quality
Status: Complete
Category: Delivery
Default enforcement: Hard
Author: PushBackLog team
Tags
- Topic: delivery, quality
- Methodology: Agile, BDD
- Skillset: any
- Technology: generic
- Stage: definition, refinement
Summary
Acceptance criteria (AC) are the explicit, pre-agreed conditions that must be satisfied before a work item can be considered complete. They translate a user story’s intent into concrete, pass/fail tests that leave no room for interpretation. High-quality AC is testable, unambiguous, written from the user’s perspective, and agreed by both the requester and implementer before work begins — not after.
This practice is enforced as Hard because missing or vague AC is one of the single largest sources of wasted engineering effort: work delivered correctly to an unclear spec is still wrong, and the cost of that realisation compounds at every handoff.
Rationale
The cost of ambiguity
A user story without good acceptance criteria is an invitation for the most expensive kind of rework: work that is technically complete but functionally wrong. When there is no explicit definition of success, teams default to implicit assumptions — and assumptions diverge across roles. A developer thinks “working” means no exceptions in the logs. A product manager means “matching the design”. A customer means “doing what I needed”. All three can be right independently and still produce a failed delivery.
Research from the Project Management Institute consistently identifies poor requirements as a top cause of project failure. At the story level, the failure mode is quieter but cumulative: ambiguous tickets become mini-waterfalls, with design questions, back-and-forth Slack threads, and finally a demo where the PM says “that’s not quite what I meant.”
The AI multiplier
As teams adopt AI pair programmers and automated delivery pipelines, AC quality becomes a multiplier — in both directions. An AI worker given well-formed AC can produce a correct implementation with minimal guidance. Given vague or missing AC, it will confidently produce something plausible that satisfies no real requirement. The strength of AC is now a direct input to how much autonomous work a team can safely delegate.
AC as communication, not bureaucracy
Before any code is written, the act of writing and reviewing AC surfaces disagreements, dependencies, and missing context that would otherwise surface as expensive surprises mid-sprint. Well-run AC discussions between product, engineering, and QA are one of the highest-leverage conversations a team can have. The artifact is valuable; the conversation that produces it is perhaps more so.
Guidance
The five properties of good acceptance criteria
| Property | What it means |
|---|---|
| Testable | Every criterion yields a clear pass or fail. No subjective judgement required. |
| Unambiguous | Any two team members reading it independently would reach the same conclusion about what it requires. |
| User-focused | AC describes what a user can observe or accomplish, not how the system implements it internally. |
| Pre-agreed | Written and approved by product, engineering, and QA before development begins — not during or after. |
| Appropriately scoped | Describes what the system must do, not how. Does not specify implementation details or technology choices. |
Formats
Two formats are widely used. Choose the one that fits the context; you may use both within the same story.
Format 1 — Given / When / Then (scenario-based)
Best for behaviour with identifiable context, action, and outcome. Maps directly onto automated test structure and supports BDD workflows.
Scenario: [name the scenario]
Given [the initial state or context]
When [the user or system takes an action]
Then [the observable outcome]
Write one scenario per distinct behaviour. Do not combine multiple outcomes into a single Then:
# Bad — two distinct outcomes combined
Then the user is redirected to the dashboard and an email is sent
# Good — separate scenarios
Then the user is redirected to the dashboard
# --- and separately ---
Scenario: Email notification on successful login
Given the user has completed authentication
When the login succeeds
Then a login-confirmation email is sent to the user's registered address
Format 2 — Verification checklist
Best for non-functional requirements, visual/design criteria, or a structured pass/fail list when scenario framing adds unnecessary ceremony.
[ ] The page loads in under 2 seconds on a standard 4G connection
[ ] The form submits without page reload
[ ] Error messages are visible without scrolling on mobile viewport (375px)
[ ] All interactive elements are keyboard-focusable
What to include
Every story’s AC should cover all of the following:
| Dimension | Description |
|---|---|
| Happy path | The primary success scenario as the user expects it to work |
| Alternate flows | Legitimate variations of the happy path (e.g. existing user vs new user) |
| Error states | What the system does when input is invalid, a service is down, or an action fails |
| Edge cases | Boundary conditions, empty states, maximum limits |
| Non-functional constraints | Performance, security, or accessibility requirements specific to this story |
Non-functional criteria are the most commonly omitted. When a story touches a customer-facing page, include a load time threshold. When it handles user data, include a data-handling constraint. When it adds a new input, include validation rules.
When to write AC
AC should be written — or at least drafted — before a story enters sprint backlog, during backlog refinement. Finalise AC during sprint planning with the implementing engineer(s) present. A story that enters a sprint without agreed AC violates the Definition of Ready.
Do not write AC for stories that are not yet scheduled: requirements change, and pre-writing AC for distant stories usually produces waste. Bias toward writing AC at the last responsible moment — when the story is imminent — to capture the latest context.
Who writes AC
The product owner or product manager typically drafts AC, since they represent the customer perspective. However, reviewing and finalising AC should be a cross-functional activity involving:
- Engineering — to identify missing technical constraints, flag infeasible criteria, and ensure each criterion is actually testable
- QA — to identify missing edge cases and verify that the criteria translate into automatable tests
- Design — for any story with a visual component, to confirm the criteria correctly describes observable design intent
The product owner writes; the team stress-tests and agrees. Both parties must be able to sign off before work begins.
Examples
Example 1 — Email login flow (Given/When/Then)
User story: As a registered user, I want to log in with my email and password so that I can access my account.
Acceptance criteria:
Scenario: Successful login with valid credentials
Given I am on the login page
When I enter a registered email address and the correct password
And I click "Sign in"
Then I am redirected to my dashboard
And my session is persisted for 30 days
And a login-confirmation email is sent to my address
Scenario: Login fails with incorrect password
Given I am on the login page
When I enter a registered email address and an incorrect password
And I click "Sign in"
Then I remain on the login page
And an error message reads "Incorrect email or password" (not specifying which is wrong)
And my account is not locked on the first failure
Scenario: Account locked after repeated failures
Given I have entered an incorrect password 5 times consecutively
When I attempt to sign in again
Then I am shown a message explaining my account is temporarily locked
And I am offered a "Reset your password" link
And no further login attempts are permitted for 15 minutes
Scenario: Login with unknown email
Given I am on the login page
When I enter an email address not registered in the system
And I click "Sign in"
Then I see the same "Incorrect email or password" error message
(Note: do not distinguish between unknown email and wrong password — prevents user enumeration)
Non-functional AC (verification checklist):
[ ] The login form submits over HTTPS only
[ ] Password field value is never included in page URLs or logs
[ ] The login page renders correctly on viewports from 375px to 1440px wide
[ ] Login completes in under 1.5 seconds at p95 under normal load
[ ] The form is fully operable by keyboard alone
Example 2 — Vague vs. specific
Vague AC (bad):
- The user can update their profile
- It looks correct on mobile
- Errors are handled properly
Why it fails: “Update their profile” doesn’t say which fields. “Looks correct” requires someone to make a judgement call. “Errors are handled properly” is circular.
Specific AC (good):
Scenario: User updates display name Given I am on the Profile Settings page
When I change my display name and click Save
Then my new display name is shown in the page header within 2 seconds
And the change persists after a full page reloadNon-functional:
[ ] The display name field accepts 2–64 characters [ ] The field rejects HTML tags and displays a validation message [ ] The Save button is disabled while the update request is in flight [ ] On a 375px viewport, the form and Save button are both visible without horizontal scroll
Anti-patterns
1. Writing AC after work is “done”
Writing AC to describe what was built — rather than what should be built — is a documentation exercise masquerading as requirements. It provides no protection against misalignment and inverts the purpose of AC entirely. If a developer opens a ticket with no AC and decides to write it once implementation is complete, stop the sprint.
2. Vague outcome language
Phrases like “works correctly”, “looks good”, “is fast enough”, “handles errors”, or “displays properly on mobile” are not acceptance criteria. They are placeholders that move the decision about what “correct” means from the spec to the developer’s discretion, late in the process, when it is most expensive to address.
3. Specifying implementation, not behaviour
AC that says “When the user clicks the blue Save button in the top-right corner, it fires a POST to /api/profile” describes implementation, not behaviour. If the button moves, or the endpoint changes, the AC is stale. The correct framing is: “When the user saves their profile, the change is persisted”. The how is the developer’s concern.
4. Missing error states
Happy-path-only AC is one of the most common quality failures. Every story that involves user input, network calls, external services, or file operations must include at least one error scenario. What happens when the server is unavailable? When validation fails? When the user has insufficient permissions? These are not edge cases — they are guaranteed to happen in production.
5. Missing non-functional constraints
A feature can pass every functional criterion and still fail in production due to missing non-functional requirements. Performance thresholds, security constraints, and accessibility requirements must be specified per story, not assumed. Relying on a separate “non-functional requirements document” that nobody reads during sprint planning does not count.
6. No shared agreement before work begins
AC written by a product manager, never reviewed by engineering, and never discussed in a planning session does not constitute agreed AC. Engineering may have read it; they did not endorse it. A story with unreviewed AC is effectively the same as a story with no AC — the team discovers disagreements during implementation or demo, when rework is highest.
7. Treating AC as a formality
The worst version of this anti-pattern is AC written to satisfy a process requirement rather than to communicate requirements. “The user can complete the workflow” is technically a written criterion. It is useless. AC written under time pressure, with the goal of having something in the ticket, actively misleads teams by creating the appearance of a ready story that isn’t one.
8. One acceptance criterion for many distinct behaviours
A single criterion that covers three different scenarios should be three separate criteria. Bundled AC makes it impossible to know which part passed and which failed during review, and makes partial completion invisible.
Related practices
- Definition of Done
- Definition of Ready
- Story Sizing
- Behaviour-Driven Development (BDD)
- Test-Driven Development (TDD)
Part of the PushBackLog Best Practices Library. Suggest improvements →