Regression-First Fixing: Test That Fails, Then Code That Passes
What This Concept Is
Regression-first fixing is a simple rule for any confirmed defect:
- Reproduce the bug with a new automated test.
- Confirm the test fails for the same reason as the bug report.
- Write the smallest change that makes the test pass.
- Keep the test in the suite forever as a regression guard.
It is a discipline, not a style. It applies to unit, integration, and E2E-level bugs equally. The key is that the test is written first, it fails first, and the failure mode matches the bug report.
Michael Feathers calls this the characterization test pattern when working with legacy code: write a test that captures current behavior, then change. For a defect, the logic inverts -- the test captures the correct behavior the system should have had -- but the discipline is identical. Dan North's BDD framing adds the second layer: name the test as a sentence about behavior ("POST /tasks accepts unicode titles"), not about internals, so the test reads as specification to the next maintainer.
Why It Matters Here (In the Capstone)
Most capstone defect regressions happen for one of three reasons:
- the fix was done without a test, so it regressed later when unrelated code changed;
- a test was added after the fix and could no longer confirm the failure was real;
- the "bug" was fixed by changing the code in a way that does not match the actual root cause.
Regression-first fixing removes all three failure modes. The test that fails first proves the bug is real. The test that passes second proves the fix addresses the bug. The test that stays in the suite proves the fix holds.
It also couples bug triage (Concept 10) to actual code change: a triage entry without a regression test is incomplete, and a regression test without a triage entry is suspicious.