tdd-constraints
Red-green-domain TDD cycle with strict phase boundaries and domain modeling review
What this skill does
# TDD Constraints
**Version:** 1.0.0
**Portability:** Universal
---
## Detected Project Environment
!`if [ -f Cargo.toml ]; then echo "Language: Rust | Test runner: cargo test"; elif [ -f package.json ]; then if grep -q vitest package.json 2>/dev/null; then echo "Language: TypeScript/JavaScript | Test runner: npx vitest"; elif grep -q jest package.json 2>/dev/null; then echo "Language: TypeScript/JavaScript | Test runner: npx jest"; else echo "Language: TypeScript/JavaScript | Test runner: npm test"; fi; elif [ -f pyproject.toml ] || [ -f setup.py ]; then echo "Language: Python | Test runner: pytest"; elif [ -f go.mod ]; then echo "Language: Go | Test runner: go test ./..."; elif [ -f mix.exs ]; then echo "Language: Elixir | Test runner: mix test"; else echo "Language: unknown | Test runner: unknown (configure manually)"; fi`
## Objective
Defines a disciplined TDD workflow with three distinct phases (Red, Green, Domain) and strict boundaries between them. Enforces domain modeling review at natural checkpoints to prevent primitive obsession and invalid state representation.
**Purpose:** Ensure tests drive design, maintain clear separation of concerns, and build domain-rich implementations from the start.
**Scope:**
- **Included:** RED/GREEN/DOMAIN phases, file ownership patterns, phase transitions, domain modeling principles, rationalization red flags
- **Excluded:** Specific test frameworks, language-specific syntax, tool-specific workflows
---
## Core Principles
### Principle 1: Three-Phase Cycle (Red → Domain → Green → Domain)
**The Cycle:** Every feature is built through alternating phases with domain review at natural checkpoints.
**Why this matters:** Traditional TDD (red → green → refactor) often skips domain modeling, leading to primitive obsession and anemic models. Adding domain review phases catches these issues early.
**The Four Steps:**
1. **RED:** Write one failing test
2. **DOMAIN (after red):** Review test, create type definitions
3. **GREEN:** Implement minimal code to pass test
4. **DOMAIN (after green):** Review implementation for domain violations
**How to apply:**
- Complete each phase fully before moving to the next
- Don't skip domain reviews ("we'll model it later")
- Each phase has a single, focused responsibility
- Repeat cycle for each acceptance criterion
**Example Cycle:**
```
RED: Write test for User.authenticate(email, password)
↓
DOMAIN: Review test, create Email type (not String), Password type, AuthError enum
↓
GREEN: Implement User.authenticate() using domain types
↓
DOMAIN: Review implementation, check for primitive obsession
↓
CYCLE COMPLETE (move to next test)
```
### Principle 2: Strict Phase Boundaries (File Ownership)
**The Principle:** Each phase can only edit specific file types. This creates mechanical enforcement of separation of concerns.
**Why this matters:** Without boundaries, developers drift into "test and implement simultaneously" which defeats TDD's design benefits. Mechanical boundaries prevent drift.
**Phase Ownership:**
**RED Phase - Test Files Only**
- CAN edit: Test files (`*_test.*`, `*.test.*`, `tests/`, `spec/`)
- CANNOT edit: Production code, type definitions, configuration
**DOMAIN Phase - Type Definitions Only**
- CAN edit: Type definitions (structs, enums, interfaces, traits)
- CAN create: Stubs with `unimplemented!()`, `todo!()`, `raise NotImplementedError`
- CANNOT edit: Test logic, implementation bodies
**GREEN Phase - Implementation Bodies Only**
- CAN edit: Function/method implementations, filling in stubs
- CANNOT edit: Test files, type definitions (signatures)
**How to apply:**
- Enforce mechanically (hooks, pre-commit checks, linters)
- If blocked by boundary, STOP and return to workflow coordinator
- Never circumvent boundaries ("just this once")
**Example:**
```rust
// RED phase writes test (test file only)
#[test]
fn user_can_authenticate_with_valid_credentials() {
let user = User::new(Email::from("[email protected]"), Password::from("secret"));
let result = user.authenticate("secret");
assert!(result.is_ok());
}
// DOMAIN phase creates types (type definition files only)
struct User { email: Email, password_hash: PasswordHash }
struct Email(String); // Newtype
struct Password(String); // Newtype
enum AuthError { InvalidPassword, UserNotFound }
impl User {
fn new(email: Email, password: Password) -> Self {
unimplemented!("GREEN phase will implement")
}
fn authenticate(&self, password: &str) -> Result<(), AuthError> {
unimplemented!("GREEN phase will implement")
}
}
// GREEN phase implements bodies (implementation only)
impl User {
fn new(email: Email, password: Password) -> Self {
User {
email,
password_hash: PasswordHash::from(password)
}
}
fn authenticate(&self, password: &str) -> Result<(), AuthError> {
if self.password_hash.verify(password) {
Ok(())
} else {
Err(AuthError::InvalidPassword)
}
}
}
// DOMAIN phase reviews: ✓ No primitive obsession, types are meaningful
```
### Principle 3: One Assertion Per Test (Red Phase Constraint)
**The Principle:** Each test verifies exactly one behavior with one assertion.
**Why this matters:** Multiple assertions hide which expectation failed. When a test with 5 assertions fails, you don't know which of the 5 expectations is wrong without investigating.
**How to apply:**
- Write one test with one `assert`
- If you need multiple verifications, write multiple tests
- If setup is complex, extract helper functions
**Example:**
```python
# ❌ Bad: Multiple assertions (which one fails?)
def test_user_registration():
user = register_user("alice", "[email protected]", "password123")
assert user.name == "alice"
assert user.email == "[email protected]"
assert user.password is not None
assert user.is_active == True
assert user.created_at is not None
# ✓ Good: One assertion per test (failure is obvious)
def test_user_registration_sets_name():
user = register_user("alice", "[email protected]", "password123")
assert user.name == "alice"
def test_user_registration_sets_email():
user = register_user("alice", "[email protected]", "password123")
assert user.email == "[email protected]"
def test_user_registration_hashes_password():
user = register_user("alice", "[email protected]", "password123")
assert user.password_hash is not None
def test_user_registration_activates_by_default():
user = register_user("alice", "[email protected]", "password123")
assert user.is_active == True
```
### Principle 4: Minimal Implementation (Green Phase Constraint)
**The Principle:** Write the simplest code that makes the test pass. No more, no less.
**Why this matters:** Over-engineering during green phase adds complexity that isn't tested. YAGNI (You Aren't Gonna Need It) prevents speculative complexity.
**How to apply:**
- Read the failing test
- Write just enough code to make it pass
- Don't add features "while you're here"
- Don't add error handling not required by tests
- Don't add flexibility for future use cases
**Example:**
```typescript
// Test (RED phase)
test('user can register with email', () => {
const user = registerUser('[email protected]');
expect(user.email).toBe('[email protected]');
});
// ❌ Bad: Over-engineered (not tested)
function registerUser(email: string, options?: {
role?: 'admin' | 'user',
metadata?: Record<string, any>,
sendWelcomeEmail?: boolean
}): User {
const user = new User(email);
user.role = options?.role ?? 'user';
user.metadata = options?.metadata ?? {};
if (options?.sendWelcomeEmail !== false) {
sendEmail(user.email, 'Welcome!');
}
return user;
}
// ✓ Good: Minimal (exactly what test requires)
function registerUser(email: string): User {
return new User(email);
}
```
### Principle 5: Domain Modeling Review at Checkpoints
**The Principle:** After REDRelated in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.