The change loop
The change loop is the four steps every Claude Code session is made of: you ask for something, Claude proposes a change, you read it, and you accept it or say what is wrong with it.
The step people drop is the third one, and it is the only one that is your job. Accepting a diff you did not read is gambling with extra steps. You find out days later, in a code review where you cannot answer the questions.
So this lesson is one small bug, fixed slowly, with the reading done properly.
Start from the failure, not from a description
There is a failing test in stockroom that is worth your attention:
npm test 2>&1 | grep "names the file"
FAIL test/store.test.ts > JsonStore > names the file when the database is malformed
Open a session in the repo, put it in Manual mode with Shift+Tab, and ask for exactly
this:
test/store.test.ts has a failing test called "names the file when the database is
malformed". Read the test, then read src/store/json-store.ts, and tell me what is
wrong before you change anything.
Two things about that prompt. It names the test rather than describing the bug, which means Claude reads the assertion instead of your paraphrase of it. And it asks for a diagnosis before a fix, which costs you fifteen seconds and saves you from the class of change that makes a test pass without fixing anything.
You should get something close to: the test writes a file containing {"movements": []},
load() calls raw.items.map(...), raw.items is undefined, and the TypeError that
comes out says nothing about which file was at fault. The test asserts the file path
appears in the error message.
Now ask for the change
Fix it. There is already a StoreError class in that file that carries the filename -
use it rather than a bare Error.
That second sentence is the whole lesson in miniature. Claude would probably have wrapped
the parse in a try/catch and thrown something. It would have made the test pass. It
would also have left the file with two ways of reporting the same class of problem, which
is how src/reports/index.ts ended up with three.
You knew StoreError was there because you read the file in the previous step. That is
what the reading is for.
Read the diff
In Manual mode you get a prompt before the edit lands, with the change shown as a diff and
three ways out: allow it, allow this kind of thing for the rest of the session, or decline.
Esc declines, the same as saying no.
What to look at, in order:
- Does it fix the case the test describes? The file in that test is valid JSON. It
parses fine. A
try/catcharoundJSON.parsealone would not catch anything and the test would still fail. If the diff only wraps the parse, decline it and say so. - Does the message contain the filename? That is what is asserted. A friendlier error that does not name the file is a nicer failure and a red test.
- What else did it touch? This is the one people skip. A three-line fix that also reformats forty lines is not a three-line fix, and you are the only person who is going to notice before it is in a commit.
A fix that passes looks roughly like this: a try/catch around the read and parse
throwing a StoreError, plus a check that raw.items and raw.movements are arrays
before mapping over them. The second half is the part that matters, and the part a
try/catch alone misses.
Run the tests yourself
Accept the change and then, in the session:
Run the tests.
It will ask permission to run npm test, because that is what Manual mode is. Say yes.
Test Files 2 failed | 4 passed (6)
Tests 8 failed | 78 passed (86)
Nine down to eight. One bug, one test.
You could have run npm test in another terminal and it would have been the same. Do it
inside the session anyway, at least while you are learning: the output goes into the
conversation, which means the next thing you ask is answered by something that has seen
the result rather than something that is assuming it.
This is also the first place a session can quietly go wrong. If Claude runs the tests, sees a failure, and fixes it in the same turn without saying so, you now have two changes and have read one. Watch for it. Lesson 27 is about the failures that do not announce themselves.
Pushing back
Push back by describing the problem, not by re-issuing the instruction louder. These work:
- “That makes the test pass but it does not handle the case where items is present and not an array. Check the type, not just the presence."
- "You changed the error message format for the duplicate-sku case too. Leave that alone."
- "Simpler, please. This is a load function, not a validator.”
These do not work as well as people expect: “no”, “that’s wrong”, “try again”. They spend a turn and give it nothing to steer by, and you will usually get a different guess rather than a better one.
If two rounds of pushing back have not got you there, stop and write it yourself. The tool is good at the change you can describe precisely and mediocre at the one you are still working out. Noticing which of those you are in is most of the skill.
How do you undo a change?
Three levels, cheapest first:
Esctwice on an empty prompt opens the rewind menu, which puts your files and the conversation back to an earlier point. This is the one to reach for when the last few turns went sideways.git checkout -- <file>throws away the change to one file. Blunt, reliable, and it does not touch the conversation, so Claude still thinks it made the edit.- Commit before you start anything you are unsure about. Lesson 19 makes this a habit rather than advice.
The middle one has a trap worth knowing now: reverting a file behind Claude’s back leaves the session believing something about your code that is no longer true. Tell it what you did. “I reverted that, let us try a different approach” costs one line and saves the next three turns.
Your turn
There is a second bug, and it is a better one. Run the CLI:
cp data/seed.json data/stockroom.json
node src/cli/main.ts low
Nothing below its reorder level.
That is a lie. node src/cli/main.ts levels will show you skus with 8 or 9 on hand against
reorder levels in the hundreds. Find out why and fix it, using the loop from this lesson:
diagnose before changing, read the diff, run the tests.
Start it off with something like:
`node src/cli/main.ts low` prints "Nothing below its reorder level", but `levels` shows
BOLT-M8 with 9 on hand against a reorder level of 400. Diagnose it before changing
anything.
Check:
npm testreportsTests 1 failed | 85 passed (86), andnode src/cli/main.ts lownow lists BOLT-M8 as short by 391. Seven tests went green from one fix, across two files that you did not mention. If only some of them did, the fix patched a caller rather than the cause.
The one test still failing is a timezone bug. It is lesson 14’s, and it is harder than it looks.
If the fix went somewhere you cannot get back from, git reset --hard after-lesson-11
returns you to the clone and you can start the lesson again.
Last thing, and it matters more than it looks: commit both fixes before you move on.
git add -A && git commit -m "Fix the malformed-database path and the paging off-by-one"
Lesson 19 is where committing becomes a subject. The reason to do it seven lessons early is
the first line of this lesson’s own advice: with a clean tree, git diff means “what this
session did”. Every lesson from here changes files, and if you never commit, by lesson 19
your diff is six lessons deep and you cannot tell any session’s work from any other’s.
Recap
Ask, read, accept or push back. Point at a failing test rather than describing a bug, because the assertion is more precise than your paraphrase. Ask for a diagnosis before a fix. Read the diff for three things: does it address the real case, does it satisfy what is asserted, and what else did it touch.
Push back with the problem rather than with disapproval, and give up after two rounds.
Next: using it on code nobody explained to you, and checking that the explanation is true.