A ticket says a feature is done. The demo looks fine. Then support messages arrive, QA reopens the story, and the founder asks why the shipped version doesn’t do the thing everyone thought it would do.

That usually isn’t a coding failure. It’s a specification failure.

Teams often write a decent user story and stop there. “As a user, I want to reset my password so that I can regain access.” Useful, but incomplete. A story explains intent. It doesn’t define what must be true for the work to count as finished. That gap is where rework, missed expectations, and AI-generated nonsense tend to creep in.

Acceptance criteria for user stories close that gap. They turn a wish into a shared contract. For a human team, that means fewer assumptions. For teams using Cursor, Claude Code, Codex, or an orchestration layer, it means the machine has a cleaner target and less room to improvise in the wrong direction.

Table of Contents

Why User Stories Fail and How Acceptance Criteria Fix It

A weak story usually fails in a familiar way. Product says “users need a faster onboarding flow.” Design mocks a polished screen. Engineering builds the flow. QA checks the happy path. The release goes live, but users still abandon the process because nobody defined whether onboarding needed a skip option, what data was mandatory, or what counted as successful completion.

That’s the difference between a story and a deliverable. The story describes the problem. The acceptance criteria define what success looks like.

A diagram illustrating how user stories and acceptance criteria lead to a successful feature development process.

The gap between intent and delivery

Historically, acceptance criteria were formalized in the Agile Manifesto era in 2001 as “conditions of satisfaction,” and Mike Cohn’s 2004 book User Stories Applied established the Product Owner as the sole writer of AC. Before that shift, software projects reportedly suffered 30-50% failure rates due to ambiguous requirements, with adoption of AC correlating with a drop to 20-30% by 2010 as teams moved toward measurable outcomes, according to Meegle’s summary of acceptance criteria history and practice.

Those numbers matter because they match what teams still see day to day. Ambiguity doesn’t look dramatic at first. It looks like “we can clarify later,” “engineering will know what I mean,” or “the edge cases can wait.” Then the story grows teeth.

You get:

  • Rework after demo: The feature technically works, but the business rejects it.
  • Conflicting interpretations: Product, QA, and engineering all use a different definition of done.
  • False velocity: Tickets close quickly, then reopen when the gaps become visible.
  • AI drift: A coding agent fills in unspecified details with plausible but wrong choices.

What acceptance criteria actually do

Good acceptance criteria for user stories sit between the story and the implementation. They don’t replace design, architecture, or tests. They establish the boundary of what must be true before the team can call the work complete.

Practical rule: If a stakeholder would reject the story when a condition is unmet, that condition belongs in the acceptance criteria.

That framing keeps ACs useful. A team doesn’t need every implementation detail in the ticket. It needs the critical conditions that separate acceptable from unacceptable.

A strong example looks like this:

  • User story: As a returning user, I want to resume onboarding so that I don’t have to start over.
  • Weak outcome: “User can continue onboarding easily.”
  • Clear AC: “If a signed-in user leaves onboarding before completion, their progress is saved and they return to the last completed step on next login.”

One sentence. Clear pass or fail. No guessing.

Crafting Clear and Testable Acceptance Criteria

A lot of teams overcomplicate this. They either write one vague sentence or dump half a test plan into the story. Neither helps.

The job is simpler than that. Write acceptance criteria for user stories as high-signal completion rules. They should be precise enough for product, engineering, QA, and AI tools to agree on what done means, but not so prescriptive that they lock the team into one implementation.

Start with the story but write for verification

A user story explains who, what, and why. Acceptance criteria explain what someone can verify.

A useful filter is this:

  1. What observable behavior must exist?
  2. What business rule must hold?
  3. What failure condition or edge case would make us reject the story?

If the answer is “we just want it to feel intuitive,” that’s not ready. If the answer is “the reset link expires after a defined period and invalid links show an error,” that’s testable.

A foundational agile guideline recommends no more than 3 acceptance criteria per story, and stories with more than 6 criteria should usually be split. The same source notes that teams using 3 or fewer AC per story report 25-40% faster sprint velocities, according to UX Planet’s analysis of acceptance criteria and story sizing.

That doesn’t mean every story must have exactly three bullets. It means if the list keeps growing, the story probably contains multiple concerns.

Three formats that work in practice

Use the format that matches the kind of decision the team needs to make.

