skills: implement branches off main and opens a PR; TDD tests come from a sub-agent
implement: sync main and cut task-<NNNN>-<slug> before work, with stop-and-ask guards for a dirty tree, a diverged main, and an unmerged blocker. Replaces the no-commit rule with one commit, a push, and a PR carrying the review's Risk block plus any unaddressed findings. test-driven-development: every test is written by a general-purpose sub-agent that never reads the implementation; the main agent writes the code and never edits a test.
This commit is contained in:
@@ -28,7 +28,9 @@ This produces **crap tests**:
|
||||
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
|
||||
- You outrun your headlights, committing to test structure before understanding the implementation
|
||||
|
||||
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
|
||||
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle.
|
||||
|
||||
The test-writer sub-agent (below) is handed **one behavior at a time** and never sees the behavior backlog, so it can't bulk-write the suite.
|
||||
|
||||
```
|
||||
WRONG (horizontal):
|
||||
@@ -42,6 +44,25 @@ RIGHT (vertical):
|
||||
...
|
||||
```
|
||||
|
||||
## Roles
|
||||
|
||||
Every test is written by a **test-writer sub-agent**. The main agent writes every line of implementation, and never writes or edits a test.
|
||||
|
||||
The sub-agent must not read the implementation source of the module under test — that is what keeps its tests from asserting _how_ instead of _what_. It works from the public interface alone.
|
||||
|
||||
Use one `general-purpose` sub-agent for the whole task: spawn it at the first RED, then continue it with `SendMessage` for each subsequent RED, so it keeps the test file and conventions it established. Cold-spawn a replacement only if its ID is lost.
|
||||
|
||||
### Test-writer sub-agent prompt — include:
|
||||
|
||||
- **One behavior**, quoted verbatim from the acceptance criterion or the agreed behavior list. Never the task file, never the rest of the list.
|
||||
- The **public interface** under test — signatures only.
|
||||
- The existing test file(s) for the module, and the project's test conventions (fixtures, helpers, runner invocation).
|
||||
- [tests.md](tests.md) and [mocking.md](mocking.md).
|
||||
- The **independent source of truth for the expected value** — the spec excerpt, worked example, or known-good literal. Without it the sub-agent recomputes the expected value the way the code would, and the test is tautological.
|
||||
- `.claude/CONTEXT.md` (if it exists) and any ADRs in the area, so test names and interface vocabulary match the project's domain language.
|
||||
- The test-side checklist from [Checklist Per Cycle](#checklist-per-cycle), pasted in full — the sub-agent has no other access to it.
|
||||
- The brief: "Write ONE test for this behavior. Do not read the implementation source of the module under test. Write it to the test file, run it, and confirm it fails with a genuine assertion failure — not an import, syntax, or collection error, which prove nothing. Report the test's name and the exact failure message you saw."
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Planning
|
||||
@@ -63,13 +84,15 @@ Ask: "What should the public interface look like? Which behaviors are most impor
|
||||
|
||||
**You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
|
||||
|
||||
Planning stays with the main agent on both paths — exploration, interface, and the order behaviors are tested in. The sub-agent receives behaviors one at a time; it never chooses what to test next.
|
||||
|
||||
### 2. Tracer Bullet
|
||||
|
||||
Write ONE test that confirms ONE thing about the system:
|
||||
ONE test that confirms ONE thing about the system:
|
||||
|
||||
```
|
||||
RED: Write test for first behavior → test fails
|
||||
GREEN: Write minimal code to pass → test passes
|
||||
RED: Spawn the test-writer sub-agent with the first behavior → it writes the test, runs it, reports a genuine failure
|
||||
GREEN: Main agent writes minimal code to pass → test passes
|
||||
```
|
||||
|
||||
This is your tracer bullet - proves the path works end-to-end.
|
||||
@@ -79,8 +102,8 @@ This is your tracer bullet - proves the path works end-to-end.
|
||||
For each remaining behavior:
|
||||
|
||||
```
|
||||
RED: Write next test → fails
|
||||
GREEN: Minimal code to pass → passes
|
||||
RED: SendMessage the same sub-agent the next behavior → it writes the test, runs it, reports a genuine failure
|
||||
GREEN: Main agent writes minimal code to pass → passes
|
||||
```
|
||||
|
||||
Rules:
|
||||
@@ -90,6 +113,13 @@ Rules:
|
||||
- Don't anticipate future tests
|
||||
- Keep tests focused on observable behavior
|
||||
|
||||
### When a test looks wrong
|
||||
|
||||
The main agent never edits a sub-agent-authored test — not to fix an import, not to "simplify" an assertion, not to reach GREEN.
|
||||
|
||||
- **Mechanical defect** — bad import path, a fixture or helper that doesn't exist, doesn't parse. Send the error output back to the sub-agent and let it fix its own test.
|
||||
- **Semantic disagreement** — you believe the expected value or the asserted behavior is wrong. Stop and ask the user. Do not resolve it yourself; this disagreement is the signal the sub-agent exists to surface, and half the time it's the code that's wrong.
|
||||
|
||||
### 4. Refactor
|
||||
|
||||
After all tests pass, look for [refactor candidates](refactoring.md):
|
||||
@@ -102,13 +132,22 @@ After all tests pass, look for [refactor candidates](refactoring.md):
|
||||
|
||||
**Never refactor while RED.** Get to GREEN first.
|
||||
|
||||
A test that breaks during refactor means the refactor broke behavior — fix the code. The one exception is a public interface change you made deliberately (a module deepened, a signature moved, as agreed in the plan): send the interface change to the sub-agent and let it update its own tests. There is no case where the main agent edits the test itself.
|
||||
|
||||
## Checklist Per Cycle
|
||||
|
||||
Test-writer sub-agent, per test — paste into its prompt:
|
||||
|
||||
```
|
||||
[ ] Test describes behavior, not implementation
|
||||
[ ] Test uses public interface only
|
||||
[ ] Test would survive internal refactor
|
||||
[ ] Expected values are independent literals, not recomputed from the code
|
||||
```
|
||||
|
||||
Main agent, per GREEN:
|
||||
|
||||
```
|
||||
[ ] Code is minimal for this test
|
||||
[ ] No speculative features added
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user