You have the best debugging partner in the history of the discipline sitting in your editor: tireless, fluent in every error message ever written, capable of reading ten files in the time you read one, and genuinely excellent at diagnosis when handed good information. That last clause is this whole lesson. Because the same partner, handed garbage, becomes something else entirely — an eager panic-fixer that will happily bury your bug under six layers of patches while assuring you each one did the trick. Which one you get is decided almost entirely by what you type, so let's talk about what to type.
The anti-pattern: "fix it"
Here's the trap, and I want to describe it precisely because you will feel its pull. Something breaks. You paste nothing, describe nothing, and type "fix it." The agent — which cannot see your screen, doesn't know what you expected, and has only the code and vibes — guesses. It finds something plausible-looking and changes it. Still broken. "fix it." It guesses again, patching its previous patch. Still broken. "still broken, fix it" — and each round, the agent adds more code: another null check, another try/catch, another special case, each one a bandage on a symptom, none of them touching the cause, and the codebase drifting further from health with every "fix." This is intellectual junk food, and the reason it's so seductive is a feeling I want to name so you can recognize it: you're always sure just one more "fix it" will finish it. You are nearly always wrong. What actually happens is the agent panic-fixes enough surface area that the symptom you noticed goes quiet — while the gap that caused it is still in there, now wearing camouflage.
Garbage in, garbage out — it was true of your very first prompt in this course and it's truest of all here, because debugging is precisely the activity where the agent has the least context and you have the most. You watched it break. You know what you expected. The agent knows neither until you say so.
The diagnostic tell, when you're reviewing an agent's fix: did it remove or correct something wrong, or did it add something protective? Real fixes usually change code — a condition corrected, a wrong name fixed, an order swapped. Bandages add code — the null check that hides where the null came from, the try/catch that muffles the scream. Additions aren't always wrong, but they should always make you ask the question.
The quality bar: describe the gap
Now the liberating part, because the fix for "fix it" is not "become a diagnostician." You do not need to pinpoint the problem. You need to describe the gap — the same gap from the last lesson, expectation versus reality, written down with care:
"On the recipe list page, I typed 'soup' in the search box and pressed enter. I expected to see the two soup recipes I know are in the database. Instead, the list went completely empty — no error on screen, nothing red in the console. The Network tab shows the request went out to
/api/recipes?q=soupand came back 200 with[]. It reproduces every time. Searching with an empty box shows all recipes fine."
Read what that report contains, because it's a template: the actions and inputs (what you did, exactly), the expectation (what should have happened, and why you believe it — "I know they're in the database"), the reality (what happened instead, including the absence of errors — silence is data), the evidence you already gathered (that Network tab check just told the agent the bug is server-side — you cut its search space in half before it started), and the reproduction (every time, plus a case that works). Not one word of diagnosis in it, and yet an agent handed that report will very likely find the bug in one pass — because you did the observing, which is the half it can't do, and left it the hunting, which is the half it's phenomenal at. Your triage questions slot straight into this format: which-world evidence and loud-or-silent are exactly the details that turn a complaint into a brief.
When there's a loud error, the report is even easier — you learned its recipe back in the Node lesson and it hasn't changed: the full error text verbatim, the code around the line it names, and what you were doing when it died.
The mode ladder, and letting it drive
With a good brief in hand, choose the engagement deliberately — the ladder from the scavenger hunt applies to bugs too: explain ("here's the gap; walk me through what's likely happening — don't fix anything yet") when you're learning; hint ("tell me where to look") when you want the find; fix when you want it done. All three are legitimate; drifting to "fix" by default is how the learning stops, so make it a choice rather than a reflex.
And in agentic mode, the agent can run the whole loop itself — adding its own console.logs, running the app, reading the output, iterating — which is legitimately powerful and worth watching at least once just to see your own methodology reflected back at speed. Your job shifts to steering, and three instructions do most of it: "reproduce it before you fix it" (the doctrine, delegated — an agent that can't make the bug happen is guessing just like you would be); constrain the blast radius ("the bug is somewhere in search; don't touch anything else"); and watch the terminal while it works, because you read that dialect now and the agent's own probes are legible to you.
Verify: the two duties
The agent declares victory. Before you believe it:
Duty one — cause or bandage? Ask it directly: "Explain the root cause, and why this fix addresses the cause rather than the symptom." If the fix added a protective layer, push: "What made that value null in the first place?" A real root-cause explanation names the gap — the specific difference between intention and code — and the fix visibly closes that. If the explanation is a shrug in paragraph form, the bug is still in there.
Duty two — the diff, always. What else did the fix touch? You know this ritual cold; its stakes are just higher now, because panic-fixes love to "improve" adjacent code. And let me elevate the ritual to the standing law it's quietly been all course: read all the code the agent outputs. Always. Every time. Every line that goes into your project should have passed through your eyes and been reviewed by you — not because each line hides a disaster, but because the alternative is a codebase you no longer know, and everything in this course depends on you knowing your codebase. This never stops being the rule, and here's the encouraging part: it never stops paying you back, either — reading code is a skill that compounds, and every diff you review makes the next one faster. The version of you six months from now reads diffs at a pace present-you wouldn't believe, and the only way there is through. And run your reproduction one more time yourself — plus a quick lap around the neighboring features, because the second-worst outcome of a fix is that it quietly broke something else. (Doing that lap by hand every time is tedious, you say? Correct. That tedium has a tool, and it's the next lesson.)
Live demo: an old friend with a limp
Let's run the whole two-player game on a real bug — one that has been sitting in this course's calculator since the day you cloned it. The ticket, as a user would file it: "If I do 1 − 1 − 5, the calculator says 5. It should say −5. Other math seems fine??" Watch the loop: reproduce (it's reliable — good), classify (silent — no error, just wrong math; browser-world, pure logic), then instrument — a flashlight in flushOperation shows the subtraction never runs on that third press. Now the brief, gap-style, handed to the agent — and the diagnosis it should land on is a genuinely satisfying one: the code uses runningTotal === 0 to mean "no calculation started yet," but 1 − 1 makes the running total legitimately zero, so the machine mistakes mid-calculation for fresh-start and stores instead of subtracting. A sentinel value colliding with a real value — a classic, and note the shape of the real fix: not a patch around zero, but replacing the sentinel with an honest separate flag for "has a calculation started." Evaluate whatever your agent proposes against that bar: does it fix the idea that was wrong, or does it special-case the symptom? You now know how to tell the difference, which was this lesson's entire job.
🤖 Ask your AI Assistant. Two rounds. First, train the report: run sabotage roulette again (commit; "introduce one subtle bug, don't tell me where"), but this time, before any fixing, write your gap description — actions, expectation, reality, evidence, reproduction — and ask: "Here's my bug report. Before you fix anything, critique the report itself: what's missing or vague that would slow you down?" Getting your bug reports reviewed by their intended audience is the fastest possible way to get good at them. Then let it hunt, and run both duties on the result — root-cause interrogation, diff review. Second, the meta-question worth asking once: "When I bring you a bug, what's the difference in how you work between me saying 'fix it' and me giving you a detailed report like this one?" The answer, from the source, is this lesson's argument — and hearing your tools explain why your care matters to them tends to make the care stick.
Recap
- The agent is the best debugging partner ever built when handed good information — and a panic-fixer when handed "fix it." Each fix-it round adds bandages and camouflage; "one more will finish it" is a feeling, not a fact.
- You don't need the diagnosis; you need the gap, in depth: exact actions and inputs, what you expected, what happened instead (silence included), the evidence you gathered, and how to reproduce it. Your observations are the half the agent can't do.
- Choose the mode — explain, hint, or fix — deliberately. In agentic mode, steer: reproduce-before-fixing, constrained blast radius, eyes on the terminal.
- Two duties before believing any fix: root cause or bandage (real fixes tend to change code; bandages tend to add it), and the diff plus a lap around the neighbors. And the standing law behind duty two: read every line the agent outputs, always — reading compounds, and knowing your codebase is what everything else depends on.
- The calculator's ghost is finally at rest: a sentinel value colliding with a legitimate zero — and the real fix replaced the wrong idea instead of patching its symptom.
Next: the best debugging session is the one that never happens — the tools that catch bugs before they're born.