// Verify, don't trust · lesson 02
Counterexample hunting
The most useful verification habit I have is also the most uncomfortable one: after the thing is built and appears to work, I stop trying to confirm it works and start actively trying to break it. Not casually. On purpose, adversarially, looking for the input or sequence or condition that makes it fail. It's a step in its own right in how I build, and skipping it is how bugs graduate from your machine to your users'.
The instinct after something runs is relief, and relief wants to move on. Counterexample hunting is the discipline of not moving on. Instead you ask the hostile questions. What input breaks this? What sequence of actions puts it in a state I didn't plan for? What assumption did I bake in that isn't actually guaranteed? What happens at the boundary, one past the limit, exactly at zero, on the empty case, on the duplicate request? You're not confirming the happy path. You're hunting the unhappy ones, because those are the ones that exist whether you look for them or not.
Why hunt for failures instead of confirming success?
Because confirming success is easy and nearly worthless. Of course it works on the case you built it for; you built it for that case. That tells you almost nothing about the cases you didn't build for, which is where every real bug lives. Confirmation bias has a technical cost here: a test suite full of cases that pass is a suite that samples the happy path and calls it coverage. Counterexample hunting deliberately steers at the parts of the input space you'd rather not think about, because that's the only place a new bug can be hiding.
The reframe that makes it work
Adopt the mindset that there is a bug and your job is to find it, not to prove there isn't one. The two mindsets search completely different spaces. "Prove it works" looks at the cases that work. "Find the bug" looks at the cases that might not, which is the only search that finds anything. You find the bug, or the user does, and finding it yourself is always cheaper, less embarrassing, and less expensive to fix.
The takeaway: after it works, try to break it, because confirming success samples the happy path while hunting counterexamples searches where the bugs actually live. Assume there's a bug and go find it.