Skip to content
Development
Skill

/ijfw-tdd

RED-GREEN-REFACTOR enforcement. Use when implementing a feature or bugfix before writing implementation code. Trigger: tdd, test first, red green refactor, /ijfw-tdd

From plugin
ijfw
20591 skills37 agents22 commands1 MCP
Install
$ npx -y skills add FerroxLabs/ijfw --skill ijfw-tdd --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/ijfw-tdd

Context preview

The summary Claude sees to decide when to auto-load this skill.

RED-GREEN-REFACTOR enforcement. Use when implementing a feature or bugfix before writing implementation code. Trigger: tdd, test first, red green refactor, /ijfw-tdd

SKILL.md

ijfw-tdd.SKILL.md
name: ijfw-tdd
description: "RED-GREEN-REFACTOR enforcement. Use when implementing a feature or bugfix before writing implementation code. Trigger: tdd, test first, red green refactor, /ijfw-tdd"
since: "1.5.0"

IJFW TDD -- RED-GREEN-REFACTOR

Write the test first. Watch it fail for the right reason. Write the minimum code to make it pass. Then improve structure without changing behavior.

**Iron law:** No production code without a failing test first. If you wrote code before the test, delete it. Implement fresh from the test.

This skill enforces three distinct moves. Each move has a green light that you must hit before advancing. Skipping a green light is not "pragmatic" -- it is the bug.

---

Move 1: RED -- write a test that fails for the RIGHT reason

Write ONE minimal test for ONE behavior. Use a descriptive name. Use real code (no mocks unless unavoidable).

Before running the test, write down the failure message you EXPECT to see. Example: "AssertionError: expected 'Email required', got undefined" or "AttributeError: module has no attribute 'retryOperation'".

Then run it:

npm test path/to/test.ts   # or pytest, cargo test, go test, etc.

Paste the actual failure into your scratch. Compare against what you predicted.

**Green light to advance:** the test FAILS, and the failure message is the one you predicted (an assertion failure on the intended behavior, or a "missing symbol" error if the function does not exist yet).

**Red flags that block advancing:**

  • Test passes immediately -- you are testing existing behavior. Rewrite.
  • Test errors on a typo, import, or syntax issue -- fix and re-run until it fails meaningfully.
  • Failure message surprises you -- you do not yet understand what you are building. Stop and think before writing implementation.

---

Move 2: GREEN -- write the minimum code to pass

Write the simplest implementation that turns the failing test green. No extra parameters. No "while I am here" cleanup. No anticipating tomorrow's tests. YAGNI.

Run the test. Paste the pass output. Run the full suite -- nothing else may regress.

**Green light to advance:** target test passes, full suite passes, output is pristine (no warnings, no stack-trace noise, no skipped tests you forgot about).

**Red flags that block advancing:**

  • You added a feature the test does not cover -- delete it.
  • Other tests broke -- fix now, do not defer.
  • You changed the test to make it pass -- revert. The test defines the contract; the code is what bends.

---

Move 3: REFACTOR -- improve structure WITHOUT changing behavior

Now and only now: rename, extract helpers, remove duplication, tighten types, collapse branches. The behavior must stay identical.

Run the FULL test suite after each meaningful change. Not at the end -- after each change. If you cannot remember which change broke green, you waited too long.

**Green light to advance to the next test:** every refactor kept the suite green. No new behavior was added under the cover of "cleanup."

**Red flag:** you find yourself wanting to add a feature mid-refactor. Stop. Commit the refactor. Start a new RED test for the new feature.

---

Anti-patterns (and WHY each is wrong)

1. **Testing the mock, not the code.** Asserting `screen.getByTestId('sidebar-mock')` proves the mock loaded, not that the component works. The test passes for the wrong reason and gives false confidence. 2. **Tautological assertion.** `expect(result).toBe(result)` or `expect(fn()).toEqual(fn())`. Always green, proves nothing, exists only to push coverage numbers. 3. **Coverage-driven test that asserts nothing.** Calls the function, never checks the return value. The line counter goes up; the bug count does too. 4. **Skipping RED because "I know what it will fail on."** You don't. Half the time the test passes immediately (you tested the wrong thing) or errors on a typo (you tested nothing). Watching it fail is the only proof the test can ever fail. 5. **Test-only methods on production classes.** A `destroy()` that exists "for tests" is production API that real callers will eventually invoke. Put cleanup helpers in test utilities. 6. **Incomplete mocks.** Mocking only the fields your test reads hides the structural contract. Downstream code that consumes other fields fails silently. Mirror the real shape completely or do not mock at all.

---

Multi-domain examples

TDD is not a software-only discipline. It applies anywhere you have a falsifiable claim about what "done" means.

  • **Book continuity** -- writing chapter 7? Before drafting, write the continuity check: "By end of ch7, Maya knows about the letter AND has not yet met Olu." Draft until the check holds. Re-run the check after every revision.
  • **Campaign metrics** -- launching a landing page? Before shipping, define the test: "Launch worked = 100 signups in 7 days AND CAC < $12 AND bounce < 60%." Anything else is "I think it went OK," which is a manual ad-hoc test.
  • **Design-system contrast** -- before picking a palette, write the test: "Every text/background pair scores WCAG AA (4.5:1) or better, verified by axe-core." Palette choices that fail the test never enter the system.
  • **Onboarding copy** -- before writing the welcome email, write the test: "A reader who has never used the product can name the first action to take in under 10 seconds." Read the draft to a non-user and time them.

In every domain, the move is the same: write the falsifiable claim FIRST, watch reality fail to meet it, then build until the check holds.

---

When stuck

| Problem | Move | |---------|------| | Don't know how to test it | Write the wished-for API. Write the assertion. Ask for help. | | Test feels too complicated | The design is too complicated. Simplify the interface. | | Must mock everything | Code is too coupled. Use dependency injection. | | Test setup is huge | Extract helpers. Still huge? The design is wrong. |

Final rule

Production artifact exists -- a function, a

Read more
Ships withijfw

IJFW — It Just F*cking Works. Ferrox Labs' local-first infrastructure for AI coding agents: shared memory, smart routing, multi-AI cross-audits, disciplined workflow.

Get the whole plugin