diff --git a/get-shit-done/references/plan-format.md b/get-shit-done/references/plan-format.md index 91d058344..fd4127987 100644 --- a/get-shit-done/references/plan-format.md +++ b/get-shit-done/references/plan-format.md @@ -243,6 +243,43 @@ Use for: Technology selection, architecture decisions, design choices, feature p See `./checkpoints.md` for comprehensive checkpoint guidance. + +Tasks can include `tdd="true"` attribute when TDD improves quality: + +**Structure:** +```xml + + Task N: [Name] + [paths] + [What test to write first - the failing assertion] + [Implementation to make test pass] + [Tests pass, behavior works] + [Criteria] + +``` + +**When to add tdd="true":** +- Business logic with defined inputs/outputs +- API endpoints with request/response contracts +- Data transformations and parsing +- Validation rules +- Algorithms with testable behavior + +**When NOT to add tdd="true":** +- UI layout and styling +- Configuration changes +- Glue code connecting existing components +- One-off scripts + +**Execution flow (when tdd="true"):** +1. Claude writes failing test from `` +2. Claude implements from `` until test passes +3. Claude refactors if needed (tests still pass) +4. Claude commits atomic change + +See `./tdd.md` for comprehensive TDD guidance. + + Use @file references to load context for the prompt: @@ -347,6 +384,26 @@ Claude: "How? What type? What library? Where?" Claude can implement this immediately. + +TDD task example: + +```xml + + Task 2: Create email validation utility + src/lib/validation.ts, src/lib/validation.test.ts + + Test: isValidEmail returns true for valid emails, false for invalid + Cases: "user@example.com" → true, "invalid" → false, "" → false, "user@" → false + + Implement isValidEmail using regex pattern. Handle edge cases: empty string, missing @, missing domain. + npm test -- validation.test.ts passes all cases + Email validation works for all edge cases, tests document behavior + +``` + +Claude executes this with RED → GREEN → REFACTOR cycle, producing atomic commits. + + Writing the actual code in the plan. Trust Claude to implement from clear instructions. diff --git a/get-shit-done/references/tdd.md b/get-shit-done/references/tdd.md new file mode 100644 index 000000000..b913656a8 --- /dev/null +++ b/get-shit-done/references/tdd.md @@ -0,0 +1,168 @@ + +TDD is about design quality, not coverage metrics. The red-green-refactor cycle forces you to think about behavior before implementation, producing cleaner interfaces and more testable code. + +**Principle:** If you can describe the behavior as `expect(fn(input)).toBe(output)` before writing `fn`, TDD improves the result. + + + +## When TDD Improves Quality + +**TDD candidates (add `tdd="true"`, include ``):** +- Business logic with defined inputs/outputs +- API endpoints with request/response contracts +- Data transformations, parsing, formatting +- Validation rules and constraints +- Algorithms with testable behavior +- State machines and workflows +- Utility functions with clear specifications + +**Skip TDD (standard `type="auto"`):** +- UI layout, styling, visual components +- Configuration changes +- Glue code connecting existing components +- One-off scripts and migrations +- Simple CRUD with no business logic +- Exploratory prototyping + +**Heuristic:** Can you write `expect(fn(input)).toBe(output)` before writing `fn`? +→ Yes: TDD will help +→ No: Implement first, add tests after if needed + + + +## Red-Green-Refactor Cycle + +**RED - Write failing test:** +1. Create test file following project conventions +2. Write test describing expected behavior (from `` element) +3. Run test - it MUST fail +4. If test passes: feature exists or test is wrong. Investigate. +5. Commit: `test: add failing test for [feature]` + +**GREEN - Implement to pass:** +1. Write minimal code to make test pass +2. No cleverness, no optimization - just make it work +3. Run test - it MUST pass +4. Commit: `feat: implement [feature]` + +**REFACTOR (if needed):** +1. Clean up implementation if obvious improvements exist +2. Run tests - MUST still pass +3. Only commit if changes made: `refactor: clean up [feature]` + +**Atomic commits:** Each TDD task produces 2-3 commits following this pattern. + + + +## Good Tests vs Bad Tests + +**Test behavior, not implementation:** +- Good: "returns formatted date string" +- Bad: "calls formatDate helper with correct params" +- Tests should survive refactors + +**One concept per test:** +- Good: Separate tests for valid input, empty input, malformed input +- Bad: Single test checking all edge cases with multiple assertions + +**Descriptive names:** +- Good: "should reject empty email", "returns null for invalid ID" +- Bad: "test1", "handles error", "works correctly" + +**No implementation details:** +- Good: Test public API, observable behavior +- Bad: Mock internals, test private methods, assert on internal state + + + +## Test Framework Setup (If None Exists) + +When a TDD task exists but no test framework is configured: + +**1. Detect project type:** +```bash +# JavaScript/TypeScript +if [ -f package.json ]; then echo "node"; fi + +# Python +if [ -f requirements.txt ] || [ -f pyproject.toml ]; then echo "python"; fi + +# Go +if [ -f go.mod ]; then echo "go"; fi + +# Rust +if [ -f Cargo.toml ]; then echo "rust"; fi +``` + +**2. Install minimal framework:** +| Project | Framework | Install | +|---------|-----------|---------| +| Node.js | Jest | `npm install -D jest @types/jest ts-jest` | +| Node.js (Vite) | Vitest | `npm install -D vitest` | +| Python | pytest | `pip install pytest` | +| Go | testing | Built-in | +| Rust | cargo test | Built-in | + +**3. Create config if needed:** +- Jest: `jest.config.js` with ts-jest preset +- Vitest: `vitest.config.ts` with test globals +- pytest: `pytest.ini` or `pyproject.toml` section + +**4. Verify setup:** +```bash +# Run empty test suite - should pass with 0 tests +npm test # Node +pytest # Python +go test ./... # Go +cargo test # Rust +``` + +**5. Create first test file:** +Follow project conventions for test location: +- `*.test.ts` / `*.spec.ts` next to source +- `__tests__/` directory +- `tests/` directory at root + + + +## Error Handling + +**Test doesn't fail in RED phase:** +- Feature may already exist - investigate +- Test may be wrong (not testing what you think) +- Fix before proceeding + +**Test doesn't pass in GREEN phase:** +- Debug implementation +- Don't skip to next task +- Keep iterating until green + +**Tests fail in REFACTOR phase:** +- Undo refactor +- Commit was premature +- Refactor in smaller steps + +**Unrelated tests break:** +- Stop and investigate +- May indicate coupling issue +- Fix before proceeding + + + +## Commit Pattern for TDD Tasks + +Each TDD task produces atomic commits: + +``` +test: add failing test for email validation + +feat: implement email validation + +refactor: extract regex to constant (optional) +``` + +This pattern: +- Creates clean git history +- Each commit is independently revertable +- Shows TDD discipline in commit log + diff --git a/get-shit-done/workflows/execute-phase.md b/get-shit-done/workflows/execute-phase.md index 2bb0d8100..83e46f8c7 100644 --- a/get-shit-done/workflows/execute-phase.md +++ b/get-shit-done/workflows/execute-phase.md @@ -439,6 +439,10 @@ Execute each task in the prompt. **Deviations are normal** - handle them automat **If `type="auto"`:** + **Before executing:** Check if task has `tdd="true"` attribute: + - If yes: Follow TDD execution flow (see ``) - RED → GREEN → REFACTOR cycle with multiple atomic commits + - If no: Standard implementation with single commit + - Work toward task completion - **If CLI/API returns authentication error:** Handle as authentication gate (see below) - **When you discover additional work not in plan:** Apply deviation rules (see below) automatically @@ -810,6 +814,54 @@ Logged to .planning/ISSUES.md for future consideration: + +## TDD Task Execution + +When executing a task with `tdd="true"` attribute: + +**1. Check test infrastructure:** +If no test framework configured: +- Detect project type from package.json/requirements.txt/etc. +- Install minimal test framework (Jest, pytest, Go testing, etc.) +- Create test config file +- Verify: run empty test suite + +**2. RED - Write failing test:** +- Read `` element for test specification +- Create test file if doesn't exist (follow project conventions) +- Write test(s) that describe expected behavior +- Run tests - MUST fail (if passes, test is wrong or feature exists) +- Commit: "test: add failing test for [feature]" + +**3. GREEN - Implement to pass:** +- Read `` element for implementation guidance +- Write minimal code to make test pass +- Run tests - MUST pass +- Commit: "feat: implement [feature]" + +**4. REFACTOR (if needed):** +- Clean up code if obvious improvements +- Run tests - MUST still pass +- Commit only if changes made: "refactor: clean up [feature]" + +**Commit pattern for TDD tasks:** +Each TDD task produces 2-3 atomic commits: +1. `test: add failing test for X` +2. `feat: implement X` +3. `refactor: clean up X` (optional) + +**Error handling:** +- If test doesn't fail in RED phase: Test is wrong or feature already exists. Investigate before proceeding. +- If test doesn't pass in GREEN phase: Debug implementation, don't skip to next task. +- If tests fail in REFACTOR phase: Undo refactor, commit was premature. + +**Verification:** +After TDD task completion, ensure: +- All tests pass +- Test coverage for the new behavior exists +- No unrelated tests broken + + When encountering `type="checkpoint:*"`: diff --git a/get-shit-done/workflows/plan-phase.md b/get-shit-done/workflows/plan-phase.md index 9ef016d12..a903f3554 100644 --- a/get-shit-done/workflows/plan-phase.md +++ b/get-shit-done/workflows/plan-phase.md @@ -19,8 +19,9 @@ Decimal phases enable urgent work insertion without renumbering: 2. ~/.claude/get-shit-done/references/plan-format.md 3. ~/.claude/get-shit-done/references/scope-estimation.md 4. ~/.claude/get-shit-done/references/checkpoints.md -5. .planning/ROADMAP.md -6. .planning/PROJECT.md +5. ~/.claude/get-shit-done/references/tdd.md +6. .planning/ROADMAP.md +7. .planning/PROJECT.md **Load domain expertise from ROADMAP:** - Parse ROADMAP.md's `## Domain Expertise` section for paths @@ -187,7 +188,33 @@ Decompose phase into tasks. Each task needs: - **Verify**: How to prove it worked - **Done**: Acceptance criteria -**TDD fit:** Can you write `expect(fn(input)).toBe(output)` before writing `fn`? Yes (business logic, APIs, validation) → test-first. No (UI layout, config, glue code) → standard implementation. +**TDD detection:** For each task, evaluate TDD fit: + +TDD candidates (add `tdd="true"` to task, include `` element): +- Business logic with defined inputs/outputs +- API endpoints with request/response contracts +- Data transformations, parsing, formatting +- Validation rules and constraints +- Algorithms with testable behavior +- State machines and workflows + +Skip TDD (standard `type="auto"` task): +- UI layout, styling, visual components +- Configuration changes +- Glue code connecting existing components +- One-off scripts and migrations +- Simple CRUD with no business logic + +**Heuristic:** Can you write `expect(fn(input)).toBe(output)` before writing `fn`? +→ Yes: Add `tdd="true"`, include `` describing the failing test +→ No: Standard task, no TDD annotation + +**Test framework:** If project has no test setup and TDD tasks exist, add a setup task first: +- Detect project type (package.json → Jest, requirements.txt → pytest, etc.) +- Add minimal test configuration +- Create example test file to verify setup + +See `~/.claude/get-shit-done/references/tdd.md` for complete TDD guidance. **Checkpoints:** Visual/functional verification → checkpoint:human-verify. Implementation choices → checkpoint:decision. Manual action (email, 2FA) → checkpoint:human-action (rare). @@ -292,6 +319,21 @@ Phase plan created: .planning/phases/XX-name/{phase}-01-PLAN.md - "Set up authentication" / "Make it secure" / "Handle edge cases" If you can't specify Files + Action + Verify + Done, the task is too vague. + +**Good TDD task:** +```xml + + Create price calculator with discount rules + src/lib/pricing.ts, src/lib/pricing.test.ts + + Test: calculatePrice applies discounts correctly + Cases: base 100 + 10% off → 90, base 100 + 20% off + $5 coupon → 75 + + Implement calculatePrice(base, discountPercent, couponAmount). Apply percentage first, then flat amount. + npm test -- pricing.test.ts passes + Price calculation handles all discount combinations correctly + +```