Format Best For Example AI-Execution Friendliness
Checklist Simple features with direct outcomes User receives a reset email after requesting password reset Good when the scope is narrow and terms are precise
Rule-oriented Business logic and validation rules Reset link expires after 10 minutes and can be used once Strong for policy-heavy features and backend conditions
Given When Then Multi-step scenarios and behavior flows Given a registered user requests a reset, when they click a valid link, then they can set a new password Strongest when the flow needs explicit triggers and outcomes

Take one story and express it in all three formats.

User story: As a registered user, I want to reset my password so that I can regain access to my account.

Checklist format

  • User can request a password reset from the login screen.
  • System sends a reset link to the registered email address.
  • User sees a confirmation after successfully setting a new password.

Rule-oriented format

  • Only registered email addresses can receive reset links.
  • Reset links expire after the defined validity window.
  • A used or expired reset link returns an error and does not allow password change.

Given When Then format

  • Given a registered user is on the login screen, when they request a password reset using their account email, then the system sends a reset link.
  • Given the user opens a valid reset link, when they submit a compliant new password, then the password is updated and the user sees confirmation.
  • Given the reset link is expired or already used, when the user attempts to open it, then the system blocks reset and shows the next step.

How to choose the right format

Teams don’t need to standardize on one format forever. They need consistency within a backlog and judgment per story.

Use this quick decision guide:

  • Checklist works when the story is straightforward and the risk of interpretation is low.
  • Rule-oriented AC fits anything with eligibility logic, permissions, validation, billing, or compliance constraints.
  • Given When Then helps when a workflow includes state changes, branching paths, or significant error handling.

If the team keeps misunderstanding the same type of story, the format is probably wrong for that category of work.

There’s also a documentation lesson here. Teams that already rely on process documentation often write better ACs because they’re used to capturing repeatable, verifiable steps. If your specs are inconsistent, it’s worth reviewing Standard Operating Procedures best practices to tighten how your team defines workflows, ownership, and review points.

A few habits improve quality fast:

  • Use observable language: “Displays error message” is better than “handles errors gracefully.”
  • Write rejection gates: Include only conditions important enough to fail the story.
  • Prefer outcomes over build instructions: Say what must happen, not which class, framework, or component must do it.
  • Split crowded stories: If the AC list looks like a mini PRD, the story is too broad.

That last point saves more teams than any formatting trick.

Writing AI-Executable Acceptance Criteria

The old standard for “clear enough” was human clarity. A developer could fill in some blanks, ask a teammate, or resolve ambiguity during implementation. That still works for a tightly aligned team.

It breaks down faster when AI agents are doing part of the build.

A friendly robot developer working at a desk while checking acceptance criteria on a digital tablet screen.

Traditional Gherkin or checklist formats often fail to address AI reliability and merge conflict prevention. A cited claim says GitHub’s 2025 report indicated 62% of indie projects face AI-induced conflicts due to ambiguous criteria, with the recommendation that criteria evolve to include AI-executable verifiability metrics, as summarized in Meegle’s discussion of AI-oriented acceptance criteria gaps.

Why human-clear is not always machine-clear

A human developer can often infer what you meant by “save user preferences.” An AI coding agent may need answers to questions your team never wrote down:

  • Which repository module owns this behavior?
  • Which model should be updated?
  • What existing API contract must remain unchanged?
  • What happens if required dependencies are missing?
  • What files should not be modified?

That doesn’t mean acceptance criteria should become design docs. It means they need enough operational context to keep execution bounded.

Here’s the difference.

Human-first AC

  • User preferences are saved and restored on next login.

AI-executable AC

  • When a signed-in user updates notification preferences and clicks save, the system persists the new values to the existing user settings model, returns success in the current settings API response shape, and restores those values on next login without modifying unrelated profile fields.

The second version still focuses on outcome. It just removes the most dangerous ambiguity.

How to rewrite criteria for AI execution

A practical pattern is to add four layers of precision.

  1. Trigger Define what starts the behavior. User action, webhook, cron event, admin change, or imported data.

  2. Boundary Define where the change should happen. Existing endpoint, current model, specific module, or named service.

  3. Verification Define what observable result proves success. Response, saved state, UI reflection, log event, or test outcome.

  4. Guardrail Define what must not break. Auth, schema compatibility, dependency integrity, or no edits outside the scoped area.

