Iteration One: Building the Core
Whose work is it when a machine helps you?
Chapter 10 — Iteration One: Building the Core
“Working software is the primary measure of progress.” — Principles behind the Agile Manifesto (2001)
“Whatever you do, work heartily, as for the Lord and not for men,” — Colossians 3:23 (ESV)
Why This Matters
Last week the skeleton walked. One request went in the front door, touched every layer, and came back out — thin, ugly, and alive. This week you put muscle on it.
The hat is the developer’s, and for the first time all semester it is the only hat that matters most hours of the day. You are in construction. Everything you built in Weeks 1 through 8 — the charter, the requirements specification, the non-functional targets, the architecture decision records, the technical specification, the work breakdown — exists so that this week you can sit down and not have to decide anything except how to make the code work. That is the payoff. A student with a real specification writes code. A student without one spends this week re-litigating the design and calls it “building.”
But there is a trap sitting in the middle of Week 10, and almost every capstone student steps in it. Construction is the phase where the process quietly dies. The board stops getting updated because updating it feels like overhead. The hours log goes unlogged because you are busy, and you will “catch up Sunday.” Commits turn into one enormous dump at midnight with the message stuff. The definition of done you wrote in Week 4 gets silently downgraded to “it ran once on my laptop.” None of these feel like decisions. They feel like moving fast. In Week 16 they will read, to a grader, exactly like what they are: a project that had no process from Week 10 onward.
The AI thread runs hard through this chapter, from both directions. As a tool, an assistant is genuinely good at construction — scaffolding a module, drafting a client for an API you have not used, writing the boring half of a form handler. Used well, it buys you hours. As a workload you are accountable for, it hands you code you did not write and may not understand, and understanding it is not free. There is a real debugging tax: heavy assistant use often moves your hours out of the “writing” column and into the “figuring out what this actually does” column rather than removing them. And when the grader asks in Week 16 why line 78 catches that exception, “the assistant put it there” is not an answer. The spine rule of this course holds all semester: the assistant accelerates, you decide, you verify, and you are accountable.
Which brings up the apologetic question for the week, and it is not an abstract one for your generation: whose work is it when a machine helps you? You will graduate into an industry where a meaningful fraction of the code in every repository was drafted by a model. Is that code yours? Is the project yours? Is there any honest sense in which you can say “I built this” — and if so, what exactly makes it true? Push that question away and you will end up either paralyzed with guilt or shameless, and both are worse than the answer.
Fifteen hours. Three to five real slices, each one traceable to a requirement, each one demoable. A log you can defend. A five-minute demo of working software. Let’s build.
10.1 — Vertical Slices: One Requirement, All the Way Through
A vertical slice is a unit of work that cuts through every layer of your system to deliver one observable behavior. It touches the interface, the logic, the storage, and whatever integration is involved. When it is finished, a human being can see the software do something it could not do yesterday.
The alternative — the way most students naturally work — is horizontal: build the whole data layer this week, the whole API next week, the whole UI the week after. It feels efficient. It is a trap, for three reasons. Nothing is demoable until the last layer lands, so you get no feedback for weeks. All the integration risk piles up at the end, in the exact week you have no slack. And if you run out of time you have three-quarters of a system that does nothing, which is worth precisely zero on a rubric that grades working software. Here is the difference, on the running example.
PantryPilot — a household pantry tracker: what food you have, what is about to expire, what you can cook tonight. It has a real user group (a roommate house), one third-party integration (a barcode/product lookup service), and an optional AI feature. We use it for worked examples all term. Your project will look different. The shape of the work will not.
HORIZONTAL (bad) — a week of tasks that demo nothing:
[ ] Create all six database tables and migrations
[ ] Write model classes for all six entities
[ ] Write repository/DAO layer for all six entities
[ ] Stub all fourteen API endpoints
VERTICAL (good) — the same week, sliced by behavior:
[ ] FR-04 Add a pantry item by hand (name, quantity, expiration)
→ form → validation → items table → list view shows it
[ ] FR-12 Add a pantry item by scanning a barcode
→ scan input → barcode client → product lookup → same add path
[ ] FR-18 Highlight items expiring within three days
→ query → date rule → list view badge
Each of those three, finished, is a thing you can put on a screen and show a human. Together they are the core of PantryPilot: an item goes in, and the system tells you when it is about to go bad. Everything else in the backlog — recipes, sharing, notifications — is decoration on that core. TraceLens, our contrast example, is a command-line log analyzer with no UI at all, and its slices work identically: tracelens scan <file> reads a file, parses lines, runs one detector, writes one report, exits with a meaningful status code. The observable behavior is a report on stdout and an exit code, not a screen — but it is still a vertical slice.
How to choose this week’s slices. Take your prioritized requirements — the Must-haves from your MoSCoW pass — and order them by this rule: the slice that would hurt most if it turned out to be impossible goes first. For PantryPilot that is FR-12, the barcode integration, because it depends on somebody else’s service and somebody else’s uptime. Discovering in Week 14 that the barcode service rate-limits you to a handful of requests an hour is a catastrophe. Discovering it in Week 10 is a Tuesday. Each slice retires a different risk:
| Slice | Requirement | Layers touched | Risk retired |
|---|---|---|---|
| Add item by hand | FR-04 | form · validation · DB · list | the core write path works at all |
| Add item by barcode | FR-12 | scan · third-party client · mapping · DB | the integration is real, not assumed |
| Expiring-soon highlight | FR-18 | query · date logic · view | the whole point of the product exists |
Three to five slices is the right ambition for a fifteen-hour week in which you also have to review, test, log, and demo. Not eight. If your list has eight, you are estimating like someone who has never been interrupted.
Coach’s Note — A slice is not finished when the code exists. It is finished when you can show it. If you cannot describe how you would demo a task in one sentence, it is not a slice — it is a chore, and chores belong inside slices, not on the board as work of their own.
10.2 — A Definition of Done, Applied Without Mercy
You wrote a definition of done in Week 4. This is the week it stops being a document and becomes a gate.
The purpose of a definition of done is to make “done” mean the same thing on Tuesday at 10 a.m. and on Saturday at 11 p.m. when you are tired and the deadline is Sunday. Without it, “done” drifts — always in the same direction, always toward “it worked when I tried it.” Here is what most students write, and what it costs.
The bad definition of done:
Definition of Done
- Code is written
- It works
- Committed to GitHub
Every line of that is unfalsifiable. “Code is written” — of course it is; that is what makes it a task. “It works” — under what input, on whose machine, against which acceptance criterion? “Committed” — a commit is evidence that a file changed, not that anything is finished. A grader in Week 16 cannot check a single one of those lines, which means they contribute nothing to your 50%.
The good definition of done — copy it from code/definition-of-done.md and adapt it to your stack:
A task is DONE when all of the following are true:
1. The acceptance criteria on its requirement are met, verbatim.
2. At least one automated test exercises the new behavior and passes.
3. The full test suite passes locally AND in CI on the pushed branch.
4. Errors and edge cases named in the technical specification are handled.
5. The four-pass self-review is complete and its findings are resolved or logged.
6. No secrets, credentials, or personal data are in the diff.
7. Any assistant contribution is recorded in `docs/ai-usage.md`.
8. The issue links to its requirement id and is moved on the board.
9. Docs touched: README, runbook, or ADR updated if this changed how it runs.
10. Hours are logged for the session, with a real description.
Ten checks, and every one of them is verifiable by someone who is not you — that is the test of a good definition of done. If a line cannot be checked by a stranger with your repository open, rewrite it or delete it. Now the part that matters more than the list: apply it without mercy. A definition of done only works if it is allowed to say no. The first time you finish a slice at 11 p.m. and realize check 2 is missing, you have a decision to make, and it is a decision about what kind of engineer you are becoming. Write the test. It is twenty minutes. The alternative is a project where “done” is a mood.
Coach’s Note — Put the definition of done where you cannot avoid it: a pull-request template, a pinned issue, a comment at the top of your board. Discipline that depends on remembering is not discipline; it is luck with good branding.
10.3 — Reviewing Your Own Code: The Techniques That Actually Work
In industry, someone else reads your code before it merges. You do not have that. You have you, and you already believe your code is correct — you wrote it fifteen minutes ago on exactly that belief. Reading your own work honestly is a real skill with real techniques: four passes, in this order, on every slice. They take about twenty minutes for a normal-sized diff, and they routinely find things that testing does not.
Pass 1 — The diff pass (mechanical). Do not read the files. Read the diff:
git add -A
git diff --staged # every line you are about to commit
git diff --staged --stat # and the shape of it
You are looking for the accidents: the debug print you left in, the commented-out block, the file you did not mean to stage, the hard-coded localhost, the TODO you wrote three hours ago and forgot. This pass catches roughly half of everything you will find, and it costs five minutes.
Pass 2 — The stranger pass (comprehension). Read the changed code as if you had never seen it, starting from the entry point. The question is not “is this right?” — it is “could someone who has never met me follow this?” Name the things that make you hesitate. Ambiguous variable names, a function doing three jobs, a magic number, a nesting depth of four. If you have to reconstruct your own reasoning to read it, so will your Week-14 self.
Pass 3 — The adversary pass (destruction). Now attack it. Walk the diff asking, for each input: what is the worst thing a user, a network, or a clock could hand this?
| Input | The hostile version |
|---|---|
| A text field | empty, 10,000 characters, emoji, '; DROP TABLE, leading/trailing spaces |
| A number | zero, negative, 0.1 + 0.2, the maximum your type holds |
| A date | today, a leap day, a date in 1900, a date in a different time zone |
| A network call | slow, timed out, 500, 429, valid HTTP with a garbage body |
| A collection | empty, one element, one million elements, duplicates |
You are not fixing everything you find. You are deciding — fix now, handle later with a logged defect, or accept with a written reason. All three are legitimate. Silence is not.
Pass 4 — The contract pass (traceability). Open the requirement. Read its acceptance criteria out loud. Then point, in the code, at the line that satisfies each one. If you cannot point at a line, the criterion is not met — no matter how good the feature feels.
Two amplifiers make all four passes sharper. Sleep on it: a twelve-hour gap between writing and reviewing is worth more than any tool, because you cannot see your own assumptions while you are still inside them. And open a pull request to yourself — even solo, branch → PR → review in the web interface → merge. The web diff view is unfamiliar enough to feel like someone else’s code, CI runs on the branch, and the PR becomes a permanent record of what you reviewed and why you merged it.
The four passes and the hostile-input table are also in code/definition-of-done.md, so you can copy them into your repository.
Coach’s Note — The bug you cannot find is almost always in the code you are proudest of, because pride is where you stop reading carefully. When a section of your diff makes you feel clever, slow down there.
10.4 — AI-Assisted Implementation, and the Line Between Using and Submitting
“Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?” — Brian W. Kernighan and P. J. Plauger, The Elements of Programming Style, 2nd ed. (1978)
Kernighan wrote that about human cleverness. It applies with double force to code you did not write at all. An assistant will hand you a compact, confident, idiomatic function in four seconds. Your ability to debug that function at 2 a.m. in Week 14 is exactly your ability to understand it — and understanding was the part you skipped.
This course permits and expects assistant use. The authoritative statement is in Appendix C; the practical version is one sentence: you may use any tool to help you build, and you must be able to defend every line you ship as your own decision. So where is the line? Not at how many characters the model typed. At judgment and accountability — and that is testable.
| Using (this is your work) | Submitting (this is not) | |
|---|---|---|
| The design | You chose it; the assistant filled it in | The assistant chose it; you accepted it |
| Comprehension | You can explain every line without looking | You would have to re-read it to explain it |
| Verification | You tested it against your acceptance criteria | It compiled, so you moved on |
| Modification | You changed it — naming, structure, error handling | It arrived as-is and merged as-is |
| Failure | You know what breaks it and what happens then | You would be surprised by any failure |
| Record | It is in docs/ai-usage.md | Nobody knows it happened |
The three tests. Before assistant-drafted code merges, put it through all three. They take about ten minutes and they are the whole difference.
- Explain it. Out loud, line by line, without re-reading. If you stall on a line, you do not own that line yet. Read it, look up what it does, or delete it.
- Break it. Deliberately feed it the hostile inputs from the adversary pass. Assistant code is famously optimistic: it assumes the network works, the field is populated, the list is non-empty, the date parses. Find the assumption. This is where the real bugs are.
- Rewrite it. Take the hardest function and retype it from memory, in your own naming, in your project’s style. If you cannot, you have found the piece you do not understand — and now you know exactly what to study. This one test is worth more than the other two combined.
Write a prompt contract, not a wish. The quality of what comes back tracks the specificity of what you asked, and a specific ask is also a record of the judgment you exercised.
Bad prompt — the wish:
write me the barcode scanning feature
You will get a plausible file that assumes a library you are not using, a framework version you do not have, an API shape you did not design, and error handling you never specified. Then you will spend two hours reconciling it with your actual system — the debugging tax, paid in full.
Good prompt — the contract:
Context: <language/framework and version>, existing module `pantry/items` with
an addItem(name, qty, expiresOn) function I already wrote and tested.
Task: write a client for the product-lookup HTTP API below. Do NOT change
addItem; the client returns a product name or null and the caller decides.
Contract:
- lookupProduct(barcode: string) -> {name: string} | null
- timeout 3 seconds, at most 1 retry on a 5xx, no retry on 4xx
- a 404 means "unknown product" and returns null, not an error
- never throws; on any other failure return null and log at warn
- the API key comes from an env var, never a literal; no new dependencies
Constraints: match the error-handling style in `pantry/items` (attached).
Then list every assumption you made that I did not state.
That last line is the highest-leverage sentence you can put in a prompt to a coding assistant: the assumptions it lists are the bugs it was about to hand you.
The debugging tax, honestly. Assistant use does not automatically make you faster, and you should not plan as if it does. A 2025 randomized trial by METR found that experienced open-source developers working in codebases they knew well took roughly 19% longer on tasks when allowed to use early-2025 AI tools — while believing they had gone faster. It was a small study (sixteen developers, mature repositories) and it does not settle the question for every setting, least of all a greenfield student project where scaffolding is a genuine win. But it should make you suspicious of your own sense of speed. Your hours log knows the truth and your feelings do not.
Where assistant help reliably pays for a capstone: boilerplate you have written before, a client for an API whose docs you have read, test scaffolding, unfamiliar syntax, and explaining an error message. Where it reliably costs: anything touching your architecture, anything where the requirement is subtle, and anything you would not be able to fix yourself.
Coach’s Note — The rule I would tattoo on a capstone student’s wrist: never merge code you could not have written, only code you did not have to. The gap between those two sentences is the entire ethics of this chapter.
10.5 — The ai-usage Log: What to Record, and Why It Protects You
Your final package includes docs/ai-usage.md. It is required, it is graded in Week 16, and it is the most misunderstood artifact in this course. Students treat it as a confession. It is not. It is your defense. Think about what happens without it. In Week 16 a grader reads a file that does not sound like the rest of your repository. They have two hypotheses: you learned something and grew, or you pasted something you do not understand. With no log, the burden is on you to prove the first one, live, under pressure. With a log — dated, specific, showing what you asked, what you took, what you changed, and how you checked it — you have already answered the question, in writing, before it was asked. Documented use is use. Undocumented use looks like concealment, and that is an integrity matter.
Log at the level of a session or a contribution, not a keystroke. If an assistant drafted something that survived into your repository, or materially shaped a decision, it gets an entry with five fields: the date; the tool and, if you know it, the model or version; what you asked for, in one line, naming the actual task and not “help with code”; what you accepted, meaning the file or function and roughly how much of it survived; and what you changed and how you verified it — the edits you made and the test or check that proved it works.
Bad entry — useless to you and to the grader:
3/19 - used AI for the barcode stuff
Which assistant? Which file? What did it write? Did any of it survive? Did anyone test it? A grader learns nothing except that you know the word “AI.” A hostile reading is available, and you handed it to them.
Good entry — same session, honestly recorded:
### 2026-03-19 — barcode lookup client
Tool: <assistant name>, <model/version if known>
Asked for: an HTTP client `lookupProduct(barcode)` for the product API, with a
3s timeout, one retry on 5xx only, 404 => null, never throws. Full contract
in prompts/2026-03-19-lookup.txt.
Accepted: `pantry/barcode/client.*` — roughly the retry loop and the response
mapping, about 40 of 95 lines survived.
Changed: rewrote error handling to match `pantry/items` (it swallowed timeouts
silently); replaced the hard-coded key with PANTRY_API_KEY; renamed three
variables; deleted a caching layer I did not ask for and do not need yet.
Verified: 4 unit tests with a stubbed HTTP layer (200 / 404 / 500-then-200 /
timeout), all green in CI on branch feat/fr-12-barcode. Confirmed against
FR-12 acceptance criteria 1 and 3. DEF-014 filed for the retry-count edge case.
Read those two again. The second is not a longer confession — it is a portrait of an engineer at work. It shows judgment (deleted a caching layer I did not ask for), verification (four named cases), traceability (FR-12, DEF-014), and honesty about proportion (40 of 95 lines). That entry earns points. The first one loses them. Start from code/ai-usage-log-template.md, commit it as docs/ai-usage.md, and write the entry in the same session as the work. Reconstructing an ai-usage log in Week 15 is impossible; you will not remember which of forty files the assistant touched, and the guessing will show.
One more thing this log does for you, quietly. Reading back six weeks of entries tells you something no rubric can: which parts of your own system you actually understand. Where the entries are thin and honest, you built it. Where they say “accepted mostly as-is” and the “changed” column is empty, you have found the module that will humiliate you in the Week-16 question period. Go read it now, while there is time.
10.6 — Commit Hygiene Under Deadline Pressure
Your commit history is a graded artifact. It is also, in Week 14 when something breaks, the only tool that can tell you when the system last worked. Both facts are invisible in Week 10 and decisive later. Deadline pressure produces one particular failure: the midnight dump — forty-one files, one commit, message iteration 1. It costs you nothing tonight and everything later, because git bisect is useless, git revert is all-or-nothing, and a grader cannot see a single decision you made across four days of work.
The discipline is small. One commit per coherent change, staged deliberately:
git add -p # stage hunk by hunk; you will see what you wrote
git status # what is staged, what is not, what is untracked
git diff --staged # pass 1 of the self-review, for free
git commit # write a real message in an editor, not with -m
git add -p is the highest-value five minutes in this chapter. It forces you to look at every hunk before it becomes history, and it will catch the debug print and the stray key more reliably than any checklist.
Messages that explain themselves. The subject line says what; the body says why. Why is the part that is unrecoverable later — the code always shows what.
| Bad | Why it fails | Good |
|---|---|---|
fix | Fixes what? | fix(items): reject expiration dates in the past (FR-04 AC-3) |
updates | Nothing is recoverable | feat(barcode): add product lookup client for FR-12 |
wip × 9 | Nine commits, zero information | squash before merge; one message per behavior |
changed the thing josh mentioned | Josh is not in the repository | fix(list): sort expiring items ascending; roommate feedback 3/18 |
iteration 1 on 41 files | No bisect, no revert, no story | one commit per slice, each linked to its issue |
A full message, for the record:
feat(barcode): add product lookup client for FR-12
Adds lookupProduct(barcode): 3s timeout, one retry on 5xx only. A 404 maps
to null ("unknown product") rather than an error, because FR-12 AC-2 requires
an unknown barcode to fall through to manual entry instead of failing the add.
Rejected an in-memory cache for now: NFR-03 does not require it and it would
need an invalidation story we have not designed. Revisit if the API rate limit
bites in iteration two.
Closes #34. Refs FR-12.
Two paragraphs of why, one deferred decision recorded, one issue closed, one requirement referenced — ninety seconds of typing. Many teams format subjects with the type(scope): summary convention documented at https://www.conventionalcommits.org/; adopt it or do not, but pick one shape and hold it for six weeks.
The commit you cannot take back. Under pressure this is when secrets get committed — the barcode API key, a database URL with a password, a .env you meant to ignore. Two facts you must internalize: deleting it in a later commit does not remove it from history, and a key pushed to a public repository should be treated as compromised the moment it lands, because automated scrapers find them fast. So the fix is not a follow-up commit — it is rotate the credential immediately, then clean the history. GitHub also runs secret scanning and can block pushes containing recognizable credential formats, but that is a backstop, not a strategy, and coverage varies by credential type. Check the diff yourself.
Coach’s Note — At the end of every working session, run
git log --oneline -10and read it as a stranger. If those ten lines do not tell the story of what you built this week, the history is already failing at its job — and it only gets harder to fix.
10.7 — Keeping the Hours Log Honest When You Are Busy
Here is the week the hours log dies. Not Week 3, when logging felt novel. Week 10, when you are actually working and stopping to type a line into a spreadsheet feels like theft from the work. So let us be blunt about what the log is for, because “the rubric says so” will not survive a hard week.
- It is your only calibration instrument. In Week 7 you estimated these tasks. This week you find out what they really cost. That comparison — estimate versus actual — is the most valuable professional habit this course can hand you, and it is unavailable without the log. Engineers who can estimate get trusted with schedules. Engineers who cannot spend their careers apologizing.
- It is the early-warning system for scope. Six weeks remain. If the log says you have spent 148 hours and the burn-down says half the features are left, you have a scope conversation to have this week, while cutting is still cheap.
- It is evidence. In Week 16 the log is part of what earns your 50%. A log that reads as if it was kept is worth points; a log that reads as if it was invented is worth less than nothing, because it puts everything else you claim under suspicion.
Log at the end of each session, in under thirty seconds. Not at the end of the week. The format has not changed since Week 1 and it still lives at docs/hours-log.csv — the columns from Appendix B, section B.11, plus the ai_assisted column you added in Week 7:
date,start,end,hours,phase,hat,task,estimate_hours,blocked_hours,notes,ai_assisted
2026-03-19,18:30,22:15,3.75,construction,developer,FR-12 barcode slice,2.50,0.00,assistant draft rewritten twice,yes
2026-03-19,22:15,23:15,1.00,construction,developer,FR-12 barcode client timeout,0.50,0.00,debugging the timeout the assistant hid,yes
Note the second row. That is the debugging tax, visible, in your own data. Do not fold it into the first row — separating “writing” from “understanding what I was handed” is exactly the measurement that makes the log worth keeping.
Whatever else you shorten this week, do not shorten the schema. estimate_hours above all. It is the only value in the file that cannot be recovered afterward, it is what makes the log a calibration instrument instead of a diary, and the Week-16 estimate-versus-actual analysis is computed straight out of it. A blank estimate on a row you genuinely forgot to estimate is honest and costs you one number. A log with no estimate column at all is a Week-16 deliverable you have already thrown away, six weeks before you find out.
A realistic sample log for the running example, covering Weeks 1 through 10, is in code/hours-log.csv. Run code/hours_report.py over it — python3 tools/hours_report.py docs/hours-log.csv — and it prints the weekly rollup, the phase distribution, the cumulative burn against 240 hours with your pace, and the pattern checks a grader runs. It needs only date, hours, and phase, and reads the work description from whichever of task, notes, or description your file has, so it runs on the Week-1 template unchanged. Point it at your own log once a week. It takes two seconds and it will tell you things about your semester you cannot feel.
What a dishonest log looks like — and why it is obvious. Backfilled logs have tells, and every one of them is a statistical fingerprint of reconstruction rather than recording:
2026-03-16,,,3,construction,developer,worked on project,,,,
2026-03-17,,,3,construction,developer,worked on project,,,,
2026-03-18,,,3,construction,developer,worked on project,,,,
2026-03-19,,,3,construction,developer,worked on project,,,,
2026-03-20,,,3,construction,developer,worked on project,,,,
Five identical durations. Every value a whole number. One task description repeated verbatim. Start, end, and estimate_hours blank on every row, which is what happens when rows are typed all at once from memory. No debugging, no reading, no dead ends, no interruptions — which is to say, no life. Real work is 1.25 hours here and 3.75 there, with a session that produced nothing but a fixed environment variable. Compare that block against the commit timestamps for the same days and the story falls apart in thirty seconds; graders check. Then there is the other classic, the fourteen-hour Sunday — one entry, 2026-03-22, 14.0, "caught up". Nobody does focused engineering for fourteen consecutive hours. What that row really records is a student reconstructing a week from memory, and it converts a required artifact into evidence against you.
Reconstructing honestly, when you have genuinely fallen behind. This is allowed, and it is far better than inventing. Rebuild from evidence — git log --since=... --date=short --pretty='%ad %s', your browser history, your editor’s recent files, your board — estimate in quarter hours, and mark the row as reconstructed:
2026-03-18,,,2.50,construction,developer,FR-04 validation and list view,,,[reconstructed from commits],no
A logged estimate labeled as an estimate is honest. An unlabeled guess is not. That bracket costs you nothing and buys you your credibility. And leave estimate_hours blank on a reconstructed row rather than back-filling it: a number invented after the session is not an estimate, and one empty cell costs you far less than a calibration factor built on fiction.
Coach’s Note — Thirty seconds at the end of a session. That is the whole practice. If you cannot spare thirty seconds, you were not going to spare the four hours it takes to fake it convincingly in Week 15 either.
10.8 — The Demo: Showing Working Software, Not Slides
Milestone 10 ends with a five-minute demo. It is small on purpose — it is the rehearsal for the thirty minutes in Week 16 that carry 10% of your grade, and rehearsal is cheaper now. The rule is absolute: a demo shows software running. Not a diagram of the architecture. Not a slide that says “implemented barcode scanning.” The software, on a screen, doing the thing. Five minutes, three acts:
| Act | Time | What happens |
|---|---|---|
| 1. The claim | 45 sec | One sentence: which requirements you closed and what a user can now do |
| 2. The software | 3 min | The system doing it, live, with seeded data, following a written script |
| 3. The evidence and the gap | 75 sec | Tests passing, the acceptance criteria checked off, and what is not done |
Act 2 is where students improvise and die. Do not. Write the script — the literal clicks or commands, in order, with the exact input values — and rehearse it once end to end. Then: seed your data (never demo on an empty database and never type a dataset live — commit a seed script; typing “asdf” into a form in front of a grader makes real software look like a toy); record a fallback before the live run, because Wi-Fi fails and third-party services go down, and “here is the recording I made this morning” reads as prepared where “it worked earlier” reads as every student who ever said it; cut the setup, so nothing installs on camera; and show one failure path — an unknown barcode, a past date — because handled errors impress more than happy paths, everyone’s happy path works.
The opening line. Compare:
Bad: “So, um, this is my project, I’ve been working on the pantry thing, let me just find the — okay, so there’s a lot still to do but basically you can add items, hold on, let me restart the server…”
Good: “PantryPilot now closes FR-04, FR-12, and FR-18: a household member can add an item by hand or by scanning a barcode, and the list flags anything expiring within three days. Here it is. I’m starting from the seeded pantry.”
Same project, same code. One of those students sounds like an engineer. And Act 3 is the one that earns points, and the one students skip. Say plainly what is not done and what it will take. “Recipe suggestion is not started. It is two slices, I have estimated eight hours, and it is scheduled for Week 12. If the barcode rate limit becomes a problem, recipe suggestion is the first thing I cut, and the requirements specification already marks it Should-have.” That paragraph demonstrates project management, honesty, and a plan — and it is impossible to fake. Compare it with “yeah, there’s some stuff left.” One of those is a status report; the other is a shrug.
10.9 — Where Your Hours Went This Week
The budget is roughly fifteen hours. A realistic Week 10, for a student who is on pace:
| Activity | Hours |
|---|---|
| Chapter, reps, weekly quiz | 1.5 |
| Planning the increment: choosing slices, writing task cards, definition of done | 1.0 |
| Implementation — the actual writing | 6.0 |
| Debugging, including reconciling assistant-drafted code | 2.0 |
| Self-review and the rework it produces | 1.5 |
| Tests written alongside the slices | 1.5 |
| Logs, commits, board, ai-usage entries | 0.5 |
| Demo: script, seed data, rehearsal, recording | 1.0 |
| Total | 15.0 |
Two things to notice. Implementation is under half the week — it always is, and students who plan for fifteen hours of typing finish Sunday with untested code and no demo. And debugging gets two hours by default, not “whatever is left over.” If your own log shows debugging routinely eating four, that is not a personal failing, it is data: feed it back into your Week 7 estimates for iteration two, and notice whether the four hours cluster around the code you wrote or the code you accepted.
10.10 — Interactive Lab: The Honest Hours Log
Below this chapter on the website is The Honest Hours Log. Do this lab before you touch your own log this week. Add entries the way you would after a real session: date, duration, work package, SDLC phase, and one line about what you actually did — a deliberately trimmed subset of your real columns, because the lab is about the shape of the data, not the schema of your file. The widget builds the weekly rollup, the phase distribution, and the cumulative burn against the 240-hour budget as you type, so you can see immediately whether you are on pace or quietly drifting.
Then open the “what your grader sees” panel. It runs the same pattern checks a grader runs: identical durations repeated, round numbers everywhere, a single implausible fourteen-hour Sunday, long silences in weeks your commit history says you were working. Deliberately feed it a backfilled week and watch every flag light up. Then fix the entries into something that resembles a real week — a 1.25, a 3.75, a session that produced nothing but a fixed environment variable — and watch the flags clear. What it teaches is not “how to avoid getting caught.” It is what an honest record looks like from the outside — and, more usefully, what your own distribution of hours has been telling you all semester while you were too busy to read it.
10.11 — Whose Work Is It When a Machine Helps You?
“Whatever you do, work heartily, as for the Lord and not for men.” (Colossians 3:23, ESV)
This is the honest version of a question your generation cannot avoid, and I want to give you a better answer than the two cheap ones on offer. The first cheap answer is “none of it is mine.” It sounds humble. It is actually a way of putting down responsibility: if the machine wrote it, the machine is answerable for it, and I am off the hook when it fails. That is not humility; it is abdication wearing humility’s coat. The second cheap answer is “all of it is mine, and I don’t have to say anything.” That is not confidence; it is concealment, and it is the thing academic-integrity policies exist to name.
Christian thinking has a durable category that cuts between them, and it is older than software: stewardship. “Moreover, it is required of stewards that they be found trustworthy” (1 Corinthians 4:2, ESV). A steward does not own the materials. A steward is answerable for what is done with them. The tools, the languages, the libraries, the machine on your desk, the intelligence you are using to read this sentence — none of it originated with you. Every engineer who has ever worked has worked with borrowed materials, and no engineer has ever been less accountable for the building because the timber grew somewhere else.
So “is this code mine?” is the wrong question, because it is a question about origin, and craft has never been settled by origin. The right question is the steward’s question: am I answerable for it? And that one has a hard, checkable answer.
You are answerable for code when you chose the design it implements. When you can explain it without re-reading it. When you tested it against a requirement you wrote. When you know what breaks it. When you changed it because your judgment differed from what you were handed. When your name is on the commit and you would defend it in a room. Every one of those is a judgment a model cannot make for you, because judgment requires someone who can be held to it — and a tool cannot be held to anything. That is not a limitation of current models; it is what accountability means.
Notice, too, that Scripture is comfortable with skill in a way our culture often is not. Exodus 31 tells of Bezalel, the craftsman for the tabernacle, described as filled by God with ability and intelligence and knowledge and craftsmanship — a passage that treats technical skill as a gift and as a genuine human accomplishment at once, with no embarrassment about either. Gift and work are not competitors. The craftsman is fully the craftsman even though nothing he used began with him.
And notice what Colossians 3:23 actually changes about this week. “Work heartily, as for the Lord and not for men” moves the audience. If you are working for men, the only thing that matters is what can be seen — the demo runs, the feature looks done, nobody knows which lines you accepted at 1 a.m. without reading. If you are working for the Lord, the unseen parts are the same work as the seen parts: the test you wrote when nobody would have checked, the entry in the log for a session you could have skipped, the function you rewrote because you could not explain it. Verse 24 follows on with the reason — the reward comes from the Lord, and it is the Lord Christ you serve. That is a strange and freeing thing to believe on a Thursday night in Week 10, because it means the honest log matters even in the universe where no grader ever opens it.
“One who is faithful in a very little is also faithful in much, and one who is dishonest in a very little is also dishonest in much” (Luke 16:10, ESV). This week the “very little” is a spreadsheet row and a five-line entry in docs/ai-usage.md. Nobody is watching. That is exactly what makes it a test worth passing.
Here is the practical landing: use the tool, log the use, own the result. Three clauses, and the middle one is what makes the other two honest. A student who does all three can say “I built this” with a completely straight back — not because no machine helped, but because at every point where judgment was required, a person exercised it, and that person’s name is on the repository.
10.12 — Common Pitfalls
Pitfall: Slicing horizontally — a week spent on “the data layer.” Example: Six tables, six model classes, six repositories, fourteen endpoint stubs. Nothing a human can look at. In Week 15 the UI is still missing and none of it is worth points. Fix: Every task on this week’s board must end in observable behavior. If you cannot say in one sentence how you would demo it, it is not a slice — fold it into one.
Pitfall: Letting “done” drift to “it ran on my machine.”
Example: FR-04 is moved to Done on Thursday. No test, no CI run, the past-date edge case unhandled. In Week 13 it breaks and you no longer remember the code.
Fix: The ten-line definition of done in code/definition-of-done.md, applied as a gate. If a check fails, the task is not done — it is nearly done, which is a different column.
Pitfall: Merging assistant-drafted code you cannot explain. Example: A retry loop with an exponential backoff you did not ask for and a swallowed timeout you did not notice. It works in the demo and fails silently in Week 14, and you have no idea where to start. Fix: Explain it, break it, rewrite it — all three, before merge. Ask the assistant to list every assumption it made that you did not state, then check each one.
Pitfall: The midnight commit dump.
Example: 41 files, one commit, message iteration 1. git bisect is useless, the revert is all-or-nothing, and the history shows a grader four days of invisible work.
Fix: git add -p, one commit per coherent change, a subject that says what and a body that says why, with the issue and requirement id referenced.
Pitfall: Backfilling the hours log on Sunday night.
Example: Five rows of exactly 3.0 hours, all described “worked on project,” on days your commit history is empty.
Fix: Thirty seconds at the end of each session. If you genuinely fall behind, reconstruct from commits and browser history, estimate in quarter hours, and label the row [reconstructed from commits].
Pitfall: Committing a secret and “fixing” it with a later commit.
Example: The barcode API key lands in config.js on Tuesday and is deleted on Wednesday. It is still in the history, still public, and by then possibly already scraped.
Fix: Rotate the credential first — treat it as compromised the moment it is pushed — then clean the history. Read every diff before staging; keep keys in environment variables from the first line of code.
Pitfall: Demoing slides, or demoing without seeded data.
Example: A slide reading ”✅ Barcode scanning implemented,” or a live demo that begins with an empty database and a student typing test test test into a form.
Fix: Working software only, from a committed seed fixture, following a written script, with a screen recording made in advance as the fallback. Close by naming what is not done and when it is scheduled.
10.13 — Reps
The reps are in the exercises. They are not warmups beside the milestone — they are the increment, built in order. Preview:
- Rep 1 — cut this week’s slices from your Must-have requirements and write a slice card for each.
- Rep 3 — adapt the ten-line definition of done, then apply it to a task you already called “done” and find the gap.
- Rep 4 — run all four self-review passes on your ugliest file and log what you find.
- Reps 6–7 — write a prompt contract instead of a wish, then put the result through explain / break / rewrite.
- Rep 9 — rewrite five bad commit messages from your own history into messages that explain why.
- Rep 10 — reconstruct one honest day from
git log, then runcode/hours_report.pyover your real log.
Do the on-page Check Your Reps quiz when you finish the chapter — it is the ungraded rehearsal for Week 10 Quiz in Canvas, and the early-warning system that tells you whether this week actually landed.
10.14 — This Week’s Milestone
Milestone 10 — Milestone 10: Core Increment & Demo. Three to five vertical slices closed against their acceptance criteria, a definition of done that was actually applied, a self-review record, an honest docs/ai-usage.md, a commit history that tells the story, a current hours log, and a five-minute demo of working software with a recorded fallback. Remember the shape of this course: the milestones are graded twice, and that is not mercy. They carry 25% together, and the Week-16 submission — worth 50% — awards points for exactly these artifacts again. What you skip this week is not forgiven; it is charged once now and deferred again to a week that has six other things in it and no room. Build it now, once, while it is cheap.
10.15 — Coach’s Final Word
This is the week the course stops being about documents and starts being about whether you can build the thing you described. That transition breaks a lot of students, and almost never because they cannot code. It breaks them because construction feels like permission to abandon everything that got them here — the slices, the gate, the log, the history, the review. Do not take that permission. The process is not a tax on the building; it is what makes the building survive contact with Week 14, when you are tired and something is broken and the only thing that can save you is a history you can read and a log you can trust.
Three to five slices. Each one demoable. Each one you can explain, line by line, including the lines a machine drafted — especially those. A log that reads as if a person kept it, because a person did. And a five-minute demo where the software runs and you say plainly what is not finished yet.
Work heartily. The unseen parts count.
See you on Monday.
Up next: the exercises builds the increment rep by rep · Milestone 10 is Milestone 10 · then Chapter 11 — where verification stops being something you do at the end and becomes a phase with a plan. Reference appendices: Appendix B (templates and worked examples), Appendix C (the grading contract and the AI-use policy), Appendix E (glossary). Previous: Chapter 9.
Week 10 Knowledge Check
HORIZONTAL (bad) — a week of tasks that demo nothing:
[ ] Create all six database tables and migrations
[ ] Write model classes for all six entities
[ ] Write repository/DAO layer for all six entities
[ ] Stub all fourteen API endpoints
VERTICAL (good) — the same week, sliced by behavior:
[ ] FR-04 Add a pantry item by hand (name, quantity, expiration)
form -> validation -> items table -> list view shows it
[ ] FR-12 Add a pantry item by scanning a barcode
scan input -> barcode client -> product lookup -> same add path
[ ] FR-18 Highlight items expiring within three days
query -> date rule -> list view badge Definition of Done
- Code is written
- It works
- Committed to GitHub docs/ai-usage.md? The Coach's Note is the version to memorize: never merge code you could not have written, only code you did not have to. docs/hours-log.csv and finds this block. What is the tell, and what is the honest repair?date,hours,work_package,phase,description
2026-03-16,3,WP-8,Construction,worked on project
2026-03-17,3,WP-8,Construction,worked on project
2026-03-18,3,WP-8,Construction,worked on project
2026-03-19,3,WP-8,Construction,worked on project
2026-03-20,3,WP-8,Construction,worked on project docs/ai-usage.md entries, and an hours log you plan to backfill on Sunday — or three slices with all of that evidence in place. What does Milestone 10's rubric reward?