Claude
Skills
← Back

tdd-workflow

Strict TDD state machine with Result types. 7-state workflow (PLANNING, RED, GREEN, REFACTOR, VERIFY, BLOCKED, VIOLATION). Every message MUST announce state. Integrates with fn(args, deps), vitest-mock-extended, and typed error handling.

Code Review

What this skill does


# TDD Workflow

Strict test-driven development with Result types, dependency injection, and state machine governance.

## The Iron Law

```
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
```

Write code before the test? **Delete it. Start over.**

**No exceptions:**
- Don't keep it as "reference"
- Don't "adapt" it while writing tests
- Don't look at it
- Delete means delete

Implement fresh from tests. Period.

**Rationale:** Code written before tests is biased by implementation. TDD requires tests to drive design, not verify existing code.

## CRITICAL: STATE MACHINE GOVERNANCE

**EVERY SINGLE MESSAGE MUST START WITH YOUR CURRENT TDD STATE**

Format:
```
⚪ TDD: PLANNING
šŸ”“ TDD: RED
🟢 TDD: GREEN
šŸ”µ TDD: REFACTOR
🟔 TDD: VERIFY
āš ļø TDD: BLOCKED
šŸ”„ TDD: VIOLATION
```

**NOT JUST THE FIRST MESSAGE. EVERY. SINGLE. MESSAGE.**

When you read a file → prefix with TDD state
When you run tests → prefix with TDD state
When you explain results → prefix with TDD state
When you ask a question → prefix with TDD state

Example:
```
⚪ TDD: PLANNING
Writing test for getUser returning NOT_FOUND...

⚪ TDD: PLANNING
Running npm test to see it fail...

šŸ”“ TDD: RED
Test fails correctly. Implementing minimum solution...

🟢 TDD: GREEN
Test passes. Checking if refactor needed...
```

## State Machine Diagram

```
                  user request
                       ↓
                 ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
            ā”Œā”€ā”€ā”€ā”€ā”‚ PLANNING │────┐
            │    ā””ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”˜    │
            │          │         │
            │  test fails        │
            │  correctly         │
  unclear   │          ↓         │ blocker
            │    ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    │
            └────│   RED    │    │
                 │          │    │
                 │ Test IS  │    │
                 │ failing  │    │
                 ā””ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”˜    │
                      │          │
              test    │          │
              passes  │          │
                      ↓          │
                 ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    │
                 │  GREEN   │    │
                 │          │    │
                 │ Test IS  │    │
                 │ passing  │    │
                 ā””ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”˜ā”€ā”€ā”€ā”€ā”˜
                      │
          refactoring │
          needed      │
                      ↓
                 ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
            ā”Œā”€ā”€ā”€ā”€ā”‚ REFACTOR │
            │    │          │
            │    │ Improve  │
            │    │ design   │
            │    ā””ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”˜
            │         │
            │    done │
            │         │
            │         ↓
            │    ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
            │    │  VERIFY  │
            │    │          │
            │    │ Run full │
  fail      │    │ suite +  │
            │    │ lint +   │
            └────│ build    │
                 ā””ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”˜
                      │
                 pass │
                      │
                      ↓
                 [COMPLETE]
```

## State: PLANNING

**Prefix:** `⚪ TDD: PLANNING`

**Purpose:** Write a failing test that proves the requirement.

### Pre-Conditions
- User has provided a task/requirement/bug report
- No other TDD cycle in progress

### The Delete Rule

If production code exists before the test:
1. **Delete it immediately**
2. Do not keep as "reference"
3. Do not "adapt" it
4. Start fresh from the test

**Rationale:** Code written before tests is biased by implementation. TDD requires tests to drive design, not verify existing code.

### Actions
1. Analyze requirement - what behavior needs testing?
2. Identify edge cases
3. Write test using fn(args, deps) pattern
4. Use vitest-mock-extended: `const deps = mock<GetUserDeps>()`
5. Run test (use Bash tool)
6. **VERIFY test fails correctly** (MANDATORY - see Verify RED below)
7. Show exact failure message verbatim
8. Justify why failure proves test is correct

### Verify RED - Watch It Fail

**MANDATORY. Never skip.**

```bash
npm test path/to/test.test.ts
```

Confirm:
- Test fails (not errors)
- Failure message is expected
- Fails because feature missing (not typos)

