Superpowers Turns Testing and Debugging into Evidence
With an isolated workspace and an explicit task contract, obra/superpowers still does not ask the coding agent to trust its own confidence. This chapter focuses on the feedback loop that tests an implementation and responds when the result is unexpected: test-driven development makes desired behavior falsifiable, while systematic debugging traces failure to its cause before a repair is attempted. The reader should come away able to tell the difference between a test that protects a behavior and a test that merely agrees with the code, then apply the same distinction to debugging.
The red phase is a proof about the test
Superpowers' TDD rule is uncompromising: no production code without a failing test first. The important word is failing. A test that passes immediately may be useful as a description of existing behavior, but it has not shown that it can detect the missing behavior the agent is about to add. Watching the failure establishes an observable starting point.
The cycle begins with one desired behavior. The agent writes the smallest test that describes it, runs that test, and checks that it fails for the expected reason. The failure should say that the behavior is missing or wrong, not that the test has a typo, an invalid fixture, or a broken setup. If the test errors for an unrelated reason, the agent fixes the test until it fails correctly. If it passes, the test may be checking behavior that already exists and needs to be reconsidered.
Only then does the agent write the simplest production code that can make the test pass. Superpowers explicitly resists the urge to add options, abstractions, error modes, or future-facing configuration that the failing test does not require. Once the test is green, the agent may refactor: remove duplication, improve names, or extract a helper while preserving the same behavior. The test is rerun after cleanup, so the refactoring remains inside an evidence boundary.
This order changes the question the agent is answering. Tests written after implementation tend to ask, “What does this code do?” Tests written first ask, “What should this code do?” The difference is not ceremonial. Existing code supplies suggestions about what to assert, including its accidental behavior. A failing test makes the desired contract explicit before the implementation can persuade the agent that its current behavior is acceptable.
The rule is also a response to common pressure. A feature may look too small to test. A manual click-through may appear faster. A developer may already have written several hours of code and want to attach tests afterward. Superpowers treats each as a reason to return to the red phase. The claimed time savings often move the uncertainty downstream, where a test that was never proven can miss the very regression it was meant to catch.
A trustworthy test names the break
A test earns its place by identifying a realistic production change that should make it fail. That change might select the wrong branch, omit a side effect, pass the wrong argument, mishandle a boundary value, or violate an interface. If no such change can be named, the test may be asserting a design decision rather than protecting behavior.
This distinction rules out several attractive but weak patterns. A test that asserts a constant has a particular value can fail when someone intentionally changes the constant, yet still miss the behavioral bug caused by using the wrong value in the wrong place. A stronger test exercises the behavior that depends on the value.