A before-and-after example makes this obvious.

Loose AC

  • The feature should create invoices automatically.

AI-ready AC

  • Given an approved order exists, when the billing job runs, then one invoice record is created for that order in the current billing schema, the invoice uses the existing tax calculation service, duplicate invoices are not created for the same order, and failed invoice creation logs an error without blocking unrelated billing jobs.

That criterion gives an AI agent less room to “help” in the wrong place.

For a deeper look at this style of specification, the ideas in spec-driven development for AI-assisted teams are useful because they focus on making execution constraints explicit before code starts.

What AI agents need that teams forget to specify

Teams tend to forget the invisible constraints. Humans work around them. Agents collide with them.

The missing details usually fall into these buckets:

  • Repository mapping: Which area of the codebase owns the change.
  • Dependency awareness: What services, models, jobs, and shared utilities the feature relies on.
  • Security expectations: What auth, permission, or validation rules must remain true.
  • Non-goals: What should remain untouched.
  • Failure behavior: What the system should do when the happy path breaks.

Clear AI-executable acceptance criteria don’t just say what success is. They define the legal area where the agent is allowed to search for success.

That’s the shift. Good ACs used to prevent team misunderstandings. Now they also prevent machine improvisation.

Writing ACs for Security Performance and Scalability

Teams generally handle UI acceptance criteria reasonably well. They struggle when the requirement is invisible.

“Make it secure.”
“Keep it fast.”
“Make sure it scales.”

Those aren’t acceptance criteria. They’re aspirations. If nobody can verify them, they won’t hold up under planning, QA, or release review.

Why non-functional criteria get skipped

This is a real pain point for small teams. A cited summary says forums like Reddit’s r/ProductManagement show 70% of 2025-2026 threads unresolved on how to write acceptance criteria for non-functional requirements, and Atlassian’s 2025 State of Agile report reveals 55% of small teams reject stories prematurely due to untestable NFRs. The same summary points toward quantifiable criteria such as “System handles 10k concurrent users with <200ms latency” instead of vague goals, according to AltexSoft’s acceptance criteria best practices overview.

That matches what happens in early-stage products. Functional work gets specified because it’s visible. NFRs get deferred because they feel technical, and product owners worry about overstepping. Then the team ships features that work in a demo but fail under real usage or security review.

A professional team meeting with a man named Alex presenting development release criteria on a whiteboard.

Templates that make NFRs testable

You don’t need a staff architect to write better non-functional ACs. You need measurable rejection gates.

Use templates like these.

Security

  • Access is denied for users without the required role.
  • Submitted input is validated against allowed formats before persistence.
  • Secrets are not exposed in logs, responses, or client-rendered payloads.

Performance

  • The endpoint returns within the agreed response threshold under the defined load condition.
  • The page remains usable while background processing completes.
  • Bulk operations do not block unrelated requests.

Scalability

  • The job processes the defined volume without data loss or duplicate records.
  • The system remains functional when concurrent requests hit the same workflow.
  • Queue retries do not create inconsistent state.

A team writing ACs this way also needs a credible way to verify them. For performance-related stories, practical references on load performance testing can help teams translate “fast enough” into repeatable checks tied to actual system behavior.

What good NFR criteria sound like

Compare weak and strong versions.

Weak AC Better AC
The API should be secure Requests without valid authentication are rejected
The dashboard should load quickly Dashboard data loads within the defined threshold under expected usage conditions
The system should scale The system continues processing concurrent requests without duplicate records or failed writes

The stronger version still leaves room for engineering judgment. It doesn’t prescribe a library, cloud service, or implementation tactic. It defines what must be true for the work to be accepted.

That distinction matters for technical specs too. If your team needs help turning broad product intent into implementation-safe requirements, writing technical specifications that preserve testability is the discipline to borrow from. Good technical specs and good acceptance criteria reinforce each other. One provides context. The other defines the gate.

A non-functional requirement becomes real only when somebody can prove it passed or failed.

Use that line in backlog review. It instantly exposes which “requirements” are still hand-waving.

Common Acceptance Criteria Anti-Patterns to Avoid

Teams rarely fail because they don’t know acceptance criteria exist. They fail because they write ACs that look formal but still produce confusion.

The common pattern is predictable. Someone adds more detail to feel safer. The story gets longer, but not clearer. Product thinks it reduced risk. Engineering sees a wall of text. QA still has to interpret intent.

