(ywc) Use when implementing a new feature, bug fix, or behavior change before production code is written; enforce RED → GREEN → REFACTOR and a real failing-test step. Triggers: "TDD", "test first", "테스트 먼저", "regression test", "テスト先行", "ywc-tdd-ritual", "ywc-code-gen --tdd". Do not use for opted-out throwaway prototypes, existing test-failure debugging (use ywc-debug-rootcause), generated/config files, or completion verification (use ywc-verify-done).
Scanned 9/2/2026
Install to Claude Code
npx -y skills add yongwoon/ywc-agent-toolkit --skill ywc-tdd-ritual --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ywc Tdd Ritual?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/yongwoon-ywc-tdd-ritual-758a0bb6)More formats (shields.io, HTML) on the badges page.
---
name: ywc-tdd-ritual
description: >-
(ywc) Use when implementing a new feature, bug fix, or behavior change
before production code is written; enforce RED → GREEN → REFACTOR and a real
failing-test step. Triggers: "TDD", "test first", "테스트 먼저",
"regression test", "テスト先行", "ywc-tdd-ritual", "ywc-code-gen --tdd".
Do not use for opted-out throwaway prototypes, existing test-failure
debugging (use ywc-debug-rootcause), generated/config files, or completion
verification (use ywc-verify-done).
---
# ywc-tdd-ritual
**Announce at start:** "I'm using the ywc-tdd-ritual skill to enforce RED → GREEN → REFACTOR with a watch-it-fail gate before any production code."
This skill is the canonical writing-time discipline for ywc. It exists because every implementation skill (`ywc-code-gen`, `ywc-sequential-executor`, `ywc-parallel-executor`) can run with or without TDD, and the cost of running without is borne later by `ywc-debug-rootcause`, `ywc-impl-review`, and CI — typically 3–10× the cost of writing the test first. Adapted from `superpowers:test-driven-development`, tightened to delegate completion claims to `ywc-verify-done` and root-cause work to `ywc-debug-rootcause`.
## The Iron Law
```text
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
```
If production code was written before the test, delete it and start over from RED. "Adapt the existing code while writing the test" is the same as "writing the test after"; it produces a test biased by the implementation that does not actually catch defects.
## Rationalization Defense
When tempted to skip the cycle, check this table first:
| Excuse | Reality |
|---|---|
| "I'll write the test right after implementing — same result" | Tests written after the code pass immediately. A test that passes the first time it runs proves nothing — it might be testing the wrong thing, the wrong path, or the wrong assertion. You never saw it catch the bug, so it cannot be trusted to catch one later. Test-first forces the test to fail for the right reason first. |
| "Too simple to need a test" | "Simple" code is where unchecked assumptions land. The test takes 30 seconds; the bug found in production takes hours. There is no size threshold below which the gate stops applying. |
| "I already manually tested every edge case" | Manual testing is ad-hoc and leaves no artifact. The next change will re-introduce the bug because there is no automated guard. Manual coverage is not coverage. |
| "Deleting the X hours of implementation I already wrote is wasteful" | Sunk cost. The time is gone either way. The choice now is (a) delete and rewrite under TDD with high confidence, or (b) keep the unverified code and inherit a debugging debt that will cost more later. Keeping it is the more expensive option. |
| "I'll keep the code as reference while I write the test first" | "Reference" becomes "model to copy", which becomes "the test I built around the existing code" — i.e., a test-after with extra steps. Delete means delete. Implement fresh from the test. |
| "I need to explore the design first; TDD blocks exploration" | Exploration is fine. Treat the exploration as a spike — keep notes, then **throw away the spike code** before starting TDD. The TDD cycle begins from the test, not from the spike. |
| "The test setup is so big the cycle slows me down" | A test that needs a 200-line setup is signal that the design is wrong. Listen to the test: extract a seam, inject the collaborator, or simplify the interface. Hard-to-test code is hard-to-use code. |
| "I'll skip the 'watch it fail' step — I know it would fail" | The watch-it-fail step is not for the test, it is for **you**. It catches: (a) the test passing for an unrelated reason (e.g., the assertion is wrong), (b) typos that turn the test into a no-op, (c) the test exercising code that already exists. Without this step, the cycle silently degrades into test-after. |
| "I have 6 features to add — I'll TDD the hard one and skip the easy ones" | The easy ones are exactly where the bug hides, because attention is elsewhere. The discipline applies per feature, not per session. |
| "This is a refactor, no behavior change — tests not needed" | Refactor = same behavior, different structure. The existing test suite must pass before and after. If no test covers the surface being refactored, write the test first (RED on the *existing* behavior), then refactor under it. Refactoring without tests is rewriting. |
**Violating the letter of this discipline is violating the spirit.** The cycle is the only mechanism in the ywc workflow that catches design defects before they ship.
## The Red-Green-Refactor Cycle
```text
RED → Verify RED → GREEN → Verify GREEN → REFACTOR → Verify GREEN → Next
```
Each transition has a verification step that **must** be executed in the current message — no transition is silent.
### Step 1: RED — Write the failing test
Write one minimal test that captures **one** behavior the production code is required to exhibit.
**Requirements:**
- **One behavior per test.** If the test name contains "and", split it.
- **Clear, intention-revealing name.** "`rejects offset > total with 400`" beats "`pagination test 3`".
- **Real code paths.** Mocks are allowed only for boundaries the test cannot cross (network, clock, file system). Mocking the unit under test is forbidden — it tests the mock, not the code.
- **No production code yet.** If the test references a function that does not exist, that is fine — the import error counts as failure.
### Step 2: Verify RED — Watch it fail
```bash
# Run ONLY the new test, using the project's configured test runner:
# npm/pnpm/yarn → the "test" script in package.json, e.g. `npm test -- <path-or-name>`
# pytest → `pytest <path>::<test>` (from pyproject.toml / pytest.ini)
# go → `go test -run <TestName> ./<pkg>`
# If the runner cannot be inferred from the project config, ask the user before running.
```
Confirm three things from the output:
1. The test ran (not skipped, not errored before reaching assertions).
2. The failure reason matches what was expected (the assertion fired, not a typo or missing import).
3. No other test broke — if the test runner shows new failures elsewhere, the test is interacting with shared state and must be fixed before advancing.
**If the test passes the first time it runs**, the test is wrong:
- It is testing existing behavior — the feature is already implemented, or
- The assertion is trivially satisfied (e.g., `expect(x).toBeDefined()` where `x` is always defined), or
- The test is reading a cached / stale value.
Fix the test. Do not advance to GREEN with a passing-on-first-run test.
### Step 3: GREEN — Write the minimal code
Write the simplest production code that makes the failing test pass.
**Requirements:**
- **Minimal.** No options the test does not exercise. No abstractions the test does not require. YAGNI applies hard here.
- **No bundled refactor.** Adjacent code that "could be cleaner" is not touched in this step. Save it for REFACTOR.
- **No additional tests.** This step makes the existing test green; new tests belong to the next cycle.
### Step 4: Verify GREEN — Watch it pass
```bash
<run the new test>
<run the broader suite to confirm no regression>
```
Confirm:
1. The new test passes.
2. The full suite passes (no other test broke).
3. The output is pristine — no errors, no warnings, no deprecation notices that were not there before.
If the broader suite breaks, the GREEN code is too aggressive (touched a public surface other tests rely on) or too narrow (mutated shared state). Either revert or extend the suite — never silence a failing test to advance.
### Step 5: REFACTOR — Clean up under green
Now, and only now, improve the implementation:
- Remove duplication.
- Improve names.
- Extract helpers if the same logic appears in 2+ places.
- Tighten types or invariants.
**No new behavior** during refactor. The same tests must pass after each edit. If a refactor breaks a test, the refactor changed behavior — revert and split into a separate cycle.
### Step 6: Verify after REFACTOR
Re-run the suite after the refactor. If it stays green, the cycle is complete. If a test breaks, treat as Step 5 violation.
### Step 7: Loop or hand off
If there are more behaviors to implement, return to Step 1 with the next test.
When all required behaviors are implemented, hand off to `ywc-verify-done` for the completion claim (build + lint + full test suite + per-claim evidence block).
## Output Format
The cycle produces three commit shapes per behavior, in this order. (Skip the REFACTOR commit when no cleanup was needed.)
| Stage | Commit message shape | Verification at commit time |
|---|---|---|
| RED | `test: <one-line behavior>` (tests fail at this commit) | Test fails for the expected reason |
| GREEN | `feat: <one-line behavior>` or `fix: <bug>` | New test passes; broader suite passes |
| REFACTOR | `refactor: <what was tightened>` | All tests still pass |
Per-stage verification blocks follow `ywc-verify-done`'s shape (command → exit code → claim). The RED commit's verification block proves the test failed; the GREEN commit's proves it passes; the REFACTOR commit's proves nothing broke.
When delegated from `ywc-code-gen --tdd`, the executor emits these three commits per behavior automatically and threads the verification block into its per-step report.
## Integration
- **Upstream callers**: user invocation; `ywc-code-gen` with `--tdd` flag (Step 7.5 enforces the cycle per generated module); `ywc-debug-rootcause` Phase 4 §1 (regression test for the bug).
- **Downstream**: `ywc-verify-done` (every Verify step uses its evidence-block format and forbidden-vocabulary rules); `ywc-debug-rootcause` (if the RED step itself uncovers an unexpected pre-existing failure, that is a Phase 1 finding — route there).
- **Pairs with**: `ywc-confidence-gate` (pre-cycle ≥90 confidence reduces RED rewrite churn); `ywc-impl-review` (downstream code review uses the test as the spec evidence).
## Validation Checklist
Before declaring a behavior complete, verify:
- [ ] A test for the behavior exists in the repository
- [ ] The test was **observed failing** in the current session for the expected reason (RED commit's verification block in this session's history)
- [ ] The production code was written **after** the test failed
- [ ] No "kept as reference" code was retained from a pre-TDD draft
- [ ] The GREEN code is minimal — every line traces to a test-required behavior
- [ ] The broader suite passes (per `ywc-verify-done`)
- [ ] If refactoring was performed, all tests stayed green throughout
## Common Mistakes
(Procedural failure modes specific to TDD. Behavioral rationalizations are in the table above — do not duplicate here.)
- **Treating a compile / import error as "test failed".** A test that errors before reaching its assertions has not exercised the production code. Fix the test setup (stub the missing import, then re-run) so the failure is at the assertion, not the import.
- **Writing the test against the implementation you secretly already drafted in your head.** The test reads the desired *behavior*, not the algorithm you imagine. If the test mentions a private helper name before that helper exists in the codebase, you are testing the implementation, not the contract.
- **Bundling the GREEN edit with a "while I'm here" fix in adjacent code.** Adjacent fixes mean the GREEN commit is no longer minimal, and you cannot bisect cleanly if the next cycle breaks. Save adjacent fixes for their own RED-GREEN-REFACTOR.
- **Letting a refactor introduce a "harmless" behavior tweak.** "It was already broken anyway" is not license to fix it in the refactor commit. Either write a RED for the new behavior or revert the tweak.
- **Skipping `ywc-verify-done` at the end of the cycle because "the cycle already verified it".** The cycle verifies one behavior; `ywc-verify-done` verifies the **claim** (build green, lint green, suite green, claim wording free of forbidden vocabulary). Both are required for completion.
## References
| Reference | Use when |
|---|---|
| [references/red-green-checklist.md](references/red-green-checklist.md) | Walking through the per-step entry / exit conditions during the cycle |
| [references/test-shape-cookbook.md](references/test-shape-cookbook.md) | Picking the right shape of test for the behavior (state vs interaction, unit vs integration, snapshot vs assertion) |
| `ywc-verify-done` | Per-step verification block shape (command + exit code + claim) |
| `ywc-debug-rootcause` | When an existing test starts failing during a cycle, route the investigation here before another fix attempt |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!