Day one. The Slack PM pings: “Simple calculator in settings — 4 functions, 17 buttons, AC. How hard can it be?” The junior writes the obvious version: every tap concatenates its label onto the display string, and the "=" key calls eval() on the accumulated expression. Demo passes. Ship.

Below is that calculator, exactly as shipped. Tap it freely. Then hit the canned trap buttons to see the five failure modes the junior missed: 1..5 (NaN), 1++2 (SyntaxError), 1+ (dangling op), +5 (leading op), 5/0 (Infinity). Each one produces a DIFFERENT visible bug. A “guard per bug” cascade is one PR away from never-ending.

The displaytaps 0
0
Canned traps (tap to replay)

Each one plays the full sequence through the naive handler. Watch the display after "=". Five distinct failure modes — feel at least three.

The failure modes are not a cohesive class. NaN means “I parsed a number badly.” SyntaxError means “eval saw garbage.” Infinity means “the arithmetic succeeded but the answer has no representation.” +5 sometimes evaluates (unary plus), sometimes doesn't. Each bug asks for a different guard. The guards accumulate faster than the feature does.

The deeper problem: the DISPLAY STRING and the CALCULATOR'S STATE are the same thing. “1+” and “+1” are identical to the concat logic — both are three characters the user typed — but one is a dangling operator and the other is a leading operator. The logic has no shape that tells them apart. Phase 2 will separate state from display and the ambiguity dissolves.

Run at least three of the five canned traps. Each one exposes a DIFFERENT failure mode. Trapped so far: 0 / 5.