A comparison chart showing anti-patterns versus best practices for writing effective project acceptance criteria.

A useful framing from Mike Cohn’s guidance is that acceptance criteria should act as a high-level table of contents, not granular test specs. The same source highlights three common specification errors: criteria that are overly specific and limit creativity, criteria that prescribe solutions instead of outcomes, and criteria that exceed the story’s scope, as explained in Mountain Goat Software’s guidance on user stories and acceptance criteria.

When criteria become noise

You can usually spot weak acceptance criteria by how they sound in planning.

If someone reads the ticket and asks, “What do you want built?” the ACs are vague. If engineering says, “Why are you telling us which component to use?” the ACs are prescribing. If the list keeps growing every time a new concern appears, the story should be split.

Here are the most expensive anti-patterns:

  • Vague language: “Simple,” “intuitive,” “fast,” and “secure” without a testable condition.
  • Task lists disguised as ACs: “Create endpoint,” “write tests,” “update schema.”
  • Solution design in the ACs: Naming implementation details that should stay negotiable.
  • Kitchen-sink stories: Adding every edge case, non-goal, and future enhancement to one ticket.
  • Detached criteria: Keeping ACs in a separate doc no one checks during build or review.

Do this not that

A short self-audit catches most problems.

Not that Do this
User sees a friendly experience User sees a validation message when required fields are missing
Build a React modal for password reset User can request password reset from the login screen
Store data in service X and class Y User changes persist to the existing settings record and appear on next login
Include 9 criteria covering multiple workflows Split the story into smaller slices with distinct completion gates

Write criteria that a reviewer can validate without reading your mind.

That one test is brutal and effective. If validation depends on tribal knowledge, the ACs are weak.

Verifying and Integrating ACs into Your Workflow

A lot of teams treat acceptance criteria as something they write once so the ticket looks complete. Then the actual work happens somewhere else. Slack threads, code review comments, QA notes, and verbal clarifications informally replace the original spec.

That habit is why “done” keeps moving.

The stronger move is to treat acceptance criteria for user stories as the operating reference from backlog grooming through release review. Scrum Alliance guidance emphasizes stakeholder engagement before development begins, warns against writing ACs too early or too late, and recommends treating them as living documents updated through regular check-ins, as described in Scrum Alliance’s article on using acceptance criteria well.

Use ACs before build starts

The fastest fix is procedural. Don’t wait for implementation to discover unclear criteria.

A lightweight pre-build review should answer:

  • Stakeholder clarity: Does the story reflect what the requester needs?
  • Testability: Can QA or a reviewer determine pass or fail from the wording alone?
  • Scope fit: Is this one story, or three stories pretending to be one?
  • Missing constraints: Are security, failure behavior, or dependency assumptions unstated?

If a team can’t answer those questions in grooming, the story isn’t ready. That’s not bureaucracy. It’s rework prevention.

Make verification part of delivery

Once development starts, ACs should show up in real workflow checkpoints.

Use them in:

  • Desk checks: Review each criterion against the implementation before merging.
  • QA scenarios: Convert each AC into a validation step or automated test where appropriate.
  • Demo scripts: Show how the shipped behavior satisfies each criterion.
  • Release review: Reject “mostly done” work when a criterion is unmet.

A simple template also helps. If your team works from Jira, a structured Jira issue template for clearer specifications can keep stories, acceptance criteria, dependencies, and open questions in one place instead of scattering them across comments.

Keep the source of truth in one place

The biggest workflow mistake isn’t bad wording. It’s fragmentation.

When the story lives in Jira, the actual requirement lives in Slack, edge cases live in a Notion page, and QA decisions live in someone’s head, acceptance criteria lose authority. Then every handoff recreates the same interpretation problem.

Keep the ACs attached to the work item. Update them when a meaningful decision changes. Use them in planning, build, test, and review. That’s how they become a real contract instead of a ceremonial checklist.

A team that does this well ships with fewer surprises because everyone, including any AI agents in the loop, is working from the same definition of acceptable.


If your team has good ideas but weak specs, Tekk.coach helps turn rough feature requests into execution-ready, security-aware requirements that humans and AI agents can both work from. It’s built for product managers, indie makers, and small dev teams that need clearer planning, tighter scope control, and a single source of truth before code starts.