A Definition of Done checklist for AI-generated code that goes beyond passing tests: EARS acceptance criteria, security review, and an enforced gate.
Definition of Done for agent-authored code needs a harder bar than compiling: a fixed, checkable list of what ready to merge actually means, confirmed by a mechanism rather than a feeling. A pull request that compiles and passes every test has cleared two checks, not earned a merge. For code an AI agent wrote, that gap is wider than it looks, because the same context window that wrote the implementation frequently wrote the tests too, so a green run confirms the code does what the agent believes it does, not what the ticket actually asked for.
Most teams that already have a Definition of Done wrote it for human pull requests and never revisited it once agents started opening most of them. It tends to read like code reviewed and documentation updated, phrased loosely enough that a rushed reviewer, human or agent, can claim the box is checked without doing the work behind it. What agent-written code needs is closer to a contract: acceptance criteria specific enough that meeting them is not a judgment call, plus a small, fixed set of checks that apply to every change no matter what it touches. Building both, and making them checkable rather than aspirational, is what a real Definition of Done for AI-generated code has to do.
Why compiling and passing tests are not a Definition of Done
Compiling proves the code is syntactically valid and type-correct. It says nothing about whether the logic matches what was asked for; a function can compile cleanly while solving the wrong problem entirely. Passing tests only narrows that gap if the tests were written independently of the implementation. When an agent writes the code and the tests for it in the same pass, the tests tend to assert on whatever the code currently produces rather than what the specification says it should produce, so a suite at 100 percent pass rate can still verify nothing real. That is how tautological assertions and mock-heavy tests slip past a green build. The short version is that a passing suite and a correct implementation are correlated, not identical, and that gap is where a Definition of Done has to do its work.
Definition of Done is not the same thing as acceptance criteria
Acceptance criteria describe what one specific piece of work must do. Definition of Done describes the bar every piece of work has to clear, regardless of what it does. Teams that only track acceptance criteria per ticket end up re-deciding, change by change, whether security got reviewed or documentation got written. Teams that only have a generic Definition of Done end up with a checklist too vague to confirm whether this particular change does what it was supposed to. The official Scrum guidance describes the Definition of Done as a formal commitment: a fixed description of the quality measures a piece of work has to meet before it counts as complete, applied the same way across every item rather than negotiated per change.
Sources: Scrum.org, "What is a Definition of Done?"
EARS turns acceptance criteria into statements you can test
EARS, the Easy Approach to Requirements Syntax, gives acceptance criteria a small, fixed grammar so each requirement maps almost directly onto a test case instead of a paragraph someone has to interpret. Alistair Mavin and colleagues developed it at Rolls-Royce while writing requirements for a jet engine control system and published it in 2009. It has since spread well beyond aerospace into software teams that need requirements precise enough for an agent, not just a person, to act on correctly.
Sources: Alistair Mavin, "EARS: Easy Approach to Requirements Syntax"
- Ubiquitous: the system shall respond a certain way at all times, with no trigger needed. Example: the upload endpoint shall reject any file over 25MB.
- Event-driven: when a trigger occurs, the system shall respond. Example: when a request omits its Authorization header, the API shall return 401.
- State-driven: while a precondition holds, the system shall respond. Example: while a migration is running, the service shall reject writes to the affected table.
- Unwanted behavior: if a trigger occurs, then the system shall respond. Example: if the payment provider times out, then the order shall roll back and the customer shall see a retry option.
- Optional feature: where a feature is included, the system shall respond. Example: where multi-currency is enabled, the invoice shall show a currency code beside every amount.
Each of those five patterns reads almost like the title of a test. That is the point: a spec written in EARS gives an agent, and whoever reviews its output, a fixed target to write the test against, independent of whatever the implementation ends up doing. The patterns also combine, naming a precondition, a trigger, and a response in one sentence, which is closer to what a real agent-facing spec usually needs than any single pattern alone. Writing acceptance criteria this way front-loads the argument about what done means, before an agent starts rather than after it finishes. A reviewer arguing with a finished diff about what the ticket actually intended is negotiating after the fact, with the implementation already anchoring the conversation. A reviewer checking a diff against acceptance criteria agreed on before any code was written is checking a fact, not relitigating an assumption.
What belongs in a real Definition of Done checklist
A checklist worth enforcing splits into two halves: whether the behavior is actually verified, and whether the change is safe to ship regardless of whether the behavior is correct. Both halves need their own line items, because a change can pass every behavioral test and still be unsafe to merge for reasons that have nothing to do with logic.
Behavioral completeness
- Every acceptance criterion in the spec, ideally written in EARS, has a test that asserts the documented behavior rather than the current output of the implementation.
- Edge cases named in the spec, plus the standard set of empty, null, boundary, duplicate, concurrent, and failure-path inputs, are each covered by a test that would fail if that behavior broke.
- At least one test has been checked against a deliberately broken version of the logic, by inverting a condition or flipping a comparison by hand, to confirm the suite would actually catch it.
- No test asserts against a mock of the exact unit under test; mocks are reserved for true external boundaries such as the network, disk, or clock.
- The tests exist before the change is treated as reviewable, not written afterward to match whatever the implementation already does.
Operational readiness
- A review pass has looked at the diff specifically for security: authentication, authorization, injection paths, and how secrets and credentials are handled, not folded into a general logic review.
- The change is documented at the point a future reader will actually look, explaining why this approach was chosen and what it assumes, not just restating what the diff already shows.
- A way back exists if the change misbehaves in production: a flag, a toggle, or a reversible migration, not reverting the commit and redeploying as the only option.
- Dependencies the agent pulled in are checked against project policy, since an agent optimizing for a working diff has no built-in reason to prefer the dependency a human maintainer would choose.
- The diff touches only the files and behaviors the spec named. Anything else is a second, unreviewed change riding along with the first, and holding that boundary during implementation, not just at review time, needs its own enforcement.
The security line item earns a specific pass rather than a checkbox inside a general review, because the bug classes it exists to catch do not surface when someone is reading purely for correctness. The OWASP Secure Code Review Cheat Sheet groups the checks worth running into input validation and injection, authentication and session handling, authorization and access control, cryptography and secrets, business logic integrity, and secure configuration. An agent-written diff that looks clean to a functional reviewer routinely fails several of those categories at once, because the model optimized for the happy path the ticket described, not for what a hostile input would do to the same code.
Sources: OWASP Cheat Sheet Series, "Secure Code Review Cheat Sheet"
A representative miss looks like this: an endpoint that checks whether the requesting user is authorized, then performs a database write, then logs the action, works exactly as intended for every input a functional test tries. That is because the check runs before the write. An agent refactoring that same endpoint later, focused only on the ticket in front of it, can just as easily move the write earlier for a performance reason and never notice the check now runs after the damage is already done. Nothing in a green test suite catches that reordering unless a test was written specifically to catch it, which is what a distinct security pass exists to force.
A rollback plan does not have to mean a rollback runbook nobody has tested. The cheapest version is a feature flag: ship the change dark or behind a small percentage rollout, watch the metrics that matter, and disable it with a configuration change instead of a redeploy if something goes wrong. An article by Martin Fowler on feature toggles describes exactly this pattern: releasing to a small canary cohort first, and using an operational toggle to degrade or disable a feature without shipping new code, which turns a rollback from an emergency deploy into a switch someone already built.
Sources: Martin Fowler, "Feature Toggles (aka Feature Flags)"
Turning the checklist into a gate, not a memory test
A Definition of Done that lives on a wiki page is advice, and advice gets skipped the day a deadline moves. The fix is mechanical: attach every line item to a check that runs without anyone having to remember it exists, so meeting the Definition of Done and passing the pipeline become the same event instead of two separate promises.
A checkbox in a PR template answers whether someone claims the work was done, not whether it was. An agent, like a person under deadline pressure, will check a box if checking it is free and nothing verifies the claim behind it. The difference between a checklist and a gate is whether unchecking the box is even possible: a gate ties the claim to evidence, a test result, a review approval, a filled-in field, so the pull request cannot reach a mergeable state without producing the artifact the checklist item was actually asking for.
- EARS-derived acceptance tests and edge-case tests run as a required CI job, not a suggestion left in the PR description.
- A mutation or hand-inversion spot check runs on the changed lines before merge, so a suite that would not catch a real regression cannot pass silently.
- The security pass is a required, separate reviewer or agent role on the pull request, distinct from the general code review approval.
- The PR template will not submit without a filled-in rollback field and a one-line rationale for the approach, so documentation is a form field instead of a follow-up task.
Enforcing that kind of gate by policy tends to fail the same way a wiki checklist does: it holds until someone is in a hurry. That is the specific problem TLM Forge is built around. A goal contract and a plan get signed off before any code exists, the same discipline EARS pushes a person to do by hand. Implementation runs under enforced test-driven development, with a failing test written before the code and a full passing run of the suite captured as evidence rather than claimed. A red-team pass reviews the diff separately from the reviewer checking correctness, aimed specifically at the class of mistake a functional read walks past. The result is a scored gate that stays shut while a critical finding is still open, which is what keeps a Definition of Done from being the first thing quietly dropped when the schedule gets tight.
| What It Confirms | It Compiles | Tests Pass | Definition of Done Met |
|---|---|---|---|
| Syntax and types are valid | Yes | Yes | Yes |
| Behavior matches the spec, not just the implementation | No | Sometimes | Required |
| Edge and failure-path cases are covered | No | Rarely | Required |
| The suite would catch a real regression, not just execute the code | No | Unverified | Required |
| A dedicated security-focused pass has reviewed the diff | No | No | Required |
| A rollback path exists if the change misbehaves | No | No | Required |
Frequently asked questions
01What is the difference between Definition of Done and acceptance criteria for AI-generated code?
Acceptance criteria describe what one specific change must do, ideally written in EARS syntax so each statement maps to a test. Definition of Done is the fixed checklist every change has to clear regardless of what it does, covering security review, documentation, a rollback path, and tests that verify behavior instead of mirroring the implementation.
02What is EARS syntax and why does it help with AI coding agents?
EARS, the Easy Approach to Requirements Syntax, is a small set of sentence templates developed at Rolls-Royce and published in 2009 for writing requirements as unambiguous, testable statements. Each EARS requirement maps closely to a test case, removing the guesswork an agent would otherwise use to infer what done actually means.
03Can a passing test suite prove that AI-generated code is actually done?
No. A passing suite proves the tests as written did not fail, which differs from proving the code matches the specification. Tests generated by the same agent that wrote the implementation often assert on the current output rather than the intended behavior, so they pass even when the logic is wrong.
04Does AI-generated code still need a security review if static analysis already passed?
Yes. Static analysis and linters catch known patterns; they do not catch business-logic flaws such as an authorization check placed after a side effect, which is exactly the class of bug a dedicated security-focused review is meant to find in code an automated scanner reads as clean.
05How do you stop a Definition of Done checklist from getting skipped under deadline pressure?
Attach each item to a mechanical check instead of a memory: a required CI job for tests and mutation coverage, a required separate security-review approval, and a PR template that will not submit without a rollback field filled in. A checklist nobody has to remember is one nobody can quietly skip.