---
name: rlm-tdd
description: 'Use when implementing any code in RLM Phase 3. Enforces strict RED-GREEN-REFACTOR discipline with The Iron Law - no production code without a failing test first. Trigger phrases: "implement this", "add feature", "fix bug", "write a failing test", "TDD".'
---
# RLM TDD Discipline
## Overview
Test-Driven Development is mandatory for all RLM implementation work. This skill ensures test-first discipline is followed rigorously.
**Core Principle:** If you didn't watch the test fail, you don't know if it tests the right thing.
**The Iron Law for RLM:**
```
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
```
## Trigger examples
- `Implement Phase 3 for run '2026-02-24-add-oauth'`
- `Add a failing regression test first, then fix the bug`
- `I already wrote the code; now add tests` (should trigger TDD reset guidance)
- `Follow RED-GREEN-REFACTOR for this change`
## When to Use
**Always in Phase 3 (Implementation):**
- New features
- Bug fixes
- Refactoring
- Behavior changes
**No Exceptions:**
- Not for "simple" changes
- Not when "under pressure"
- Not because "tests after achieve same goals"
## RED-GREEN-REFACTOR Cycle
```dot
digraph tdd_cycle {
rankdir=LR;
red [label="RED\nWrite failing test", shape=box, style=filled, fillcolor="#ffcccc"];
verify_red [label="Verify fails\ncorrectly", shape=diamond];
green [label="GREEN\nMinimal code", shape=box, style=filled, fillcolor="#ccffcc"];
verify_green [label="Verify passes\nAll green", shape=diamond];
refactor [label="REFACTOR\nClean up", shape=box, style=filled, fillcolor="#ccccff"];
record [label="Record in\nPhase 3 artifact", shape=box];
red -> verify_red;
verify_red -> green [label="yes"];
verify_red -> red [label="wrong\nfailure"];
green -> verify_green;
verify_green -> refactor [label="yes"];
verify_green -> green [label="no"];
refactor -> verify_green [label="stay\ngreen"];
verify_green -> record;
}
```
### RED - Write Failing Test
Write one minimal test showing what should happen.
**Requirements:**
- One behavior per test
- Clear, descriptive name
- Test real code (no mocks unless unavoidable)
- Clear assertion showing expected outcome
```typescript
test('rejects empty email with clear error message', async () => {
const result = await submitForm({ email: '' });
expect(result.error).toBe('Email is required');
});
```
```typescript
test('email validation works', async () => {
const mock = jest.fn().mockResolvedValue({ valid: true });
const result = await validateEmail(mock);
expect(mock).toHaveBeenCalled();
});
```
### 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)
**Record in Phase 3 artifact:**
```markdown
### TDD Cycle for R3 (Email Validation)
**RED Phase:**
- Test: `rejects empty email with clear error message`
- Command: `npm test src/forms/email.test.ts`
- Expected failure: "Email is required" not found
- Actual failure: [paste output]
- RED verified: ✅
```
### GREEN - Minimal Code
Write simplest code to pass the test.
**Rules:**
- Just enough to pass
- No additional features
- No "while I'm here" improvements
- No refactoring yet
```typescript
function submitForm(data: FormData) {
if (!data.email?.trim()) {
return { error: 'Email is required' };
}
// ... rest of form handling
}
```
```typescript
function submitForm(
data: FormData,
options?: {
strictMode?: boolean;
customValidators?: Validator[];
onValidationError?: (err: Error) => void;
}
) {
// YAGNI - over-engineered
}
```
**Record in Phase 3 artifact:**
```markdown
**GREEN Phase:**
- Implementation: Added null check for email field
- Command: `npm test src/forms/email.test.ts`
- Result: PASS
- GREEN verified: ✅
```
### REFACTOR - Clean Up
After green only:
- Remove duplication
- Improve names
- Extract helpers
- Keep tests green
**Never add behavior during refactor.**
**Record in Phase 3 artifact:**
```markdown
**REFACTOR Phase:**
- Extracted `validateRequired(field, name)` helper
- Renamed `submitForm` to `processFormSubmission` for clarity
- All tests still passing: ✅
```
## Common Rationalizations (STOP - You're Rationalizing)
| Excuse | Reality |
|--------|---------|
| "This is just a simple fix, no test needed" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after confirming the fix works" | Tests passing immediately prove nothing. You never saw it catch the bug. |
| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
| "I already manually tested it" | Ad-hoc ≠ systematic. No record, can't re-run, no regression protection. |
| "Deleting working code is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
| "TDD is dogmatic, I'm being pragmatic" | TDD IS pragmatic. Finds bugs before commit, enables refactoring. |
| "I'll keep the code as reference" | You'll adapt it. That's testing after. Delete means delete. |
| "Test hard = design unclear" | Listen to the test. Hard to test = hard to use. Simplify design. |
| "I need to explore first" | Fine. Throw away exploration, start TDD fresh. |
| "This is different because..." | It's not. The rules don't have exceptions. |
## Red Flags - STOP and Start Over
If you encounter any of these, DELETE CODE and restart with TDD:
- ❌ Code written before test
- ❌ Test passes immediately (not testing what you think)
- ❌ "I'll add tests later"
- ❌ "This is too simple to test"
- ❌ "I know what I'm doing, I don't need the ritual"
- ❌ Can't explain why test failed (or didn't fail)
- ❌ Test testing mock behavior, not real behavior
- ❌ Multiple behaviors in one test ("and" in test name)
## Integration with RLM Phase 3
### Phase 3 Artifact TDD Section
Every Phase 3 artifact must include:
```markdown
## TDD Compliance Log
### Requirement R1 (Feature X)
**Test:** `test/features/x.test.ts` - "should do Y when Z"
- RED: [timestamp] - Failed as expected: [output]
- GREEN: [timestamp] - Minimal implementation: [description]
- REFACTOR: [timestamp] - Cleanups: [description]
- Final state: ✅ All tests passing
### Requirement R2 (Bug Fix)
**Regression Test:** `test/bugs/issue-123.test.ts` - "reproduces crash on empty input"
- RED: [timestamp] - Confirmed bug: [output]
- GREEN: [timestamp] - Fix applied: [description]
- REFACTOR: [timestamp] - N/A (minimal fix)
- Final state: ✅ Test passes, bug fixed
```
### Phase 3 Coverage Gate Addition
```markdown
## Coverage Gate
- [ ] Every new function has a corresponding test
- [ ] Every bug fix has a regression test that fails before fix
- [ ] All RED phases documented with failure output
- [ ] All GREEN phases documented with minimal implementation
- [ ] All tests passing (no skipped tests)
- [ ] No production code written before failing test
TDD Compliance: PASS / FAIL
```
### Phase 3 Approval Gate Addition
```markdown
## Approval Gate
- [ ] TDD Compliance: PASS
- [ ] Implementation matches Phase 3 plan
- [ ] No code without preceding failing test
- [ ] All tests documented in TDD Compliance Log
Approval: PASS / FAIL
```
## Bug Fix TDD Procedure
1. **Add Regression Test First**
- Write test that reproduces the bug
- Run test, confirm it fails with expected error
- Document failure in Phase 3 artifact
2. **Implement Minimal Fix**
- Fix only what's needed to make test pass
- Run test, confirm it passes
- Document fix in Phase 3 artifact
3. **Verify No Regressions**
- Run full test suite
- Confirm nothing else broke
- Document in Phase 3 artifact
4. **Lock Phase 3**
- TDD Compliance: PASS
- Approval: PASS
- Status: LOCKED
## Example: Complete Phase 3 TDD Section
```markdown
## TDD Compliance Log
### R1: Add email validation
**Test:** `test/forms/validation.test.ts`
RED Phase (2026-02-21T10:15:00Z):
```bash
$ npm test test/forms/validation.test.ts
FAIL: Expected 'Email is required', got undefined
```
RED verified: ✅
GREEN Phase (2026-02-21T10:18:00Z):
- Added null check in `submitForm()` function
- Test passes
GREEN verified: ✅
REFACTOR Phase (2026-02-21T10:22:00Z):
- Extracted `validateRequired()` helper
- All tests still passing
REFACTOR complete: ✅
### R2: Fix crash on empty array
**Regression Test:** `test/utils/array.test.ts`
RED Phase (2026-02-21T10:25:00Z):
```bash
$ npm test test/utils/array.test.ts
FAIL: TypeError: Cannot read property 'map' of undefined
```
RED verified: Bug reproduced ✅
GREEN Phase (2026-02-21T10:27:00Z):
- Added guard clause in `processItems()`
- Test passes
GREEN verified: ✅
REFACTOR: N/A (minimal 2-line fix)
## Verification
Full suite run: `npm test`
Result: 47 passing, 0 failing
```
## References
- **REQUIRED:** Follow this skill for all Phase 3 implementation work
- **SEE ALSO:** `references/rationalizations.md` for extended excuse/reality table