Hypotheses, logging, and binary search
Once the AI proposes a cause, don't just accept it. Test it cheaply. The cheapest test is usually a log line.
Ask the AI to add temporary logging:
"Before we change anything, add a
console.log(oruserright before line 14, so we can see whether it's actually undefined."
Run it, paste the output back. Now you have evidence, not a theory. Maybe user is undefined — confirming the hypothesis. Maybe it's fine and the real culprit is one level up. Either way you've moved forward. Log generously while you investigate: the value of the variable, and a label saying which one it is and where the log sits. A bare console.log(user) that prints undefined is far less useful than console.log("user at validate.js:14 =", user). And remember to pull the temporary logs back out once the bug is fixed — leftover debug noise is its own small mess.
When the bug lives somewhere in a long process and you can't tell where, use binary search. Cut the suspect region in half: add a log at the midpoint.
The idea: each check throws away half of what's left, so a huge search space collapses fast. Here a bug hides somewhere between step 1 and step 8 — three checks corner it:
step: 1 2 3 4 5 6 7 8 a bug is somewhere in here
░░░░░░░░░░░░░░░░░░░░░░
check 1 ── log at 4 ── OK ──▶ bug is AFTER 4, drop 1–4
░░░░░░░░░░░ (5 6 7 8 left)
check 2 ── log at 6 ── BAD ─▶ bug is AT/BEFORE 6, drop 7–8
░░░░░ (5 6 left)
check 3 ── log at 5 ── OK ──▶ bug is at step 6 ✔ found
8 steps → 3 checks. 1000 steps → about 10 checks.
``` Did the value look correct there? Then the bug is *after* it — search that half. Did it look wrong already? The bug is *before* — search that half. Each step halves the search space, so even a thousand-line path narrows down in about ten checks. Tell the AI explicitly: "Help me bisect this — where's the halfway point I should log?" The same technique works on history, not just code: if a feature worked last week and broke today, bisect your commits to find the exact change that introduced the bug.