--- name: tdd description: Implement a single `ready-for-agent` slice from a wiki user story using disciplined red-green-refactor with vertical tracer bullets. Reads the slice description, the story's Gherkin scenarios (as the test specification), `glossary.md` (for vocabulary), and the referenced specs/ADRs. Refuses horizontal slicing (write-all-tests-then-all-impl). Ticks the slice checkbox when done. Use when the user says "let's TDD slice X", "implement slice 2 of story Y", "/tdd", "red-green-refactor this", or wants to start vertical-slice implementation on a wiki-tracked story. --- # TDD — Vertical Tracer-Bullet Test-Driven Development Take ONE `ready-for-agent` slice from a wiki story and implement it with the red-green-refactor loop. The story's Gherkin scenarios ARE the test specification — translate them directly into integration tests. ## Prerequisites - `WIKI_SCOPE: ` declared in the project instructions. - Target slice exists in a story file at `projects//plan//story-N-.md`. - The parent story's `triage_state` is `ready-for-agent`. If `needs-info` or `needs-triage`, suggest `/triage` first. ## Philosophy **Test 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*. They survive refactors. - **Bad tests** are coupled to implementation: mock internal collaborators, test private methods, query internals directly. Warning sign: test breaks when you refactor but behavior hasn't changed. A story's **Gherkin scenarios are your test specification**. Each `Scenario` block translates to one integration test. Given/When/Then maps to setup/action/assertion. ## Anti-pattern: Horizontal slicing — REFUSED **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." ``` 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 ``` Why horizontal produces crap tests: - Tests written in bulk test *imagined* behavior, not *actual* behavior. - You end up testing the *shape* of things rather than user-facing behavior. - Tests become insensitive to real changes. - You outrun your headlights — committing to test structure before understanding the implementation. If you find yourself writing test #2 before test #1's implementation passes, **stop**. Finish the green for #1 first. ## Process ### 1. Read the slice context - Read the story file: User Story, Scenarios, Slices, References. - Identify the target slice (user names it, or pick the next unchecked slice). - Read `glossary.md` for vocabulary — test names, variable names, interface vocabulary should match the project's domain language. - Read each referenced `[[spec-X]]` and `[[adr-Y]]` for technical constraints. - Read recent ADRs in the scope's `adr/` for testing strategy decisions (look for `adr-testing-strategy.md` or similar). - Identify whether prior tests in the codebase establish a pattern (test framework, structure, helpers). Match the existing style. ### 2. Plan the slice (one block of upfront thinking, then loop) Before writing code: - [ ] Confirm with user what interface changes the slice requires (if not already obvious from spec). - [ ] List the **behaviors to test** for THIS slice (not all of the story — only what this slice covers). - [ ] Identify deep-module opportunities (small interface, deep implementation). - [ ] Check that scenarios are concrete enough to be tests; if not, return to `/triage`. - [ ] Get user approval on the test list. State your plan briefly. Don't burn turns enumerating implementation steps — the loop will reveal them. ### 3. Tracer bullet (first vertical) Pick the simplest scenario from the slice. Translate it to ONE test: ``` RED: Write test for scenario 1 → test fails (compilation or assertion) GREEN: Write minimal code to pass → test passes ``` This is your tracer bullet — it proves the path works end-to-end through every layer. ### 4. Incremental loop For each remaining scenario in this slice: ``` RED: Write next test → fails GREEN: Minimal code to pass → passes ``` Rules: - **One test at a time.** - **Only enough code to pass the current test.** - **Don't anticipate future tests** (that's horizontal-slicing creeping in). - **Keep tests focused on observable behavior** — through the public interface only. - **Run all prior tests** after each green to catch regressions. ### 5. Refactor (only after slice is green) After all scenarios for this slice pass: - [ ] Extract duplication. - [ ] Deepen modules — move complexity behind simple interfaces. - [ ] Apply principles where natural (DRY, SOLID), but don't force them. - [ ] Consider what new code reveals about existing code. - [ ] Run tests after each refactor step. **Never refactor while RED.** Get to GREEN first. ### 6. Tick the slice checkbox Once the slice is green and refactored: 1. Open the story file. 2. Tick the corresponding `## Slices` checkbox: `- [ ]` → `- [x]`. 3. Bump `updated:` in the story's frontmatter. 4. If ALL slices in the story are now ticked and its acceptance criteria hold: set `status: archived` with `updated` from the clock and say so in the report — the story is done, and the plan's Story Index row follows at handoff. A story whose slices are ticked but whose acceptance still waits on a witness or a release stays `active`, with the waiting condition in its Decisions. 5. Confirm the resync: the posttool hook syncs automatically; if `kmd config`'s `synced` line did not advance, run `kmd validate` then `kmd sync`. ### 7. Done — report > "Slice of `[[story-N-]]` is green. tests added. Remaining slices in this story: . Next: pick another slice or move to a different story." ## Per-slice checklist ``` [ ] Test describes behavior, not implementation [ ] Test uses public interface only [ ] Test would survive an internal refactor [ ] Code is minimal for the current test [ ] No speculative features added [ ] No mocks of internal collaborators [ ] All prior tests still pass ``` ## Mocking guidance - **Mock external systems at the boundary** — third-party APIs, network calls to services not under test. - **Don't mock your own internal collaborators** — that's coupling tests to structure. - **Don't mock the database in integration tests** — use a real test database. Mock-based tests passing while migrations break is a real failure mode (recurring industry incident). - If the user has an `adr-testing-strategy.md` or similar, follow its guidance. ## Deep modules A **deep module** has a small interface and a substantial implementation. A **shallow module** has a large interface relative to its implementation (often a thin wrapper). When refactoring: - Look for shallow modules to deepen — push complexity behind narrower interfaces. - Look for opportunities to encapsulate variability — make the surface stable while internals can change. - Don't deepen prematurely — let the third use-case reveal the right shape. ## Spec/ADR drift If during implementation you discover the spec is wrong (code reality differs from `spec-{topic}.md`): - **Update the spec inline** in the same commit as the slice. Don't queue spec corrections in the plan — that creates doc-debt the wiki resync protocol explicitly forbids. - If the divergence is a hard-to-reverse decision, propose an ADR via `/intent`. ## Rules - **One slice at a time.** Consecutive slices in one session are fine while the context is hot; commit at a story or release boundary, not per slice. - **Tests before code, every time.** No exceptions. - **One test, then make it green, then next test.** Vertical, not horizontal. - **Minimum code to pass.** No speculative features. - **Refactor only when green.** - **Tick the checkbox when done** — that's the resync protocol's signal that the slice shipped. - **Confirm the resync** — the posttool hook syncs automatically; if `kmd config`'s `synced` line did not advance, run `kmd validate` then `kmd sync`. - **Update spec inline** if reality diverges; don't queue corrections. - **Quote prose-bearing frontmatter scalars** to avoid breaking the sync walker.