Path to AI Architect · Chapter 10 of 25
Specification-Driven Development with AI
Build reusable context packages and acceptance tests, and turn features into bounded tasks AI can implement.
32 min read Slides for this chapter
Opening scenario: “Add instructor accounts”#
Dr. Okafor teaches the statistics course that half the testers were taking. She liked what she saw over their shoulders and asked Maya a simple question: could she invite her students, and see who was falling behind before the midterm, not after?
Chapter 3 had put teacher dashboards on the “won't have this time” list. Now there was a real user asking, with evidence behind the request, and Maya had a week. She opened an agent session and typed: “Add instructor accounts so lecturers can invite students and see their progress.”
The agent worked for most of an afternoon in one long session. The result looked finished: an instructor sign-up, a class page, an invite link, a dashboard with a row per student. Then Maya and Priya tested it, and four problems appeared, one after another.
- Instructors saw too much. Each dashboard row listed the student's task titles for the week and the names of her uploaded notes. Nobody had decided what an instructor should see. The agent had chosen “everything on the student's plan page,” which is a reasonable guess and the wrong one. Worse, the invite link added students to a class as soon as they opened it. Priya was in Dr. Okafor's class before she knew a class existed.
- A rule disappeared. Late in the session, the agent extended the weekly review from chapter 9 so the assistant could say “three of your students are behind.” To make the message friendlier, it put the students' first names into the prompt. The project instructions say, in plain words, that names never go to the AI provider (chapter 3's NFR-5). The rule was there at the start of the session. Four hours and dozens of files later, it no longer shaped what the agent did.
- A change went undocumented. To mark instructors, the agent added a
rolefield toGET /meand, while it was there, renameddisplay_nametoname. The student settings page broke. The PRD, the contract table, and the generated types all still described the old shape. - Two halves didn't meet. Maya had started a second session for the invite screen, to save time. That session assumed invite links looked like
/join/{class_id}. The backend session had built/invite?code=…. Each half passed its own tests.
None of these is a coding mistake in the usual sense. Each is a decision nobody wrote down, and the agent made it anyway, quickly and plausibly. The prompt was one sentence. The feature needed a specification.
Why it matters#
Part II gave the Learning Coach its parts, each with a contract. Part III is about building and changing those parts with agents, every week, without losing control of them.
A one-line prompt works for a small, self-contained change, because the agent can see everything that matters. It stops working when a feature crosses modules, touches personal data, or takes more than one session. GitHub's announcement of its Spec Kit toolkit puts the problem simply: a vague request makes the model guess at a great many unstated requirements, it will guess some of them wrong, and you often find out late (Delimarsky, 2025).
Specification-driven development answers this by writing the decisions down before the agent starts, in a form the agent can read and you can check against: what the feature does, what it must not do, where it lives in the code, and how anyone will know it works. The architect's job is to make those decisions, package them so every session starts with the right context, cut the work into tasks small enough to verify, and keep the documents true as the code changes.
Learning objectives#
After this chapter you will be able to:
- Explain why vague prompts fail on larger features: missing assumptions, lost instructions, undocumented changes, and misaligned interfaces.
- Assemble a specification package: problem and constraints, feature specification with acceptance examples, architectural boundaries and a repository map, and test and release requirements.
- Decompose a feature into vertical, dependency-ordered tasks, each with inputs, outputs, files, boundaries, and evidence of completion.
- Run an execution loop that inspects, plans, implements a constrained change, verifies it, and ends in human review.
- Engineer the context agents work from: persistent instructions, relevant files, permission boundaries, and regular removal of stale instructions.
- Produce a feature spec, a context pack, a task graph, and a completion checklist for a real feature.
10.1 Why vague prompts stop working at scale#
Missing assumptions and implicit requirements#
Every feature carries requirements nobody says out loud, because to the person asking they are obvious. Dr. Okafor would never expect to read a student's notes; Maya would never add a student to a class without asking. To an agent, nothing is obvious. It fills each gap with the most common pattern it has seen, and the most common pattern for “a dashboard of users” is to show everything about them.
The gaps cluster in predictable places: who may see what, what happens on the unhappy paths, what the feature must leave untouched, and which earlier decisions still apply. Chapter 3 found them in a product; they reappear in every feature. The difference now is scale. One gap in a one-screen change produces one wrong guess. A feature with four roles, two new tables, and a privacy question produces dozens, and the agent doesn't tell you which ones it guessed.
Context overflow and lost instructions#
Chapter 2 noted that early instructions drop out of view in a long conversation. With agents, the effect is stronger, because the agent fills its own context: every file it reads, every command output, every failed attempt stays there. Anthropic's guidance for its coding agent names this as the constraint behind most of its advice: the context window fills quickly, and performance degrades as it fills, with earlier instructions forgotten and more mistakes made (Anthropic, Best practices for Claude Code).
Researchers at Chroma measured the effect directly. Across 18 models, holding the task fixed and changing only the length of the input, performance became less and less reliable as inputs grew, even on simple tasks, and topically related but irrelevant text made it worse (Hong et al., 2025). A long agent session is exactly that kind of input: thousands of lines of related but mostly irrelevant code, surrounding one rule that matters. Bigger context windows let a session run longer. They don't make every token in it count equally.
Undocumented changes#
An agent changes whatever helps it finish. Renaming display_name to name made the dashboard slightly tidier and silently broke a contract the web app depended on. When a change isn't written into the specification, the next session works from an outdated picture, reviewers can't tell intended changes from accidental ones, and the documents that brief agents become wrong without anyone noticing. Chapter 3's rule still holds: change the document first, then the code.
Misaligned interfaces#
When two sessions build two sides of an interface, each fills the gaps in its own way. Chapter 6 gave the fix for one slice: commit the contract before either side starts. A larger feature has several interfaces, and the invite link shows the general rule: anything two pieces of work both depend on must be decided and written down before the work splits.
10.2 A specification package#
A specification package is everything an agent session needs to do its part of a feature correctly, kept in the repository. It has four parts. Some are written once for the whole product; others are written for each feature.
| Part | Scope | Lives in |
|---|---|---|
| Problem statement and constraints | Product-wide, refined per feature | docs/prd.md (chapter 3) |
| Feature specification and acceptance examples | One feature | docs/specs/instructors.md |
| Architectural boundaries and repository map | Product-wide | Project instructions, docs/architecture.md, ADRs |
| Test and release requirements | Product-wide, with feature additions | Definition of done, CI configuration |
Birgitta Böckeler draws a useful line between the two kinds of document. General context, such as rules files and descriptions of the product and codebase, applies to every session. A specification applies only to the tasks that build or change that particular feature (Böckeler, 2025). Keeping them apart keeps both short.
Problem statement and constraints#
Start the feature specification with the problem, not the solution: who needs what, and why now. Then list the constraints: the decisions already made that the feature must respect. For instructor accounts, they come from earlier chapters:
- Students' notes, tutor questions, and task titles are theirs alone (chapter 7's data classification).
- Names and emails never go to the AI provider (NFR-5, as revised in chapter 9).
- Deleting an account removes all of the student's data within 7 days (NFR-6).
- Every query on student data is authorized in the query itself, and a missing record and a forbidden record look the same (chapter 6).
Then list what the feature won't do, such as messaging or grades, so no agent builds them because they seemed natural.
Feature specification and acceptance examples#
The core of the specification is chapter 3's toolkit applied to one feature: user stories, acceptance criteria as Given/When/Then examples, the states the important things can be in, and open questions. The decisions the vague prompt skipped now have to be made, and written down:
- What an instructor sees: for each student who joined, the share of this week's tasks done, whether she is Behind (chapter 3's plan state), and the date she was last active. Nothing else.
- How a student joins: the invite link opens a page that says exactly what the instructor will see. Nothing is shared until she presses Join.
- How a student leaves: at any time, from settings, and the instructor loses access at once.
Acceptance examples turn those decisions into checks:
Scenario: An instructor sees only students who joined
Given Dr. Okafor's class has an invite link
And Priya has opened the link but not pressed Join
When Dr. Okafor opens the class page
Then Priya is not listed
Scenario: Leaving removes access at once
Given Priya has joined Dr. Okafor's class
When Priya leaves the class from her settings
And Dr. Okafor reloads the class page
Then Priya is not listed
And requesting Priya's progress directly returns "not found"
Write examples for the paths agents skip: a signed-out student, another class's instructor, a deleted account, an empty class.
Architectural boundaries and repository map#
An agent needs to know where the feature goes and where it must not go. The repository map is a short description of the code's layout and who owns what: chapter 6's folder structure, plus a line for each module saying what it's responsible for. The boundaries say which modules the feature may touch, which interfaces are frozen, and which existing decisions apply. For instructor accounts:
- New module
backend/coach/classes/, owning classes, memberships, and invite codes. - It may read progress through the
plansmodule's existing service function. It may not query theplansornotestables directly. GET /meis frozen. Instructor status comes from a new endpoint.- ADR-002 (sign-in) and ADR-005 (tutor) are unchanged.
The decision about who may see a student's data is architecture, so it gets an ADR, the boundaries reference it, and the specification links to it.
Test and release requirements#
Finally, the package says how “done” will be judged. Chapter 3's definition of done applies to every task. The feature adds its own requirements: two instructors and two classes in every access test, a student who left, a student who deleted her account; the privacy review of what instructors see; and an end-to-end check of the full journey, from invite to dashboard to leaving. Anthropic's advice for writing specifications for its agent makes the same point: the most useful ones are self-contained, name the files and interfaces involved, say what is out of scope, and end with an end-to-end verification step that proves the feature works (Anthropic, Best practices for Claude Code).
How much specification?#
Spec-driven tools have arrived quickly, and they differ. Böckeler, comparing three of them in 2025, distinguishes three levels: spec-first, where a spec is written before the work and then set aside; spec-anchored, where the spec is kept and updated as the feature evolves; and spec-as-source, where people edit only the spec and code is generated from it. She also reports the costs: one tool turned a small bug fix into 4 user stories with 16 acceptance criteria, the generated documents were long and repetitive to review, and agents still sometimes ignored instructions despite all the structure (Böckeler, 2025).
Size the package to the change. A one-file fix needs a sentence and a test; a feature that adds a role, a table, and a privacy decision needs the full package. If two fresh sessions given only your documents would build noticeably different things, the documents aren't finished.
10.3 Task decomposition#
Vertical slices and dependency ordering#
Chapter 6 built accounts in vertical slices, one small feature at a time from screen to database. Bill Wake's description of good user stories gives the reason with an image: a story is a layered cake, and a slice is only valuable if it cuts through every layer, because a finished database layer with no screen is worth little to the customer (Wake, 2003). The same holds for agent tasks.
Some work must still come first: every slice depends on the data model and the frozen contracts, so they go first and are reviewed before anything is built on them. Then order the slices by dependency, and within that by risk, so the riskiest decision is tested while changing course is still cheap.
Anthropic's report on agents working across many sessions shows why the order must be explicit. Given only a high-level goal, its agent tended to attempt everything at once, ran out of context partway, and left half-finished, undocumented work; later sessions sometimes saw progress and declared the job done. The fix was a feature list written up front, every item marked failing, with each session told to pick one item, finish it, test it, commit, and record progress (Young, 2025). A task graph in the repository does the same job for you.
Define inputs, outputs, files, and boundaries#
Each task gets a task card, short enough to read in a minute:
- Delivers: the requirement and acceptance IDs.
- Inputs: the documents and files to read first.
- Outputs: the code, tests, and document updates expected.
- May change: the folders the task owns.
- Must not change: frozen contracts and other modules.
- Done when: the evidence that proves it, stated as commands and results.
- Stop and ask if: the conditions under which the agent must not decide alone.
The “stop and ask” list matters most. It covers the decisions a task card can't anticipate: a conflict between documents, a needed change to a frozen contract, a requirement that seems wrong.
Size tasks for independent verification#
A task is the right size when someone can verify it on its own, in one sitting. Wake suggests tasks should be specific enough that they don't overlap, and measurable in one plain sense: can we mark it as done (Wake, 2003). GitHub describes its toolkit's task step the same way: each task should be implementable and testable in isolation, which gives the agent a way to check its own work and stay on track (Delimarsky, 2025).
A task is too big if its diff can't be reviewed in under half an hour, and too small if it can't be tested without the next task.
Assign implementation versus review responsibilities#
Decide, for each task, who implements it and who checks it, before work starts. An agent can implement most tasks. It shouldn't be the only reviewer of its own work: Anthropic recommends a second opinion, such as a separate session asked to refute the result, so the agent doing the work isn't the one grading it (Anthropic, Best practices for Claude Code). Some reviews need a person, every time:
- database migrations, read line by line (chapter 4);
- anything that decides who may see whose data;
- text that asks a student for consent;
- changes to frozen contracts.
Chapter 11 covers delegating to coding agents in depth, and chapter 12 covers splitting work across several agents at once.
10.4 The AI execution loop#
Each task runs through the same loop. It is short enough to follow every time, and each step leaves something you can check.
flowchart LR
I["1. Inspect<br/>task card, spec,<br/>current code, git log"] --> P["2. Plan<br/>files, steps, risks,<br/>questions"]
P --> A{"Architect<br/>approves plan?"}
A -->|no: answer questions,<br/>fix the spec| I
A -->|yes| C["3. Implement<br/>only the files<br/>on the task card"]
C --> T["4. Verify<br/>tests, typecheck,<br/>end-to-end check"]
T -->|fails| C
T -->|passes| E["Evidence summary"]
E --> R{"5. Review"}
R -->|changes needed| C
R -->|approved| M["Merge, update spec<br/>and task graph"]
Inspect repository state#
The session starts by reading: the task card, the specification sections it names, the code it will change, and recent commits. Anthropic's long-running agents began each session the same way, reading the progress notes and git history and running a basic test before touching anything, so they found work the previous session had left broken instead of building on top of it (Young, 2025).
Propose a plan and identify risks#
Next, the agent proposes a plan: which files it will change, in what order, which tests it will add, what could go wrong, and what it needs to ask. Many tools have a mode that only reads and plans; Anthropic suggests separating exploration and planning from implementation, and also notes the overhead: if you could describe the change in one sentence, skip the plan (Anthropic, Best practices for Claude Code). Reading the plan is the cheapest review you will do. A wrong assumption caught here costs a sentence; caught in the diff, it costs a rewrite.
Answer questions in the specification, not only in the chat. An answer in the chat helps this session. An answer in the document helps every session after it.
Implement a constrained change#
The agent implements the approved plan and nothing else, within the folders the task card allows. If it finds a reason to go outside them, it stops and asks. Chapter 11 discusses keeping diffs small and commits meaningful.
Run tests and summarize evidence#
Give the agent a check it can run. Without one, Anthropic notes, the agent stops when the work looks done, and you become the only check; with one, it can run the check, read the result, and keep going until it passes (Anthropic, Best practices for Claude Code). The task card's “done when” is that check.
Ask for evidence, not claims: the commands that were run and their output, which acceptance examples each test covers, and anything not verified. Anthropic's long-running agents marked features complete after unit tests or quick requests to a development server, missing that the feature didn't work end to end, until they were told to test the way a user would (Young, 2025). “All tests pass” is a claim. A list of the acceptance examples, each with the test that proves it, is evidence.
Review and merge#
Review against the specification, not against your memory of it: does each acceptance example have a passing test, did anything change outside the task card, do the documents still describe the code? Then merge, update the task graph, and record any decision made during the task in the specification or an ADR. The next session starts from the documents, so they must be true when this one ends.
10.5 Context engineering#
Chapter 9 introduced context engineering for AI features: choosing what goes into each model call. Coding agents need the same discipline, applied to what every session starts with and what it picks up along the way.
Persistent project instructions#
Chapter 4 introduced the project instructions file, which many tools read at the start of every session. Since 2025, many tools read a common one: AGENTS.md, described by its maintainers as a README for agents, a predictable place for the build steps, tests, and conventions agents need. It is plain Markdown with no required fields, and it is now stewarded by the Agentic AI Foundation under the Linux Foundation (AGENTS.md). Some tools still use their own file names; check what yours reads (checked October 2026).
What belongs in it: commands to set up, run, and test the project; the repository map; the rules that apply to every change; and where the specifications live. What doesn't: anything only one feature needs, long explanations, and anything the agent can learn from the code. Anthropic's test for each line is a good one: would removing it cause the agent to make mistakes? If not, cut it. Its guidance warns that bloated instruction files cause agents to ignore the instructions that matter (Anthropic, Best practices for Claude Code).
Large projects can use nested files. The AGENTS.md convention is that agents read the nearest file in the directory tree, so a file in backend/coach/classes/ can hold rules for that module only, and the user's own prompt overrides both (AGENTS.md).
Instructions are advice. Anything that must always happen belongs in a check that runs in code: a test, a linter rule, a hook that blocks a commit. Anthropic's documentation draws the same distinction between its instruction file, which is advisory, and hooks, which run every time (Anthropic, Best practices for Claude Code). NFR-5 is now a test that fails if any prompt template or prompt-building function can receive a name or an email.
Relevant files and architecture summaries#
Give each session the files its task needs, named on the task card, and a short architecture summary instead of the whole codebase. A summary of a module's responsibilities, public functions, and limits is a few hundred tokens; reading the module is tens of thousands.
Start a new session for each task. Anthropic's advice is blunt: clear the context between unrelated tasks, and if you have corrected the agent more than twice on the same issue, start fresh with a better prompt, because a clean session usually beats a long one full of failed attempts (Anthropic, Best practices for Claude Code). The task card and the documents are what make a fresh start cheap.
Tool permission boundaries#
Context includes what the agent can do. Decide, per task, which commands it may run without asking (tests, the typecheck, the linter), which need approval (installing packages, running migrations against a shared database), and which are never allowed (anything touching production, live keys, or other students' real data). Chapter 8 gave agents test-mode keys only; chapter 11 covers sandboxes and permission settings in detail.
Treat the context itself as a place where risk enters. An instruction file, a specification, a fetched web page, or a code comment can contain text an agent will follow. Review changes to instruction files as carefully as code, and accept skills and rules only from sources you trust, as chapter 9 advised.
Memory hygiene and stale instruction removal#
Instructions go stale. The project changes, and the file that briefs every agent doesn't change with it unless someone makes it. A stale instruction is worse than a missing one, because an agent follows it confidently. The failure clinic shows how.
Make hygiene routine:
- When a feature changes a rule, update the instruction file in the same pull request.
- Once a month, read the whole file. Delete anything the code now enforces, anything no longer true, and anything only one module needs (move it to that module's file).
- When two documents disagree, fix one of them. Don't leave the agent to pick.
- Watch behavior. Anthropic suggests that if the agent keeps breaking a rule, the file is probably too long and the rule is getting lost, and if it asks questions the file answers, the wording is unclear (Anthropic, Best practices for Claude Code).
Architect's decision: where do feature specifications live after the feature ships?#
| Context | Instructor accounts is the first feature built from a full specification package. More will follow, and features will change after they ship. The team is two people and several agent sessions a week. |
| Constraints | Agents start every session with no memory, so whatever they need must be in the repository. Review time is the scarcest resource. Documents that drift from the code mislead agents. |
| Option A | Spec-first, then discard: write the spec, build the feature, delete or archive the spec. Least to maintain. The next change to the feature starts from the code alone, and the decisions behind it (why instructors can't see task titles) are lost. |
| Option B | Spec-anchored: keep each feature's spec in docs/specs/, update it in the same pull request as any behavior change, and link it from the PRD and the instruction file. More upkeep. Every future session starts from the decisions, not just the code. |
| Option C | Spec-as-source: edit only specs and regenerate code from them. Appealing in principle. Generation is not repeatable from natural-language specs, reviews would have to cover both spec and generated code, and current tools are immature for this, as Böckeler's comparison found. |
| Decision | Option B, recorded as ADR-006. |
| Tradeoffs | Each behavior change costs a document edit. Specs can still drift if reviews don't check them. Small fixes don't get specs, so the line between “fix” and “change” needs judgment. |
| Validation | For the next three features: every merged pull request that changes behavior updates its spec; a fresh session given only the spec answers five questions about the feature's rules correctly. |
| Revisit trigger | Specs are found out of date in more than one review a month, or updating them takes longer than the change itself for most pull requests. |
AI collaboration recipe#
Agents are good at drafting specifications, finding gaps in them, and breaking them into tasks. They are poor at deciding what a feature should do, because to them a reasonable guess and a decision look the same. Use them to surface decisions, then make every decision yourself.
1. Interview me before writing the spec.
I'm adding a feature to the Learning Coach. Read
docs/prd.mdandAGENTS.mdfirst. Then interview me about the feature, one question at a time: who uses it, what each role may see and do, the unhappy paths, what it must not change, and which earlier decisions apply. Don't propose a design. When I say we're done, writedocs/specs/instructors.mdusing the template, marking anything I didn't decide as an open question.
2. Critique the spec in a fresh session. Use chapter 3's prompt, with one addition:
Also list every place two parts of the work will depend on the same interface, and say whether the spec fixes its exact shape.
3. Decompose into a task graph.
From
docs/specs/instructors.md, propose a task graph. Data model and contracts first; then vertical slices in dependency order, riskiest first. For each task, write a task card: delivers, inputs, outputs, may change, must not change, done when, stop and ask if. Each task must be verifiable on its own in under half an hour of review. Don't write code.
4. Run one task.
Do task T5 from
docs/tasks/instructors.md. Read its inputs and the current code, then propose a plan with risks and questions, and wait for my approval. After implementing, run the checks in “done when” and give me evidence: each acceptance example with the test that covers it, the commands run and their output, and anything you couldn't verify.
Boundaries to state every time:
- “The documents in the repository are the source of truth. If the spec, the instructions, and the code disagree, stop and tell me.”
- “Change only the files the task card allows. A needed change to a frozen contract is a question, not an edit.”
- “Mark anything you add that the spec doesn't require as [proposed].”
- “Don't decide anything about privacy, consent, or access. List it as a question.”
Worked example: a specification package for instructor accounts#
Maya threw away the afternoon's branch and started again with documents.
1. The feature specification. After an interview session (recipe prompt 1) and a fresh-session critique that found eleven gaps, the core of the spec read:
# Feature: Instructor accounts (v0.2)
## Problem
University instructors want to see which of their students are falling
behind before an exam, so they can step in early. Students want help,
but their notes and questions are private.
## Constraints
- Instructors never see notes, tutor questions, or task titles.
- NFR-5: no names or emails to the AI provider.
- NFR-6: deleting an account removes memberships within 7 days.
- Access is granted only by ADR-007 (class membership), never by role.
## Stories and acceptance criteria
US-7: As an instructor, I want to create a class and share an invite
link, so that my students can join.
US-8: As a student, I want to choose whether to join a class and to
leave at any time, so that I control what my instructor sees.
- AC-8.1: The invite page lists exactly what the instructor will see.
- AC-8.2: Nothing is shared until the student presses Join.
- AC-8.3: Leaving removes the instructor's access immediately.
US-9: As an instructor, I want to see each joined student's progress
this week, so that I can see who is behind.
- AC-9.1: Each row shows share of tasks done, Behind status, last active date.
- AC-9.2: Only students with an active membership in this class appear.
- AC-9.3: Another class's instructor gets "not found" for this class.
- AC-9.4: The page needs no student's name to reach the AI provider.
## Out of scope
Messaging, grades, instructor access to plans or notes, users under 18.
## Open questions
Q4: Should a student see when her instructor last viewed the class page?
Q5: Which privacy rules apply to instructors at partner universities?
(legal review)
The constraints line about ADR-007 came from the critique session, which asked, reasonably, what “instructor” would mean to the access checks. Maya wrote the decision as ADR-007: a student's data is visible to another person only through an active membership in a class that person teaches, checked by one function, classes.access.can_view_progress(viewer_id, student_id). Q5 is marked for someone qualified in privacy law; rules on sharing student information differ by country and institution, and this book can't settle them.
2. The context pack. The project instruction file got three changes in the same pull request as the spec:
## Specifications
Feature specs live in docs/specs/. Read the spec named on your task card
before planning. If a spec and this file disagree, stop and ask.
## Access to student data
A student's data is visible to the student, or to an instructor through
classes.access.can_view_progress(). Never grant access by role alone.
Missing and forbidden records both return 404.
## Repository map (excerpt)
backend/coach/classes/ classes, memberships, invite codes (ADR-007)
A new backend/coach/classes/AGENTS.md holds what only that module needs: how invite codes are generated and that progress is read through plans.service.weekly_summary(), never by querying plan tables.
3. The task graph.
flowchart TD
T1["T1 Data model: classes, memberships,<br/>invite codes + migration<br/>(review: Maya, line by line)"] --> T3
T2["T2 Contracts: schemas, OpenAPI,<br/>generated types, frozen<br/>(review: Maya)"] --> T3
T3["T3 Instructor creates class<br/>and invite link (US-7)"] --> T4
T4["T4 Student joins with consent,<br/>leaves from settings (US-8)<br/>(review: Maya reads consent text)"] --> T5
T4 --> T6
T5["T5 Class progress page (US-9)<br/>(review: second session + Maya)"] --> T7
T6["T6 Deletion and leaving<br/>remove access (NFR-6)"] --> T7
T7["T7 End-to-end journey,<br/>docs, data inventory"]
T1 and T2 come first because every slice depends on them. T4 comes before the dashboard because consent is the riskiest decision: if students wouldn't join, the dashboard was pointless, and Dr. Okafor's class could test it within days.
4. A task card.
## T5: Class progress page
Delivers: US-9, AC-9.1 to AC-9.4
Inputs: docs/specs/instructors.md, ADR-007, classes/AGENTS.md,
plans/service.py (weekly_summary)
Outputs: GET /classes/{id}/progress, web page /classes/[id],
tests, spec status updated
May change: backend/coach/classes/, web/src/pages/classes/,
backend/tests/classes/
Must not change: plans/, notes/, accounts/, any frozen schema
Done when:
- pytest backend/tests/classes passes, including: instructor of
another class, student who left, student never joined,
deleted student
- typecheck and lint pass
- end-to-end: invite, join, view, leave, view again
- evidence lists each AC with the test that covers it
Stop and ask if: you need data weekly_summary() doesn't provide; any
access rule seems to conflict with another document
5. Running T5. The planning step paid for itself at once. The agent's plan proposed adding the student's display name to each row. Maya checked AC-9.1, which didn't list it, and realized the spec had never said how an instructor tells rows apart. A row of percentages is useless. She decided the instructor sees the name the student chose to show the class, entered on the join page, and added it to AC-8.1 and AC-9.1 before approving the plan. It took five minutes, in the document, before any code.
The agent's evidence summary listed AC-9.1 to AC-9.4, each with its test, the commands it ran, and one item it couldn't verify: how the page looked with 300 students. A second session, asked only to find ways an instructor could see a student she shouldn't, found none in the code and one in the tests: no test covered a student in two classes. Maya added it to the task card and the agent wrote it.
6. The completion checklist. Before the feature shipped, Maya checked:
| Item | Evidence |
|---|---|
| Every acceptance example passes | Test names listed per AC in the T7 summary |
Access only through can_view_progress |
Search shows no other query on another user's progress; test with two classes and a shared student |
| Consent text matches what instructors see | Read by Maya and two testers against AC-9.1 |
| NFR-5 | The prompt-input test passes; no class code calls the AI adapter |
| NFR-6 | Deletion test removes memberships; the instructor sees the student vanish |
| Documents current | Spec v0.3, ADR-007, data inventory, AGENTS.md updated in the same pull requests |
| Open questions | Q4 deferred with reason; Q5 with the privacy reviewer |
The second build took four days instead of one afternoon, and it held up.
Verification: is the work driven by the spec?#
| Check | How |
|---|---|
| Spec exists | Every feature beyond a small fix has a spec in docs/specs/ with constraints, examples, out-of-scope, and open questions. |
| Decisions, not guesses | A fresh session given only the spec builds a test plan that matches yours on every expected result. |
| Interfaces fixed | Every interface two tasks share is written down and frozen before the tasks start. |
| Tasks bounded | Every task card names what it delivers, the files it may change, and how it is proven done. |
| Evidence, not claims | Each merged task has an evidence summary mapping acceptance examples to tests. |
| Independent review | Access, consent, migrations, and contract changes were reviewed by a person. |
| Instructions lean | The instruction file is short and current; rules that must always hold are checks in code. |
| Documents current | Spec, ADRs, and instructions changed in the same pull request as the behavior. |
Failure clinic: the rule that said “never”#
Symptom. Three weeks after launch, a tester who taught a second class reported that she could open the progress page of Dr. Okafor's class by changing the class ID in the address bar. She saw percentages and Behind flags for students who had never joined her class.
Reproduce. Maya created two instructors and two classes on staging. The second instructor could request the first class's progress. The test suite passed: every access test used one instructor and one class.
Diagnose. The bug came from a small task after launch: “let co-instructors view a class.” The agent's session read the instruction file, which by then was 240 lines long. Near the top, from chapter 6, was a line nobody had touched: “Never return another user's data. Every query must filter by the current user's ID.” Further down, added with instructor accounts, was the newer rule pointing at can_view_progress. The co-instructor task needed a query that returned other users' data, which the old rule forbade outright. The agent resolved the conflict on its own: it bypassed can_view_progress and added a condition allowing any user with an instructor role to read class progress. That satisfied the task's tests and read like a sensible exception to the old rule.
Four causes combined:
- A stale instruction. The chapter 6 rule had been true for students only. When access through classes arrived, nobody rewrote it, so the file held two rules that disagreed.
- A long instruction file. At 240 lines, with module details mixed in with product-wide rules, the newer rule was easy to lose, and nothing marked which rule was current.
- No stop condition. The task card didn't say to stop when documents conflict, so the agent made an access decision by itself.
- A test suite that couldn't fail. With one instructor and one class, “any instructor may read” and “this class's instructor may read” behave the same.
Fix.
- Rewrite the rule once. The old line was deleted. The access rule now says one thing, in one place, with the function that enforces it.
- Prune the file. Maya cut the instruction file from 240 lines to 70: commands, repository map, product-wide rules, and pointers to specs and ADRs. Module details moved to each module's own file, which agents read when working in that folder.
- Make the rule a check. A test now scans the
classesandplansqueries and fails if any reads another user's progress outsidecan_view_progress. Every access test uses two instructors, two classes, and a student in both. - Add the stop condition to every task card template. “If two documents disagree, stop and ask.”
Lesson. An instruction file ages like code, but its contradictions don't fail loudly; whichever agent hits them resolves them, in whichever direction makes its task pass. Keep it short, keep each rule in one place, enforce what matters in code, and tell agents that a conflict is a question.
Architect's checklist#
Before an agent builds a feature:
- ☐ The problem, constraints, and out-of-scope list are written in a feature spec.
- ☐ Who may see and do what is decided, written as acceptance examples, and checked by a person.
- ☐ The spec has been critiqued by a fresh session, and the answers are in the spec, not the chat.
- ☐ Every shared interface is written down and frozen before work splits.
- ☐ The feature is cut into vertical, dependency-ordered tasks, riskiest first.
- ☐ Each task card names what it delivers, its inputs, the files it may change, how it is proven done, and when to stop and ask.
- ☐ Each task runs in a fresh session through inspect, plan, implement, verify, review.
- ☐ Evidence maps every acceptance example to a test.
- ☐ Access, consent, migrations, and contracts are reviewed by a person.
- ☐ The instruction file is short and current, with module details in module files.
- ☐ Rules that must always hold are enforced by checks in code.
- ☐ Spec, ADRs, and instructions are updated in the same pull request as the behavior.
Exercises#
Beginner. Here is a vague request for the Meal Planner: “Let users share meal plans with their household.” List at least eight decisions an agent would have to guess (who can edit, what happens to allergies, what a removed member keeps, and so on). For each, write the decision you would make and one Given/When/Then example that tests it.
Intermediate. For the Trip Planner, write a specification package for “re-plan a day when a booked activity is canceled”: problem and constraints, acceptance examples including two failure cases, the modules it may and may not touch, and its test requirements. Then cut it into a task graph of four to seven tasks with a task card for the riskiest one. Give your package to a fresh agent session and ask it only for a plan for that task; list every assumption in its plan that your documents didn't settle.
Advanced. Take the Shop Help Chat and write a project instruction file for it, then deliberately age it: add six months of plausible changes (a new returns policy, a second language, a refund tool that needs approval), each with a new rule appended and nothing removed. Find the contradictions and stale rules, prune the file, move module-only rules to module files, and turn the two most important rules into checks in code. Give the same three tasks to fresh sessions using each version, and compare what they do.
Lab, artifact, and review#
Lab. Write a specification and an agent task package for adding instructor accounts to the Learning Coach, then build at least the access slice (T4 and T5) from it, one task per fresh session.
Deliverable. Add to your portfolio:
- the feature specification, with constraints, acceptance examples, out-of-scope list, and open questions;
- the context pack: the updated project instruction file, any module instruction files, and the repository map;
- the task graph and a task card for each task;
- the evidence summary for each merged task, mapping acceptance examples to tests;
- the completion checklist with evidence for each item;
- ADR-006 on where specs live, and ADR-007 on access through class membership;
- the privacy questions, marked for review by someone qualified.
Review. Ask someone who hasn't seen the project to read only your spec and task card for T5, and to tell you what the instructor will see. If their answer differs from yours, the spec isn't finished.
Reflection#
- Which decision in your current project exists only in your head or a chat history?
- If a new agent session started on your project tomorrow, what would it get wrong first, and which document would have prevented it?
- Which rule in your instruction file would you most regret an agent ignoring, and is it enforced anywhere else?
- Where is the line, in your work, between a change small enough for a sentence and one that needs a spec?
References#
- AGENTS.md. AGENTS.md: A simple, open format for guiding coding agents. Agentic AI Foundation.
- Anthropic. Best practices for Claude Code. Claude Code documentation.
- Böckeler, B. (2025, October 15). Understanding spec-driven-development: Kiro, spec-kit, and Tessl. martinfowler.com.
- Delimarsky, D. (2025, September 2). Spec-driven development with AI: Get started with a new open source toolkit. The GitHub Blog.
- Hong, K., Troynikov, A., & Huber, J. (2025, July 14). Context rot: How increasing input tokens impacts LLM performance. Chroma.
- Wake, B. (2003). INVEST in good stories, and SMART tasks. XP123.
- Young, J. (2025, November 26). Effective harnesses for long-running agents. Anthropic Engineering.
Links checked October 2026.
Check your understanding
3 questions
1.Halfway through a long session, an agent adds students' names to an AI prompt, even though the project instructions forbid it. What is the most likely cause?
2.Which task is sized well for an agent?
3.The project instructions say “return 404 for any record the user doesn't own.” The new feature spec says instructors may see progress for students in their class. An agent hits the conflict. What should it do?
Was this chapter helpful?
Cite this chapter
Shi, T. (2026). Specification-Driven Development with AI. In Path to AI Architect: From vibe coding to designing, building, and leading AI-driven software systems (Online edition, Chapter 10). Exciton Research. Retrieved November 2, 2026, from https://excitonresearch.com/education/become-an-ai-architect/specification-driven-development
Brief quotations are welcome with attribution and a link.
© 2026 Tian Shi. All rights reserved.