**Test passes?** You're testing existing behavior. Fix test.
**Test errors?** Fix error, re-run until it fails correctly.

### Post-Conditions (ALL required before transition)
- [ ] Test written with proper deps mocking
- [ ] Test executed
- [ ] Test FAILED correctly (not setup error) - **VERIFIED by watching it fail**
- [ ] Failure message shown verbatim
- [ ] Failure is "meaningful" (assertion failure, not import error)

### Validation Before Transition
```
Pre-transition validation:
āœ“ Test written: [yes/no]
āœ“ Test executed: [yes/no]
āœ“ Test failed correctly: [yes - output above]
āœ“ Meaningful failure: [yes - justification]

Transitioning to RED.
```

### Transitions
- PLANNING → RED (test fails correctly)
- PLANNING → BLOCKED (cannot write valid test)

## State: RED

**Prefix:** `šŸ”“ TDD: RED`

**Purpose:** Test IS failing. Implement ONLY what the error message demands.

### Pre-Conditions
- Test written and executed
- Test IS FAILING correctly
- Failure is meaningful (not setup/syntax error)

### The Hardcode Rule

Before implementing, announce:
```
Minimal implementation check:
- Error demands: [what the error literally says]
- Could hardcoded value work? [yes/no]
- If yes: [what hardcoded value]
- If no: [why real logic is required]
```

| Error Says | Do This |
|-----------|---------|
| `expected err('NOT_FOUND')` | `return err('NOT_FOUND')` |
| `expected ok(user)` | `return ok(mockUser)` |
| `expected count: 0` | `return { count: 0 }` |

Only add logic when tests FORCE you to.

### Actions
1. Read error message - what does it literally ask for?
2. Announce minimal implementation check
3. Implement ONLY what error demands (hardcode if possible)
4. Run test
5. **VERIFY test PASSES** (MANDATORY - see Verify GREEN below)
6. Run typecheck (`npm run typecheck`)
7. Run lint (`npm run lint`)
8. Show all output verbatim
9. Transition to GREEN

### Verify GREEN - Watch It Pass

**MANDATORY. Never skip.**

```bash
npm test path/to/test.test.ts
```

Confirm:
- Test passes
- Other tests still pass
- Output pristine (no errors, warnings)

**Test fails?** Fix code, not test.
**Other tests fail?** Fix now.

### Post-Conditions (ALL required)
- [ ] Implemented ONLY what error demanded
- [ ] Test executed and PASSES
- [ ] Code compiles (no TypeScript errors)
- [ ] Code lints (no ESLint errors)
- [ ] All output shown verbatim

### Validation Before Transition
```
Post-condition validation:
āœ“ Test PASSES: [yes - output above]
āœ“ Code compiles: [yes - output above]
āœ“ Code lints: [yes - output above]
āœ“ Implementation minimal: [justification]

Transitioning to GREEN.
```

### Critical Rules
- NEVER transition to GREEN without test PASS + compile + lint
- NEVER anticipate future errors - address THIS error only
- NEVER change test to match implementation - fix the code

### Transitions
- RED → GREEN (test passes, code compiles, code lints)
- RED → BLOCKED (cannot make test pass)
- RED → PLANNING (test failure reveals misunderstood requirement)

## State: GREEN

**Prefix:** `🟢 TDD: GREEN`

**Purpose:** Test IS passing. Assess code quality and decide next step.

### Pre-Conditions
- Test exists and PASSES
- Code compiles and lints
- Implementation is minimal

### Actions
1. Review implementation against patterns:

| Pattern | Check |
|---------|-------|
| fn(args, deps) | Is deps type explicit and minimal? |
| Result types | Are all error cases typed? |
| Validation | Is Zod at boundary only? |
| Naming | Domain-specific, not generic? |

2. Decide: Does code need refactoring?
3. If YES → REFACTOR
4. If NO → VERIFY

### Post-Conditions
- [ ] Test IS PASSING
- [ ] Code quality assessed
- [ ] Decision made: refactor or verify

### Transitions
- GREEN → REFACTOR (improvements needed)
- GREEN → VERIFY (code is clean)
- GREEN → RED (test starts failing - regression)

## State: REFACTOR

**Prefix:** `šŸ”µ TDD: REFACTOR`

**Purpose:** Tests ARE passing. Improve design while keeping green.

### Pre-Conditions
- Tests ARE 

Related in Code Review