# Acceptance Criteria

Course: [Intent Engineering](https://www.devtutorials.ai/learn/intent-engineering) · Section: Foundations
Source: https://www.devtutorials.ai/learn/intent-engineering/foundations/acceptance-criteria

> Write acceptance criteria as Given, when, then checks that a runner can execute. Prove they work by catching three planted bugs while the correct build passes. Then download your v1 spec kit: intent.md and spec.md for your tool.

## "Done", With Nothing to Prove It

Remember Run 4 in the Guess Gallery?

The agent followed every requirement. It built the feature. It ran a small test. Then it said:

```text
Done.
```

But there was still a bug in the result.

Nothing noticed it, because nothing checked the result properly.

This is a **verification gap**.

**Verification Gap** = the work looks finished, but nothing proves it is right.

**Simple lesson:** "done" is only a word until a check proves it.

### A Real-World Example

You order a cake for 12 people.

"The cake is nice" is not a check. Every baker says their cake is nice.

"There are 12 slices" is a check. You can count them.

Acceptance criteria are checks like that, for software.

Click the button and open the **Agent** tab.

- **The requirements:** there are three, and they are good.
- **The acceptance criterion:** there is only one, "the export works correctly". The lab marks it **NOT EXECUTABLE**.
- **The builds:** the lab tries three builds, each with a planted bug. All three **survive**.

The requirements were not the problem.

The problem is that nothing could check the result.

**Simple lesson:** requirements say what to build. Acceptance criteria prove it was built right.

## TL;DR

1. **Acceptance criterion (AC)** = a check that proves a requirement was built correctly.
2. Write each one as **Given, when, then**:
   - **Given** = the starting state.
   - **When** = the action.
   - **Then** = the result you can see.
3. The Then must be something a check can see, such as:
   - a number of rows
   - a date format
   - a button
   - a status code
4. "It works" or "the export is correct" cannot be checked.
5. A good check passes the correct build and fails a buggy build.
6. **Mutation testing** = planting bugs on purpose to see if your checks catch them.
7. At the end of this lesson, you download your **v1 spec kit**: `intent.md` and `spec.md`.

## What You Will Learn

In this lesson, you will learn:

1. What an acceptance criterion is.
2. How it is different from a requirement.
3. How to write one with Given, when, then.
4. What makes a Then something a check can see.
5. How planted bugs prove your checks work.
6. How to export your first spec kit for your tool.

**About the builds in this lab**

- There are four **simulated** builds.
- One build is correct.
- Three builds each have one planted bug.
- Your checks run against all four, using fixed rules. No AI grades anything.

## What an Acceptance Criterion Is

### Requirement vs Acceptance Criterion

**Requirement = what to build.**

Example:

```text
When the user clicks Export, the grid shall export only the rows shown by the current filter.
```

**Acceptance criterion = how to check it was built right.**

Example:

```text
Given a filter that shows 2 rows, when the user clicks Export, then the file has 2 data rows.
```

You need both.

- The requirement removes a guess before the work starts.
- The acceptance criterion proves the result after the work is done.

**Simple lesson:** a requirement without a check is a promise nobody tests.

### Given, When, Then

Every acceptance criterion has three parts:

- **Given** = the starting state.
- **When** = the action.
- **Then** = the result you expect to see.

Example:

- **Given:** a filter that shows 2 rows.
- **When:** the user clicks Export.
- **Then:** the file has 2 data rows.

In the lab, start each line with an ID like `AC-1:`.

The runner uses the ID when it shows the results.

If a line does not have all three parts, the runner cannot use it. The lab shows **NOT EXECUTABLE** and tells you why.

## Make the Then Something a Check Can See

### Something a Check Can See

Most weak acceptance criteria go wrong in the Then.

A check can see these:

- "the file has **2 data rows**"
- "the Created cell is **2026-10-01**"
- "an error message with a **Retry button** is shown"
- "the response is **503** with a Retry-After header"

A check cannot see these:

- "it works"
- "the export is correct"
- "the user is happy"

A check can count rows. It can read a value. It can find a button or a status code.

But it cannot tell if something "works". That word means different things to different people.

**Simple lesson:** if a robot could not answer yes or no, rewrite the Then.

### The Given Must Set Up the Then

The Given must create the situation the Then talks about.

Example:

```text
Given a normal day,
when the user clicks Export,
then a Retry button is shown.
```

This check is wrong. Nothing failed, so there is no reason for a Retry button.

Another example:

```text
Given some data,
when the user clicks Export,
then the file has 2 rows.
```

This check is not finished. The Given does not say how many rows the filter shows.

Watch one check get better, step by step:

The check only works once the Given and the Then agree.

**Important:** a check that fails on the correct build is a broken test.

If the Given says 2 rows, the Then must expect 2 rows.

## Prove Your Checks With Planted Bugs

### Mutation Testing

How do you know your checks are good?

Try them on builds that you know are wrong.

The lab has four builds:

1. The correct build.
2. A build that ignores the filter.
3. A build that writes dates in the wrong format.
4. A build with no Retry action.

Two words to know:

- **Caught** = at least one check fails on the buggy build.
- **Survives** = every check passes, so the bug gets through.

**Mutation testing** = planting small bugs on purpose to see if your checks notice them.

Watch what happens as checks are added, one at a time:

Each check catches one bug. You need one check for each requirement.

**Simple lesson:** a set of checks is only as good as the bugs it catches.

### Lab Exercise: Catch All Three Planted Bugs

Open the spec. Replace this line:

```text
the export works correctly
```

Write checks for every requirement, so that every planted bug is caught.

Press **Check my spec**, then open **Preview & Checks**.

A table shows each check against each build.

You pass when:

- the correct build passes every check;
- every buggy build is **caught**.

**Start with one check per requirement.**

This spec has three requirements:

- the filtered rows
- the date format
- the Retry after a failure

## Your v1 Spec Kit

### What Is in the Kit

You now have two files:

- **`intent.md`** from the Problem Statements lesson
- **`spec.md`** from this lesson

Together, they say what to build and how to check it.

The export puts the files where your tool expects them:

| Tool | Main file | Also adds |
|---|---|---|
| Claude Code | `docs/specs/excel-export/intent.md` | `CLAUDE.md` |
| Spec Kit | `specs/001-excel-export/spec.md` | `.specify/memory/constitution.md` |
| Kiro | `.kiro/specs/excel-export/requirements.md` | `.kiro/steering/product.md` |

It also adds a line to files like `AGENTS.md` or `CLAUDE.md`. That line tells the agent to read the spec before it decides anything.

Spec Kit and Kiro do not use a separate intent file. For those tools, your intent goes inside the spec file.

The zip also holds extra files, such as templates, a plan and review tools.

### Lab Exercise: Download Your v1 Spec Kit

Open the **Export** tab and choose your tool.

Both files must pass their checks before the download is ready.

If `intent.md` is not finished, go back to the Problem Statements lesson first.

When every check passes, download the zip file.

The README inside has prompts you can try in your tool.

## What Changes per Tool

| Tool | Where ACs live |
|---|---|
| Claude Code, Codex, Cursor | under Acceptance criteria in `docs/specs/<feature>/spec.md` |
| Spec Kit | acceptance scenarios under each user story in `specs/<NNN-feature>/spec.md` |
| Kiro | acceptance criteria under each requirement in `.kiro/specs/<feature>/requirements.md` |

Given, when, then works the same way in every tool.

Only the place where the checks are kept is different.

## Common Mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Writing "the export works correctly" | It sounds like a check. | "Then the file has 2 data rows." | Nothing can run it, so every bug gets through. |
| A Then that does not match the Given | "A stricter check is better." | Given 2 rows, then 2 rows. | The correct build fails, so the test is broken. |
| Checking Retry when nothing failed | "Just check that the Retry button exists." | Given the export fails, then a Retry button is shown. | The Retry never shows, so it is never checked. |
| One check for everything | "One good check is enough." | One check for each requirement. | Bugs in the other requirements get through. |
| Trusting the agent's own test | "It said tested and done." | Write your own checks, from the stakeholder's view. | The agent's test only checks what it built. |
| Never testing your checks | "They look right." | Run them against planted bugs. | A hole in your checks stays hidden. |

## Exercises

These exercises help you practise writing checks that really work.

Press **Check** when you are ready. Use **Show Hint** if you get stuck.

## What to Remember

- Requirements say what to build.
- Acceptance criteria prove it was built right.
- Write every check as Given, when, then.
- The Then must be something a check can see.
- The Given must set up the situation the Then talks about.
- Good checks pass the correct build and catch the planted bugs.
- Your v1 spec kit holds `intent.md` and `spec.md`, ready for your tool.

## Further Reading

- [Harness engineering, by OpenAI](https://openai.com/index/harness-engineering/): why humans turn feedback into acceptance criteria.
- [GitHub Spec Kit](https://github.com/github/spec-kit): acceptance scenarios under each user story.
- [Kiro specs](https://kiro.dev/docs/specs/index): acceptance criteria under each requirement.

Next: **API Contracts**. You will learn how a clear contract stops the agent from inventing function names.
