| name | tdd |
| description | Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", or asks for integration tests. |
Test-Driven Development
When to use
- The user wants to build a feature or fix a bug using test-first development
- The user mentions TDD, "red-green-refactor", or asks for integration tests
- You want to ensure behavior is verified through public interfaces before implementing
Philosophy
Core principle: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
Good tests are integration-style: they exercise real code paths through public APIs. They describe what the system does, not how it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
Bad tests are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
See tests.md for examples and mocking.md for mocking guidelines.
Anti-Pattern: Horizontal Slices
DO NOT write all tests first, then all implementation. This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
This produces crap tests:
- Tests written in bulk test imagined behavior, not actual behavior
- You end up testing the shape of things (data structures, function signatures) rather than user-facing behavior
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
- You outrun your headlights, committing to test structure before understanding the implementation
Correct approach: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
WRONG (horizontal):
RED: test1, test2, test3, test4, test5
GREEN: impl1, impl2, impl3, impl4, impl5
RIGHT (vertical):
RED→GREEN: test1→impl1
RED→GREEN: test2→impl2
RED→GREEN: test3→impl3
...
Workflow
1. Planning
When exploring the codebase, use read, grep, find, or read-only bash commands — or dispatch a scout subagent for broader exploration. Read the project's domain glossary (look for CONTEXT.md or context.md — case-insensitive) so that test names and interface vocabulary match the project's language, and respect any ADRs in the area you're touching.
Before writing any code:
You can't test everything. Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
1.5 Criteria Audit (after plan approval)
After the plan is approved by the user, dispatch a criteria-auditor subagent to cross-reference the plan's intended behaviors against the issue's acceptance criteria.
dispatch subagent: criteria-auditor
task: |
Audit the acceptance criteria in {issue_path} against the planned test coverage.
The plan intends to cover these behaviors: {list from step 1}.
Test directory: {test_dir}
Source directory: {src_dir}
Report any criteria that lack planned test coverage.
This catches gaps before any code is written — if a criterion has no corresponding test in the plan, surface it now.
2. Tracer Bullet
Write ONE test that confirms ONE thing about the system:
RED: Write test for first behavior → test fails
GREEN: Write minimal code to pass → test passes
This is your tracer bullet - proves the path works end-to-end.
2.5 Checkpoint Review (after tracer bullet)
After the tracer bullet passes (GREEN), dispatch a checkpoint-reviewer subagent to verify the first slice before continuing.
dispatch subagent: checkpoint-reviewer
task: |
Review the first TDD slice (tracer bullet).
Issue: {issue_path}
Slice description: {tracer bullet behavior}
Changed files: {list of files modified}
Test files: {list of test files modified/added}
This catches foundational problems early — wrong abstractions, missing gates, boundary violations — before they compound across subsequent slices.
3. Incremental Loop
For each remaining behavior:
RED: Write next test → fails
GREEN: Minimal code to pass → passes
Rules:
- One test at a time
- Only enough code to pass current test
- Don't anticipate future tests
- Keep tests focused on observable behavior
3.5 Periodic Checkpoint Reviews
Dispatch checkpoint-reviewer after every integration-boundary slice — a slice that:
- Touches a public API or changes a function signature
- Adds a new module boundary or cross-module call
- Introduces a new gate/conditional that other slices depend on
- Wires a new integration (e.g., connects module A to module B)
For simple slices (adding another test for the same behavior, refactoring), a checkpoint review is not necessary.
dispatch subagent: checkpoint-reviewer
task: |
Review TDD slice: {slice_description}
Issue: {issue_path}
Changed files: {list}
Test files: {list}
Previous slices: {brief summary of what earlier slices implemented}
4. Refactor
After all tests pass, look for refactor candidates:
Never refactor while RED. Get to GREEN first.
4.5 Final Quality Gate
After all slices are complete and refactored, dispatch both subagents for a final quality gate:
dispatch subagent: criteria-auditor
task: |
Full audit of acceptance criteria coverage.
Issue: {issue_path}
Test directory: {test_dir}
Source directory: {src_dir}
Verify every checkbox in the issue has a dedicated test AND implementation.
dispatch subagent: checkpoint-reviewer
task: |
Final review of all slices.
Issue: {issue_path}
Changed files: {all files changed across all slices}
Test files: {all test files added/modified}
Previous slices: {summary of all slices}
Only proceed to mark the issue complete once both reports show no BLOCKERs.
Rules
- Write one test at a time. Write minimal code to pass. Then move to the next test.
- Tests must verify behavior through public interfaces only — never test implementation details.
- Never write all tests first (horizontal slicing). Use vertical tracer bullets instead.
- Never refactor while RED. Get to GREEN first.
- When exploring the codebase, use
read, grep, find, or read-only bash — or dispatch a scout subagent for broader exploration.
- Use the project's domain glossary vocabulary from
CONTEXT.md throughout. Look for both CONTEXT.md and context.md (case-insensitive) when searching.
- Respect any ADRs in the area you're touching.
- Mock only at system boundaries (external APIs, databases, time, file system). Do not mock your own classes or internal collaborators.
- Use
read over shelling out to cat for file contents.
- Dispatch
criteria-auditor after plan approval (step 1.5) and after all slices (step 4.5).
- Dispatch
checkpoint-reviewer after the tracer bullet (step 2.5), after integration-boundary slices (step 3.5), and after all slices (step 4.5).
- Fix all BLOCKERs from checkpoint reviews before proceeding to the next slice. CONCERNs and NOTEs can be deferred but must be tracked.