| name | test-driven-fix |
| description | Test-first debugging loop that reproduces bugs with failing tests, then iterates until tests pass. Activates for "write a test first", "test-driven fix", "TDD fix", "reproduce with test", "make it pass", or when fixing bugs that have an existing test suite. |
| allowed-tools | ["Read","Grep","Glob","Bash","Edit","Write","Task"] |
Test-Driven Fix Protocol
When This Skill Activates
- "Write a test first", "fix with TDD", "test-driven fix"
- "Reproduce with a test", "make the tests pass"
- Bug fixes where a test suite already exists
- Iterative fix cycles where verification is automated
- After 2+ failed fix attempts on the same bug (escalation)
Anti-Hallucination Rules (NEVER violate)
| Rule | Description |
|---|
| TEST MUST FAIL FIRST | Never skip the "reproduce" step. The test MUST fail before you fix anything, proving it captures the bug |
| MINIMAL FIX ONLY | Fix the bug, not the neighborhood. Don't refactor, don't add features, don't "improve" surrounding code |
| NO BLIND RETRIES | If a fix doesn't work, DIAGNOSE why before trying again. Never retry the same approach |
| EVIDENCE AT EVERY STEP | Show test output at each phase. User should see: failing test → diagnosis → fix → passing test |
| FULL SUITE AFTER FIX | After your fix passes the targeted test, run the FULL test suite. No regressions allowed |
| 3-ATTEMPT LIMIT | If 3 fix attempts fail, STOP and escalate to the user with findings so far |
The Loop: REPRODUCE → DIAGNOSE → FIX → VALIDATE
Phase 1: REPRODUCE (Write or Identify Failing Test)
If tests already exist:
npm test
npm test -- --grep "test name"
If no test captures the bug, write one:
describe('BugDescription', () => {
it('should [expected behavior] when [condition]', () => {
const input = ;
const result = functionUnderTest(input);
expect(result).toBe(expectedValue);
});
});
Run the test — it MUST fail:
npm test -- --grep "BugDescription"
If the test passes immediately, your test doesn't capture the bug. Rewrite it.
Phase 2: DIAGNOSE (Understand Root Cause)
Before writing any fix:
1. Read the failing test output carefully
2. Read the relevant source code (use Read, Grep, Glob)
3. Trace the execution path from input to failure point
4. Form a specific hypothesis:
- NOT: "something is wrong"
- YES: "fetchUser returns null when id=0 because the falsy check treats 0 as missing"
5. Document your hypothesis before proceeding
Use TodoWrite to track your diagnosis:
[ ] Identified failing test and its assertion
[ ] Read source code at failure point
[ ] Formed specific hypothesis with evidence
[ ] Planned minimal fix
Phase 3: FIX (Implement Minimal Change)
Apply the smallest possible change that addresses the root cause:
- Change ONLY the lines needed to fix the bug
- Do NOT refactor surrounding code
- Do NOT add "nice-to-have" improvements
- Do NOT change unrelated files
- If fix requires changes in multiple files, verify each file path before editing
Phase 4: VALIDATE (Run Tests)
Step 1: Run the targeted test
npm test -- --grep "BugDescription"
Step 2: Run the full test suite
npm test
Step 3: If targeted test fails → back to Phase 2
- Do NOT retry the same fix
- Re-read the test output
- What's different from your hypothesis?
- Form a NEW hypothesis based on the new evidence
- Track attempt number (max 3 before escalation)
Step 4: If full suite has regressions → adjust fix
- Read the newly failing tests
- Your fix broke something else
- Adjust fix to handle both cases
- Re-run full suite
Step 5: Only when ALL tests pass:
git add [specific files]
git commit -m "fix: [description of what was fixed and why]"
Attempt Tracking
Track each fix attempt:
### Attempt 1
- Hypothesis: [what you thought was wrong]
- Fix applied: [what you changed]
- Result: FAIL — [why it failed]
- Learning: [what you learned]
### Attempt 2
- Hypothesis: [updated hypothesis based on attempt 1]
- Fix applied: [different approach]
- Result: PASS/FAIL
After 3 failed attempts:
### Escalation
- Bug: [description]
- 3 attempts tried: [summary]
- Evidence gathered: [what we know]
- Remaining hypotheses: [what hasn't been tried]
- Recommendation: [suggested next step]
Framework-Specific Commands
| Framework | Run All | Run Specific | Watch Mode |
|---|
| Jest | npm test | npm test -- --grep "name" | npm test -- --watch |
| Vitest | npx vitest | npx vitest -t "name" | npx vitest --watch |
| Bun | bun test | bun test --grep "name" | N/A |
| Pytest | pytest | pytest -k "name" | pytest-watch |
| Cargo | cargo test | cargo test test_name | cargo watch -x test |
| Playwright | npx playwright test | npx playwright test -g "name" | N/A |
Verification Checklist
Key Principle
The test is your contract. Write a test that fails because of the bug, then make it pass with the smallest possible change. If you can't make it pass in 3 attempts, you don't understand the bug well enough yet — escalate with your evidence, don't keep guessing.