Without notes, state yesterday’s main idea and one unresolved question.
Build vertical slice 1 with Codex
AI-Assisted Capstone: Build Without Vibe Coding
Objective
Implement one thin end-to-end path rather than separate giant layers.
AI is an advanced instrument or junior collaborator: it expands throughput, but the engineer still defines requirements, verifies measurements, and signs off on safety.
- vertical slicing
- plan and diff review
- manual explain-back
Why this matters
Today the project becomes real: one workflow, working end to end, from a row in the database to something a person can see. Not the whole database layer, not all the endpoints — one path through every layer, committed and demonstrable. A project built in vertical slices is usable at every point in its life; one built in horizontal layers is usable only at the end, if it arrives.
By the end of the hour you have one small workflow committed, and you can explain every line of it.
Vertical slicing
A vertical slice is a small feature that crosses every layer it needs — database, API, UI — end to end. Its opposite is horizontal work: build all the tables, then all the endpoints, then all the screens.
Horizontal looks efficient and is a trap. Three sessions in you have a schema, some routes, and no way to know whether any of it works together; the first real feedback arrives once everything is already built on the misunderstanding. You also cannot demonstrate anything, so you cannot tell whether you are ahead or behind.
A slice is thin, not short. SLICE 1 of the calibration tracker:
migration: calibrations table -> POST /api/instruments/:id/calibrations
-> GET /api/instruments/:id/calibrations
-> CalibrationForm + history list
Four files, maybe five. It saves one record and shows it back. It does not edit, delete, paginate, or validate beyond the criteria you wrote for it.
Bring up one channel first
You do not populate an entire board and apply power hoping for the best. You bring up the supply, then one signal path — sensor, amplifier, converter, display — and confirm a real reading on one channel. Every remaining channel is then a repetition of a path you have already proven. A vertical slice is that first channel: the smallest complete path from input to visible output.
The slice plan
Before writing code, write the plan. One row per slice, and this template works for any project:
| # | Slice | Table | Endpoint | Screen | Done when |
|---|---|---|---|---|---|
| 1 | Record a calibration | calibrations |
POST/GET /instruments/:id/calibrations |
form + history | Story 1, criteria 1–4 pass on seeded data |
| 2 | Show overdue instruments | none (derived) | GET /instruments?status=overdue |
badge on list | Story 2, criteria 1–3 pass |
| 3 | Edit a calibration | none | PATCH /calibrations/:id |
edit form | Story 3 criteria pass |
The rule that makes this a slice plan rather than a task list: after every row, the app still runs. If finishing a row leaves the app broken until the next row lands, the rows are horizontal layers wearing a costume. Reorder until each ends in something you could demonstrate.
Order by risk, not comfort: the slice you are least sure about goes early, while there is still time to change the design around it.
Plan and diff review
You are using an agent today in pair mode: it proposes, you verify. Two moments carry all the safety.
The plan, before any file changes. Ask for a plan and read it against your spec, checking four things: does it touch only the files you expected, does it satisfy the criteria you named, does it invent requirements, does it add dependencies. Correcting a wrong plan costs a sentence; correcting wrong code costs the hour.
The diff, before it is committed. A diff is the line-by-line difference between the last committed state and now. Start with size, then read every line:
git status
git diff --stat
db/migrations/003_calibrations.sql | 12 ++++++++
src/routes/calibrations.ts | 41 +++++++++++++++++++
src/web/CalibrationForm.tsx | 58 ++++++++++++++++++++++++
3 files changed, 111 insertions(+)
Compare that against the Touches line in your issue. Three files, roughly as predicted — good. If
it said eleven files and 900 lines, reject it before reading further: a diff too big to read is a
diff you cannot own, and the fix is a smaller task, not more reading.
Then read it properly:
git diff
Read every changed line and ask three questions of each: what does this line do, why is it here, and what breaks if it is wrong? You need not have written the line, but you must be able to answer those three questions, and the rule from Day 34 is absolute: never accept code you cannot explain. Not "it passes the tests" — tests only check what someone thought to check.
Signing the inspection sheet
An inspector who signs without looking has not saved time; they have transferred the fault to their own name. The moment you commit generated code it is your code — defended by you in every review, debugged by you at midnight. Sign what you have read.
Checkpoints: commit known-good states
A checkpoint is a commit where the app worked and the checks were green — your undo button. The discipline is mechanical:
git switch -c slice-1-record-calibration # start from a known-good main
# ... one scoped change ...
npm run check # must be green
git add -A
git commit -m "feat: record a calibration against an instrument"
Commit at every point where the app works, not at the end of the day. If the next attempt goes badly, you have somewhere to return to:
git restore . # discard uncommitted changes, back to the last checkpoint
`git restore .` throws away uncommitted work permanently
Every change since the last commit is gone, with no recovery. That is why you commit known-good
states first: with a checkpoint behind you this costs one experiment, without one it costs your
afternoon. Run git status and read the list before you run it.
Manual explain-back
Before committing, close the tool and narrate the slice out loud, following the data:
- What the user types, and where the browser sends it.
- Where the server receives it, and what it validates.
- What SQL runs, and what changes in the database.
- What comes back, and what the screen shows.
- What happens on each failure case in your spec.
Any step where you say "and then somehow" is the step to go read. Finding that gap now, in a fifty-line slice, is the entire reason this checkpoint exists; finding it in a three-thousand-line app on Day 89 is a different experience.
When you get stuck
You will get stuck today, and recognising it early is a skill. The signal is concrete: twenty minutes with no new information. Not no progress — no information. Re-reading the same file or asking the agent to try again feels like work while telling you nothing new.
When that happens, use one of three moves:
- Reduce scope. Cut the slice in half. Drop the form and prove
POSTworks with a manual request; drop validation and save one hard-coded record. A smaller thing that works beats a bigger thing that might. - Reproduce smaller. Take the failure out of the app: one SQL statement in the database client,
one
curlto the endpoint, one function in a scratch script. Most bugs become obvious when nothing else is running. - Check the boundary. From Day 69: at each boundary, inspect what actually crossed it. What did the browser send, what did the server receive, what did the database get? The bug lives at the first boundary where reality stops matching what you expected.
Checkpoint
Say which of the three moves fits each case: the form submits but nothing appears in the list; the migration fails; the slice is becoming six files instead of three.
Walkthrough: the slice in one pass
git switch -c slice-1-record-calibration
Then the plan request, then the implementation request — separately, never in one message:
Pair mode — plan first, then implement
"Implement only this vertical slice after presenting the plan. Keep the diff small. Run checks and explain each changed file."
Paste the issue and its acceptance criteria underneath. Read the plan against your spec and reply
with corrections before allowing any edit. Then verify in this order every time: inspect the
diff, run npm run check, explain the behaviour in your own words. Any one failing means the
change is not accepted.
Now verify by hand, because green checks are not proof that the feature works:
npm run db:seed
npm run dev
Walk your acceptance criteria one at a time in the browser: submit a valid calibration and confirm it appears at the top of the history, then submit with the date empty and confirm the exact message from criterion 2. Then commit:
npm run check
git add -A
git commit -m "feat: record a calibration against an instrument"
git log --oneline -1
a3f1c9d feat: record a calibration against an instrument
One slice, one commit, all criteria checked by hand.
Your turn
- Write your slice plan table in
docs/backlog.md. Confirm the app still runs after every row. git switch -ca branch named for SLICE 1.- Ask for the plan only. Check it against your spec: expected files, no invented requirements, no new dependencies. Correct it in writing before any edit happens.
- Let it implement, then run
git diff --statand compare with the issue'sTouchesline. If it is much larger, discard and ask for a smaller task. - Read the whole diff. For each changed section, write one line in
docs/slice-1-notes.mdsaying what it does and why. - Run
npm run check, then verify each acceptance criterion by hand, failure cases included. - Do the explain-back out loud through all five steps. Read anything you cannot narrate.
- Commit the slice as one commit with a message describing the behaviour.
You are done when
One commit contains a workflow that works end to end, npm run check is green, and you can
explain every changed line without opening the AI tool.
Common pitfalls
- Letting the slice grow while inside it. "While I'm here" is how a three-file diff becomes eleven. Put the extra idea in the backlog and leave it.
- Accepting a diff because the tests passed. Tests check what someone thought to check; reading catches the rest.
- One giant commit at the end of the day. With no checkpoints, your only undo is "delete everything". Commit every time it works.
- Asking for a retry instead of new information. If the second attempt fails the same way, you need a smaller reproduction.
Verify it yourself
Open today's reference, OpenAI's Codex CLI documentation.
- Find how the CLI shows what it changed and how you approve or reject changes. Compare with your
git diffreview — which shows you more, and what does each miss? - Find whether it can be asked to plan without editing. Note the exact way to do that; a plan step you cannot enforce is one you will skip when tired.
Write both answers in docs/slice-1-notes.md. Making the tool stop before it edits is what keeps
you the author of this project.
The hour
- 0–5 min Recall
- 5–20 min Learn
Read only the listed concept notes and official reference sections needed today.
- 20–48 min Build
Have Codex plan and implement one flow from database to API to UI. Review every changed file and rerun checks.
- 48–55 min Explain and verify
Run the result, inspect evidence, and explain the data/control flow in your own words.
- 55–60 min Quiz and commit
Complete the quiz, record one lesson, and commit the verified change when applicable.
What to hand in
One complete, small workflow committed separately.
Working with AI today
Define one small task, review the plan, inspect the diff, run checks, and explain every changed section.
Implement only this vertical slice after presenting the plan. Keep the diff small. Run checks and explain each changed file.
References
End-of-day quiz
Explain-back gate
Pass the quiz above to unlock completion.
Quiz + explain-back checks required.