This directory contains Claude Code commands that enforce Test-Driven Development workflows for the Brighter project.
Guides you through the Red-Green-Refactor TDD cycle with an approval gate before implementation that is armed by default.
Purpose: Ensures you write and approve tests before writing implementation code, preventing scope creep and promoting better design.
Usage:
/test-first when an invalid message is received it should be sent to the dead letter queueWorkflow:
-
🔴 RED Phase: Claude writes a failing test following Brighter's testing conventions
- Uses BDD-style naming:
When_[condition]_should_[expected_behavior] - One test per file
- Arrange/Act/Assert structure
- Tests public exports only
- Uses InMemory* implementations instead of mocks
- Uses BDD-style naming:
-
✅ APPROVAL GATE: Claude asks for your explicit approval
- You must approve the test before implementation begins
- You can request modifications to the test
- Implementation only proceeds after approval
- Armed by default — see The review gear below
-
🟢 GREEN Phase: Claude implements minimum code to pass the test
- Only writes what's needed for this specific test
- No speculative code
- Follows Brighter's code style and documentation standards
-
🔵 REFACTOR Phase: Claude suggests design improvements (optional)
- Structural changes only (no behavior changes)
- Tests remain green throughout
Why Use This?
From .agent_instructions/testing.md:
You cannot bypass the gate on your own initiative. It is disarmed only by a deliberate, recorded, scoped gear shift the user makes with
/spec:gear.
This command enforces that requirement automatically, ensuring:
- Tests correctly specify desired behavior before implementation
- Scope control - only code required by tests is written
- Better design - thinking about behavior first
- No speculative code
- Incremental progress through small, focused tests
The pause is a gear, not a policy (ADR 0071). You select it for the certainty you have and the blast radius you face: review every test while the design is still moving; review a batch once the shape has been approved several times over; shift back down the moment the work produces a test you would not have approved.
| Gear | Gate | Meaning |
|---|---|---|
review-before |
✅ armed | Approve each test before implementation. The default. |
review-after |
➖ not armed | RED still proved first; reviewed as a batch afterwards. |
/test-first itself is always gated. It does not read the gear file — a standalone invocation
must never inherit a mode it did not ask for from whichever spec happens to be current. The gear is
resolved by /spec:implement and /spec:ralph-implement, which pass the result into this workflow
explicitly. /bugfix:test is always gated too.
Shift the gear with /spec:gear. It writes specs/{spec}/.current-gear —
untracked working state, scoped to one spec and optionally one section of tasks.md, carrying the
reason for the shift.
review-after removes the human pause and nothing else. These hold in both gears:
- RED first — the test is observed failing for the right reason before any production code. Ungated is not test-after.
- The full regression suite, not just the new test's own
--filter. - The two-commit shape —
feat:/test:for the behaviour, then a separatedocs:for any task-list tick. - Every test-authoring convention — naming, one test per file, TestDoubles one class per file,
a distinct request type per new test double, new closed generics registered with the test
project's logging
Initializer.cs, no mocks for isolation,InMemory*for I/O.
Related Guidelines:
The /test-first command can be used standalone or as part of the specification workflow.
- Standalone: Use anytime you want to add behavior with TDD. Always gated.
- With /spec:implement: The spec implement command uses the same TDD workflow, in whichever gear the spec is currently in
- With /spec:ralph-implement: The same workflow again, run unattended in a loop over the same
tasks.md, alwaysreview-after
$ /test-first when a message fails to send it should retry with exponential backoff
🔴 RED: Writing test...
[Claude shows test code]
Test fails: ✓ "RetryWithExponentialBackoff method not found"
✅ Should I proceed to implement the code to make this test pass?
> Yes
🟢 GREEN: Implementing RetryWithExponentialBackoff...
[Claude shows implementation]
✓ Test passes
✓ All tests pass
🔵 REFACTOR: Extracting backoff calculation...
[Claude shows refactoring]
✓ All tests still pass
Suggested commit: feat: add exponential backoff retry logic
Should I commit these changes?- Start small: Write the simplest test that moves you toward your goal
- One behavior at a time: Use
/test-firstmultiple times to build up functionality - Review the test carefully: The test is your specification - make sure it's correct before approving
- Trust the process: Don't skip ahead to implementation. If the gate has stopped earning its
cost on a run of near-identical tasks, shift gear deliberately with
/spec:gear— don't quietly stop honouring it - Refactor regularly: Take advantage of the refactor phase to improve design while tests are green
/tidy-first- Separate structural (refactoring) changes from behavioural ones, following Beck's "Tidy First". Use it for refactoring beyond the small, in-cycle tidy of the REFACTOR phase above./refactor:smells- Optional review, once a unit of work is complete, for Fowler's code smells in the changed code; schedules the refactorings rather than making them.
Planned TDD commands:
/tdd:coverage- Check that the code added for a task is reachable from its tests through the public interface. Code written test-first should be covered by the tests that drove it; a line that can only be covered by a special-purpose test (a branch reachable only through an internal or private member rather than the public interface) is a sign of speculative code or a design problem, not a gap to plug with a test. It runs once the task is GREEN and after any/tidy-firstrefactoring, so it checks the code as it will be committed. The command would collect coverage (dotnet test --collect:"XPlat Code Coverage") for the task's diff and report uncovered added lines as findings to remove or redesign, rather than suggesting tests to cover them.