Writing an Executable Spec
Write the six parts of a spec Quill can build from and Mr. Hale can read: intent, constraints, criteria, verification, human gates, evidence.
Before this: L1 The artifact chain
- Write each of the six parts of an executable spec: intent, constraints, acceptance criteria, verification, human gates, evidence.
- Turn a vague request into observable acceptance criteria.
- Pair each criterion with a verification command that exits non-zero on failure.
- Name where a human must approve, override, or escalate, and who that person is.
- Explain why the spec is committed with the code derived from it.
Why this matters
Omar opens spec.md for CR-102 and types one line: "Add gift card refunds." He hands it to Quill. Forty minutes later there is a PR with a Refund button on the gift card page. The tests pass. Any logged-in staff member can press the button, for any amount, and nothing is written down when they do. Priya reads the PR and lists her rules from memory: store managers only, never more than the original purchase, every refund logged. None of those rules were in the file, so none of them are in the code. Quill did exactly what it was asked. The problem is what it was asked. This lesson teaches you to write the file so a request cannot leave those gaps.
1. A spec an agent can build from and an auditor can read
An executable spec is a spec.md written so that two very different readers get what they need from it. Quill needs enough detail to build the right thing without guessing. Mr. Hale, the auditor, needs to see what was promised, who agreed, and how you would know if the promise was broken. One file serves both when it has six parts.
| Part | Question it answers | Who cares most |
|---|---|---|
| Intent | What outcome are we after? | Nadia |
| Constraints | What must not change, and what boundaries apply? | Priya |
| Acceptance criteria | What behaviors prove it is done? | Quill, Omar |
| Verification | Which command checks each criterion? | Quill, CI |
| Human gates | Where does a person decide, and who? | Priya, Omar |
| Evidence | What is recorded, where, and who signs it? | Mr. Hale |
Each part exists because a specific thing goes wrong without it. No intent, and Quill builds toward the wrong outcome. No constraints, and it opens a system it should never touch. No criteria, and "done" is whatever the PR does. No verification, and the criteria are opinions. No human gates, and money moves without a person. No evidence, and a year later nobody can prove any of it.
2. Part 1, Intent
Intent is the business outcome in one sentence, in plain words, with no implementation detail. It comes from intent.md, which Nadia accepted in L1, and it is copied into the top of spec.md so the spec cannot drift from what she agreed to.
The test for an intent sentence: could Nadia say "yes, that is the outcome I want" without asking an engineer what it means? If she has to ask, it is not intent yet.
3. Part 2, Constraints
A constraint is a rule the change must obey no matter how it is built. Constraints come in three kinds: which systems the change may touch, which data boundaries apply, and which regulatory or policy limits are in force. A data boundary is a line between data the change may read or write and data it must never reach.
The card processor line is the one Omar would have skipped. To Priya it is the difference between a bookkeeping entry and money leaving the bank.
4. Part 3, Acceptance criteria
Acceptance criteria are observable behaviors, written before any code is generated, that together define "done." Observable means something outside the code can watch it happen: a response, a screen, a table row, an error message. Each criterion is true or false, never "mostly."
| Bad criterion | Why it fails | Good criterion |
|---|---|---|
| "Refunds work correctly." | Nothing to observe | "A refund of $30 on a $50 card sets the balance to $20." |
| "Only the right people can refund." | Who? | "A request from a staff role returns 403 and changes nothing." |
| "Refunds should be limited." | To what? | "A refund larger than the original purchase is rejected with over_purchase." |
| "Refunds are tracked." | Where? How? | "Every successful refund writes one row to refunds with manager id and amount." |
Count Priya's rules from the opening story: managers only (3), never more than the purchase (2), every refund logged (5). The other two came from asking her one more question.
5. Part 4, Verification
A verification command is paired with one criterion, runs the check, and reports the result by its exit code. The rule is non-zero exit on failure: 0 when the criterion is met, any other number when it is not. This is why the spec is "executable." A criterion with a command can be checked by Quill, by gate.sh in L4, and by CI in L6, without anyone reading anything.
The pairing for all five:
| Criterion | Command |
|---|---|
| 1. Manager can refund up to purchase price | make test-refund-happy |
| 2. Over purchase is rejected | make test-refund-limit |
| 3. Non-manager gets 403 | make test-refund-role |
| 4. Over $200 waits for Priya | make test-refund-hold |
| 5. One row per refund | make test-refund-log |
One command per criterion is deliberate. When make test-refund-role fails, everyone knows which promise broke. When one giant run fails, someone has to read the log.
6. Part 5, Human gates
A human gate is a point where the work pauses until a named person approves, overrides, or escalates. Every change that moves money, touches personal data, or cannot be undone needs one. The spec says three things per gate: the condition that triggers it, the person who decides, and where the decision is recorded.
The word "named" matters. "Approval from a senior person" is not a gate, because on the day it matters nobody knows who that is. "Priya, or Nadia when Priya is away" is a gate. Same for the threshold: "large refunds" is a feeling, $200 is a number.
L4's hooks come from this section. The hook that returns ask for a refund over $200 is the code version of this paragraph. The paragraph comes first.
7. Part 6, Evidence
Evidence is the record that a rule was followed, written automatically, stored where it cannot be quietly edited, and signed off by a person. The spec says what is logged, where it lands, and who confirms it before merge. Mr. Hale reads this part first. Most specs leave it out, because nothing breaks on the day you skip it.
Evidence also includes what the PR carries, as a checklist Omar completes and the reviewer confirms.
8. Policy while writing, not in review
The opening story went wrong at one moment: Priya's rules reached the work after the code existed. The fix is to read her policy while drafting, not while reviewing the PR. Priya is the policy owner for payments and customer data, so the constraints and human gates sections are routed to her before Quill starts. Ten minutes of her time before generation replaces a rewrite after.
The spec and the code are a file pair: the spec is committed in the same PR as the code derived from it, so the repository holds what was asked next to what was built. If someone later changes the refund limit, the diff shows the spec line and the code line moving together, or one moving without the other, which is a finding of its own.
The full spec.md for CR-102, all six parts in one file:
# CR-102: Refund a gift card purchase
Author: Omar · 2026-09-12 · Policy owner: Priya · Reviewer of record: TBD at PR
## 1. Intent
A store manager can refund a customer's gift card purchase from Shelf,
so customers no longer wait for head office to process refunds by hand.
## 2. Constraints
- Touches the payments service. Never touches the card processor.
- store_manager role only, checked on the server.
- Data boundary: reads/writes gift_cards and refunds. Never reads customers.email.
- Stored-value policy applies. Priya confirms this section before generation.
## 3. Acceptance criteria
1. A store_manager can refund up to the original purchase price.
2. A refund above purchase price is rejected with over_purchase; balance unchanged.
3. Any other role gets 403 and no row is written.
4. A refund over $200 is held as pending_approval until Priya approves.
5. Each successful refund writes one refunds row: manager, card, amount, time.
## 4. Verification (exit non-zero on failure)
1 make test-refund-happy · 2 make test-refund-limit · 3 make test-refund-role
4 make test-refund-hold · 5 make test-refund-log
## 5. Human gates
Over $200: Priya approves or rejects in Shelf admin. Nadia covers when Priya is away.
Decision, user id, and time are written to the refund row.
## 6. Evidence
One JSON line per refund to the refund log, shipped nightly to the audit bucket.
PR carries: this file, all five make outputs, Priya's confirmation link,
one sample log line, and the named reviewer of record.
Summary
- An executable spec has six parts: intent, constraints, acceptance criteria, verification, human gates, evidence. Each part prevents a specific failure.
- Acceptance criteria are observable, true-or-false behaviors written before any code is generated.
- Every criterion pairs with one verification command that exits non-zero on failure, so the spec can be checked by a script, not an opinion.
- A human gate names a condition, a person, and where the decision is recorded. "Over $200, Priya" is a gate. "Large refunds need review" is not.
- Read the policy owner's rules while drafting, route the constraints and gates to her before generation, and commit the spec with the code as a file pair.
Key terms in this lesson
Check your understanding
Pick an answer to see why it is right or wrong. These are graded in code, instantly.
Apply it
Write your answer in your own words. Eve grades it against a rubric and gives you feedback, the same way an LLM judge works in Lesson 5.
Nadia's ticket for CR-103 says "the export should be safe." Turn that sentence into two observable acceptance criteria for the newsletter email export.
Write the Constraints and Human gates sections of spec.md for CR-103, the newsletter email export. Name the systems touched, the data boundary, the policy that applies, and at least one gate with a condition, a named person, and where the decision is recorded.
Homework 1 — An executable spec for CR-102
Write a complete six-part spec.md for CR-102, "Let a store manager refund a gift card purchase," as if you were Omar and Priya had not yet seen it.
Use the Bramble Books world exactly: Shelf is the app, Quill is the agent, Nadia owns intent, Priya owns payments policy, Mr. Hale will read it next year. Your file must have these six headed sections, in this order: Intent, Constraints, Acceptance criteria, Verification, Human gates, Evidence.
Requirements:
- Intent is one sentence in business terms with no implementation detail.
- Constraints name the systems touched, at least one system never touched, a data boundary in terms of tables or fields, and Priya as policy owner.
- Acceptance criteria are at least four observable, true-or-false behaviors written before any code. Do not copy the lesson's five verbatim; at least one criterion must be your own.
- Verification pairs every criterion with one command (a
maketarget or a test command) and states that it exits non-zero on failure. For one command, describe in two or three sentences what the test sets up and what it expects. - Human gates name a condition, a named person, a fallback person, and where the decision is recorded.
- Evidence names what is logged, where it lands, and what the PR must carry.
Keep the whole file under 60 lines. Submit it as one markdown code block, followed by a short paragraph (under 100 words) saying which single line you think Priya would push back on and why.
- One `spec.md` in a markdown code block with all six headed sections in order
- A description of what one verification command sets up and expects
- A paragraph under 100 words naming the line Priya would question and why
Paste your homework write-up below. Include every deliverable.
Instructor notes(for whoever is teaching this lesson)
Talking points
- The one-line spec is the thread. For each of the six parts, ask which of Priya's three rules it would have captured.
- Two readers, one file. Quill needs enough to build without guessing. Mr. Hale needs to see what was promised and how anyone would know.
- "Observable" is the word to hammer. A criterion is something you could watch from outside the code: a response, a row, a screen, a log line. "Works correctly" is not observable.
- One criterion, one command, non-zero on failure. That sentence makes the spec executable and bridges to L3, L4, and L6.
- A human gate is a condition, a named person, and a place the decision lands. Two out of three is not a gate.
- Policy while writing, not in review.
Live demo idea
Put the one-line spec, "Add gift card refunds," on screen and ask the room to list everything Quill would have to guess: who may refund, how much, what happens over a limit, what is logged, which tables. Then open the full CR-102 spec.md and have the class match each guess to the section that answers it. Finish with make test-refund-limit: describe the test in one sentence, ask "what happens if Quill checks the wrong field?" and let someone say "exit 1."
Common misconceptions
- "The intent should say how." Intent is the outcome in Nadia's words. The how belongs in
plan.md. - "Acceptance criteria are the test names." Criteria come first and are written in plain language. Tests are derived from them, one command per criterion.
- "A firm sentence in the spec is enforcement." The spec is the contract. Enforcement arrives in L4 with hooks.
- "Evidence is the PR being merged." Evidence is a record written by the system: a log line, a make output, an approver id. A green merge button proves nothing on its own.
- "Priya reviews the PR." Priya reviews constraints and human gates before any code exists. At the PR she confirms nothing drifted.
Timing
Sixty minutes: story and section 1, seven; intent, four; constraints, seven; acceptance criteria with the good-versus-bad table, ten; verification, eight; human gates, eight; evidence, six; policy and the full spec, ten.
If you only have 20 minutes
Run the whiteboard demo with the one-line spec (six minutes), teach acceptance criteria and verification together using the five-criteria table and the make test-refund-limit example (ten minutes), then close on the full spec.md with the human gate line circled (four minutes). Assign sections 2, 3, and 7 as reading and set HW1.