flow-tdd
Enforces strict TDD discipline within the flow-dev workflow. It mandates writing failing tests before any production code, provides clear protocols for the TDD cycle, and integrates error logging with attention refresh protocols to prevent regression. The skill includes rationalization prevention tables and concrete examples.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install dimon94-cc-devflow-flow-tdd
Repository
Skill path: .claude/skills/flow-tdd
Enforces strict TDD discipline within the flow-dev workflow. It mandates writing failing tests before any production code, provides clear protocols for the TDD cycle, and integrates error logging with attention refresh protocols to prevent regression. The skill includes rationalization prevention tables and concrete examples.
Open repositoryBest for
Primary workflow: Write Technical Docs.
Technical facets: Testing, Full Stack, Tech Writer.
Target audience: Development teams and individual engineers committed to adopting or strictly maintaining Test-Driven Development practices, especially those struggling with discipline around writing tests first..
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: Dimon94.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install flow-tdd into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/Dimon94/cc-devflow before adding flow-tdd to shared team environments
- Use flow-tdd for testing workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: flow-tdd
description: "Enforces TDD Iron Law in flow-dev. NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST."
---
# Flow TDD - Test-Driven Development Enforcement
## The Iron Law
```
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
```
This is NON-NEGOTIABLE. No exceptions. No "just this once."
## The TDD Cycle
```
RED: Write a failing test
→ Run it
→ Confirm it FAILS
→ If it passes immediately → ERROR (invalid test)
GREEN: Write minimal code to pass
→ Only enough to make the test pass
→ No extra features
→ No "while I'm here" additions
REFACTOR: Clean up
→ Keep tests green
→ Improve structure
→ Remove duplication
```
## Enforcement in flow-dev
### Phase 2: Tests First
```yaml
TASKS.md Phase 2 (Tests):
- Write contract tests
- Write integration tests
- Write unit tests
- Run all tests → ALL MUST FAIL
⚠️ TEST VERIFICATION CHECKPOINT:
→ Run: npm test (or equivalent)
→ Expected: All new tests FAIL
→ If any test passes immediately → STOP
→ Passing test = invalid test or code already exists
```
### Phase 3: Implementation
```yaml
TASKS.md Phase 3 (Implementation):
- Implement to make tests pass
- One test at a time
- Minimal code only
After each implementation:
→ Run tests
→ Verify previously failing test now passes
→ Verify no regressions
```
## What If Code Already Exists?
If you've written code before tests:
```yaml
Option A: DELETE AND RESTART (Recommended)
1. Delete the implementation code
2. Keep only the interface/contract
3. Write failing tests
4. Re-implement with TDD
Option B: WRITE TESTS THAT FAIL FIRST
1. Comment out the implementation
2. Write tests
3. Run tests → verify they fail
4. Uncomment implementation
5. Run tests → verify they pass
NEVER: Keep code and write passing tests
→ This is "testing after" disguised as TDD
→ Tests that pass immediately prove nothing
```
## Rationalization Prevention
| Excuse | Reality |
|--------|---------|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
| "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. |
| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
| "TDD slows me down" | TDD faster than debugging. Pragmatic = test-first. |
| "This is different because..." | No. This is rationalization. Follow the law. |
| "Spirit not letter" | Violating letter IS violating spirit. No loopholes. |
| "I'm being pragmatic, not dogmatic" | TDD IS pragmatic. Shortcuts = debugging in production = slower. |
| "Just this once" | No exceptions. Rules exist for this exact moment. |
## Red Flags - STOP
If you find yourself:
- Writing code before tests
- Tests passing immediately
- Saying "just this once"
- Keeping "exploration" code
- Writing tests that describe existing code
**STOP. Delete the code. Write the test first.**
## Test Quality Requirements
```yaml
Good Tests:
✅ Test behavior, not implementation
✅ Use realistic data
✅ Cover edge cases
✅ Independent (no shared state)
✅ Fast (< 1 second each)
✅ Descriptive names
Bad Tests (Cheater Tests):
❌ assert True
❌ assert result is not None
❌ Mock everything, test nothing
❌ Test implementation details
❌ Depend on execution order
```
## Error Recording Protocol
当测试失败或构建错误发生时,必须立即记录到 ERROR_LOG.md:
```yaml
Error Recording Workflow:
1. Capture Error Context:
- Phase (flow-dev / T###)
- Error Type (Test Failure | Build Error | Runtime Error)
- Full error message
- Timestamp
2. Create ERROR_LOG.md if not exists:
→ Use .claude/docs/templates/ERROR_LOG_TEMPLATE.md
→ Location: devflow/requirements/${REQ_ID}/ERROR_LOG.md
3. Append Error Record:
## [TIMESTAMP] E###: TITLE
**Phase**: flow-dev / T###
**Error Type**: Test Failure
**Error Message**:
```
[完整错误信息]
```
**Root Cause**: [分析后填写]
**Resolution**: [解决后填写]
**Prevention**: [可选]
4. Debug with Error Context:
→ Read ERROR_LOG.md for similar past errors
→ Apply attention refresh (Protocol 4)
→ Fix the root cause, not symptoms
5. Update Record After Fix:
→ Fill Root Cause
→ Fill Resolution
→ Add Prevention if applicable
```
### Error Recording Example
```markdown
## [2026-01-08T14:30:00] E001: Test Failure - User Login Validation
**Phase**: flow-dev / T005
**Error Type**: Test Failure
**Error Message**:
\`\`\`
FAIL src/auth/login.test.ts
× should reject invalid email format
Expected: false
Received: true
\`\`\`
**Root Cause**: 正则表达式 `/^.+@.+$/` 过于宽松,接受了 `user@` 这样的无效邮箱
**Resolution**: 更新正则为 `/^[^\s@]+@[^\s@]+\.[^\s@]+$/` 要求至少有域名和顶级域
**Prevention**: 扩充测试用例,添加边界情况(无域名、无顶级域、特殊字符等)
```
## Integration with Constitution
- **Article I**: Complete implementation includes tests
- **Article VI**: TDD Mandate (this skill)
- **Article IX**: Integration-first testing
## Integration with Attention Refresh
- **Protocol 4**: Error Recovery 时读取 ERROR_LOG.md
- 避免重复犯相同错误
- 从历史错误中学习
## Cross-Reference
- [flow-attention-refresh](../flow-attention-refresh/SKILL.md) - Protocol 4
- [ERROR_LOG_TEMPLATE.md](../../docs/templates/ERROR_LOG_TEMPLATE.md)
- [rationalization-library.md](../../rules/rationalization-library.md#article-vi-test-first-development---rationalization-table)
- [project-constitution.md](../../rules/project-constitution.md#article-vi-test-first-development-测试优先开发)
---
**[PROTOCOL]**: 变更时更新此头部,然后检查 CLAUDE.md
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### ../flow-attention-refresh/SKILL.md
```markdown
---
name: flow-attention-refresh
description: "注意力刷新协议。在关键时刻强制读取核心文档,防止目标遗忘。被 flow-dev, flow-ralph 等命令引用。"
---
# Flow Attention Refresh - 注意力刷新协议
## Overview
解决 "Lost in the Middle" 效应:当上下文过长时,原始目标被"推出"注意力窗口。
```
问题:
上下文开始: [原始目标 - 距离很远,被"遗忘"]
↓
... 50+ 工具调用 ...
↓
上下文末尾: [最近的工具输出 - 在注意力窗口]
解决:
在关键时刻强制读取目标文档 → 将目标"拉回"注意力窗口
```
## The Iron Law
```
BEFORE MAJOR DECISION → READ GOAL FILES → THEN ACT
```
## Refresh Protocols
### Protocol 1: Flow Entry (每个 flow-* 命令开始)
**触发点**: 任何 `/flow-*` 命令的 Entry Gate
**动作**:
```yaml
read:
- BRAINSTORM.md "成功标准" 章节
- TASKS.md 当前阶段任务列表
focus: 本次命令要达成什么?
```
**实现**: 已由现有 Brainstorm Alignment Check 覆盖
---
### Protocol 2: Task Start (flow-dev 每个任务开始)
**触发点**: `flow-dev` TDD 循环中,每个任务执行前
**动作**:
```yaml
read:
- TASKS.md 当前任务 T### 段落 + DoD
- quickstart.md 相关命令
focus: 这个任务的验收标准是什么?
```
**实现位置**: flow-dev.md 阶段 3 TDD 循环
**代码片段**:
```markdown
**注意力刷新** (Protocol 2):
→ Read: TASKS.md 当前任务 T### 段落
→ Focus: 任务目标和 DoD
→ Then: 开始执行任务
```
---
### Protocol 3: Ralph Iteration (Ralph 循环每次迭代)
**触发点**: `/flow-ralph` 每次迭代开始
**动作**:
```yaml
read:
- TASKS.md 第一个未完成任务
- ERROR_LOG.md 最近 5 条记录
focus: 下一步行动 + 避免重复错误
```
**实现位置**: flow-ralph.md Ralph Loop 开始处
**代码片段**:
```markdown
**注意力刷新** (Protocol 3):
→ Read: TASKS.md 找到第一个 `- [ ]` 任务
→ Read: ERROR_LOG.md 最近 5 条(如存在)
→ Focus: 下一步行动是什么?有什么错误需要避免?
→ Then: 执行任务
```
---
### Protocol 4: Error Recovery (遇到错误后)
**触发点**: 测试失败、构建错误、运行时异常后
**动作**:
```yaml
read:
- ERROR_LOG.md 当前错误记录
- TASKS.md 当前任务定义
focus: 错误根因 + 解决方案
```
**实现位置**: flow-tdd skill 错误处理部分
**代码片段**:
```markdown
**错误恢复刷新** (Protocol 4):
→ Record: 将错误追加到 ERROR_LOG.md
→ Read: ERROR_LOG.md 当前错误 + 历史相似错误
→ Read: TASKS.md 当前任务
→ Focus: 根因分析,避免盲目修复
→ Then: 有针对性地修复
```
---
## Integration Map
```
现有机制:
┌──────────────────────────────────────┐
│ flow-brainstorming skill │
│ ↓ 触发于 /flow-init │
│ ↓ 输出 BRAINSTORM.md │
└──────────────────────────────────────┘
↓
┌──────────────────────────────────────┐
│ Brainstorm Alignment Check │
│ ↓ 在每个 flow-* Entry Gate │
│ ↓ 读取 BRAINSTORM.md 验证对齐 │
│ ↓ = Protocol 1 │
└──────────────────────────────────────┘
新增机制:
┌──────────────────────────────────────┐
│ flow-attention-refresh skill (本文件) │
│ ↓ 被 flow-dev, flow-ralph 引用 │
│ ↓ 在更细粒度的时刻刷新注意力 │
│ ↓ Protocol 2, 3, 4 │
└──────────────────────────────────────┘
```
## Rationalization Prevention
| Excuse | Reality |
|--------|---------|
| "我记得目标是什么" | 上下文 50+ 工具调用后,你真的不记得了 |
| "读文件浪费时间" | 读文件 < 1秒,返工 > 10分钟 |
| "这个任务很简单" | 简单任务也会偏离目标 |
| "刚刚读过了" | 每次迭代都要读,这是协议 |
## Red Flags - STOP
如果你发现自己:
- 开始任务前没有读取 TASKS.md
- 遇到错误后没有先记录 ERROR_LOG.md
- Ralph 循环中忘记读取上次错误
- 做决策时没有参考 BRAINSTORM.md
**STOP。执行对应的 Protocol。**
---
**[PROTOCOL]**: 变更时更新此头部,然后检查 CLAUDE.md
```
### ../../docs/templates/ERROR_LOG_TEMPLATE.md
```markdown
# Error Log: ${REQ_ID}
> 本文件记录需求开发过程中遇到的所有错误及解决方案。
> **[PROTOCOL]**: 遇到错误时立即追加,不要等到最后。
---
## 错误记录格式
每条错误记录遵循以下结构:
```markdown
## [TIMESTAMP] E###: TITLE
**Phase**: flow-dev / T### 或 flow-qa / 测试名
**Error Type**: Test Failure | Build Error | Runtime Error | Type Error | Lint Error
**Error Message**:
\`\`\`
完整错误信息
\`\`\`
**Root Cause**: 根因分析(解决后填写)
**Resolution**: 解决方案(解决后填写)
**Prevention**: 预防措施(可选,防止再犯)
```
---
## 示例记录
## [2026-01-08T10:30:00] E001: Test Failure - Email Validation
**Phase**: flow-dev / T003
**Error Type**: Test Failure
**Error Message**:
```
FAIL src/auth/login.test.ts
× should validate email format
Expected: true
Received: false
at Object.<anonymous> (src/auth/login.test.ts:25:20)
```
**Root Cause**: 正则表达式未处理 + 号邮箱(如 [email protected])
**Resolution**: 更新正则为 `/^[^\s@]+@[^\s@]+\.[^\s@]+$/`
**Prevention**: 添加 + 号邮箱到测试用例,扩充边界测试
---
## [2026-01-08T11:15:00] E002: Build Error - Missing Import
**Phase**: flow-dev / T005
**Error Type**: Build Error
**Error Message**:
```
ERROR in src/components/UserProfile.tsx
Module not found: Can't resolve '@/utils/formatDate'
```
**Root Cause**: formatDate 函数移动到 @/utils/date 但未更新 import
**Resolution**: 更新 import 路径为 `@/utils/date`
**Prevention**: 使用 IDE 重构功能移动文件,自动更新引用
---
## 统计信息
| 指标 | 值 |
|------|-----|
| 总错误数 | 0 |
| 已解决 | 0 |
| 待解决 | 0 |
| 最常见类型 | - |
> 注:此统计在开发结束时手动更新
---
**[PROTOCOL]**: 变更时更新此头部,然后检查 CLAUDE.md
```