agentleFS
mik2winmik2win/foureyes/skills/test-spec/SKILL.md

test-spec

Skill2 starsChanged 3 months agoMITView on GitHub

Spec-first testing — derive tests from a plan/spec file WITHOUT reading the implementation, so the spec is the source of truth: a failing test means the CODE is wrong, not the test. For pure-logic units (calculations, transforms, validators, parsers, state reducers, filters). Enforces verbatim spec-quoting, one-test-per-spec-case coverage, and a deviation report. TRIGGER when: a plan/spec (a /prepare plan file, or an inline `f(1.3) → ~1.0` contract) defines pure-logic behaviour to verify — either test-first before /implement, or as post-implementation spec-conformance. DO NOT TRIGGER when: authoring/refactoring tests by READING an existing module (use /test), driving new code red-green from scratch (use /tdd), or covering integration wiring, IO/handlers/persistence, or anything needing 3+ mocks (use /test).

2 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

10 rules. About 0 are common, 3 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If $ARGUMENTS is empty, ask which plan or inline spec to test, then stop.

    line 24
  2. Distinctive:

    The spec is the source of truth: Do NOT read the implementation while writing tests — tests come from the spec alone, so they can't be …

    line 39
  3. Very specific:

    Read .claude/PROJECT.md — Commands (test, test:targeted) and Architecture (the test layout: where tests, fixtures, and factories live, and …

    line 45
  4. Very specific:

    Read .claude/rules/_generic/testing.md and every stack testing rule whose paths match the target module — these carry the concrete …

    line 50
  5. Very specific:

    If CONTEXT.md exists, read it so test names use the project's ubiquitous language.

    line 53
  6. Very specific:

    Read the plan at $ARGUMENTS (or parse the inline function(input) → expected_output form).

    line 57
  7. Distinctive:

    Place the test at the project's test path/naming for the target module (PROJECT.md → Architecture).

    line 94
  8. Very specific:

    Run the targeted command (PROJECT.md → Commands → test:targeted) on the new test file — never hardcode the runner.

    line 104
  9. Very specific:

    Run the full test command (PROJECT.md → Commands) — no regressions elsewhere.

    line 124
  10. Distinctive:

    MUST: write a test for every case extracted in Phase 1.

    line 132

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Spec-First Testing: $ARGUMENTS

$ARGUMENTS is one of:

  • Plan/spec path — a /prepare plan or spec file under the backlog location.
  • Inline spec — "compute_score(1.3, 'gold') → ~1.0, (0.7, 'gold') → ~0.0".

If $ARGUMENTS is empty, ask which plan or inline spec to test, then stop.

This skill carries only the invariant spec-first discipline. The test/run commands, test layout, and framework idioms are read at runtime from .claude/PROJECT.md and the installed stack rules — never hardcoded here.

Core principle

Plan (spec) → Tests from spec → Code → Run tests
                                        │
                                  FAIL? → the CODE is wrong (spec = truth)
                                  PASS? → code matches spec ✓

The spec is the source of truth. Do NOT read the implementation while writing tests — tests come from the spec alone, so they can't be "written to match the bug". A failing test is a finding about the code, not a prompt to weaken the test.

Phase 0 — Load profile

  1. Read .claude/PROJECT.md — Commands (test, test:targeted) and Architecture (the test layout: where tests, fixtures, and factories live, and the naming convention). If missing or still TEMPLATE, fall back to the root CLAUDE.md (always in context) when it carries the commands/test layout — note you're running without a kit profile; only if neither has them, STOP → run /bootstrap first.
  2. Read .claude/rules/_generic/testing.md and every stack testing rule whose paths match the target module — these carry the concrete framework, assertion style, and factory locations. This skill does not restate framework idioms.
  3. If CONTEXT.md exists, read it so test names use the project's ubiquitous language.

Phase 1 — Parse the spec (mandatory verbatim quoting)

  1. Read the plan at $ARGUMENTS (or parse the inline function(input) → expected_output form). Do not open the implementation.
  2. Quote every testable behaviour verbatim — never paraphrase: function signatures, concrete input→output mappings, edge cases, and error conditions, each with its spec line reference.
  3. List ALL extracted cases before writing any test, and count them for the coverage check:
## Extracted test cases from spec
1. [spec line 45] `compute_score(1.3, "gold") → ~1.0`
2. [spec line 50] `compute_score(bad_input) → raises ValueError`
Total: N cases

Extract only pure logic — deterministic units with no external boundary: calculations (compute_score(x) → number), transforms/parsers (parse(raw) → Model), validators (validate(cfg) → bool | raises), state reducers (reduce(state, event) → state), filters (check(state) → (factor, blocked)). Do NOT extract integration wiring, network/DB/filesystem IO, request/message handlers, or anything needing 3+ mocks — those belong to /test.

Phase 2 — Design the test cases

Build a table from the spec — one row per extracted case. Keep the spec's own notation (~1.0, raises ValueError); the notation→assertion mapping lives in the reference.

FunctionInputExpected outputEdge case?
compute_score(1.0, "gold")~0.5boundary
compute_score(bad_input)raises ValueErrorerror

Phase 3 — Write the tests

Entering the writing phase → read reference/spec-test-patterns.md for the spec-notation→assertion mapping, the table→parametrize pattern, naming, the test skeleton, missing-implementation handling, and factory/fixture reuse. Render every idiom in your stack's framework (from the installed testing rules), not a hardcoded one.

Non-negotiables:

  • Place the test at the project's test path/naming for the target module (PROJECT.md → Architecture); the module docstring references the spec file.
  • Concrete assertions tied to the spec value (assert result >= 0.9), never assert result > 0 or is not None.
  • One spec case → one test (or one parametrized row); a spec table → one parametrized test.
  • Reuse the project's factories/fixtures for domain objects (check before building inline); seed all randomness; freeze/inject time — the spec cases must be repeatable.

Phase 4 — Run the tests

Run the targeted command (PROJECT.md → Commands → test:targeted) on the new test file — never hardcode the runner. If any test fails, do NOT assume the test is wrong → go to Phase 5 and investigate the code first.

Phase 5 — Failure investigation (spec = truth)

  1. Show the mismatch — Expected (from the spec, with file + line) vs Actual (from the run).
  2. Locate the implementation — grep the source tree for the function under test.
  3. Root-cause it — ask "why doesn't the code produce what the spec expects?" Common causes: formula wrong, parameters swapped, missing normalization, edge case unhandled.
  4. Suggest a fix direction for the CODE — do not modify the test to make it pass; the spec defines correct behaviour. The one exception: if the spec itself is contradictory or wrong, STOP and ask — do not silently pick a winner.

Worked example → reference/spec-test-patterns.md.

Phase 6 — Verification

  • Re-run the targeted command — the spec tests behave as expected (pass, or fail pointing at a real code defect you've reported).
  • Run the full test command (PROJECT.md → Commands) — no regressions elsewhere.
  • Optionally check coverage of the target module if the project defines a coverage command.

For spec tests, Timely (the T in FIRST) means written from the spec before implementation — the strongest position, because the test cannot have been shaped by the code.

Spec-compliance rules

MUST: write a test for every case extracted in Phase 1; quote the spec line in the test docstring/comment; report coverage — which cases are tested, which are not.

CANNOT without asking FIRST: skip any case (even one that looks redundant); merge cases in a way that loses coverage; declare a case "too hard to test".

STOP and ask when: you want to skip a case, a case describes behaviour that seems genuinely untestable at this layer, or the spec contradicts itself.

Output

## Spec-based tests: <plan/spec name>

### Extracted cases (from spec)
| # | Spec location | Case | Covered? |
|---|---------------|------|----------|
| 1 | line 45 | `compute_score(1.3, "gold") → ~1.0` | yes |
| 2 | line 50 | `compute_score(bad_input) → raises` | no — skipped (reason) |
**Coverage: X/Y spec cases**

### Spec deviation report — ALWAYS include ("No deviations" if all covered)
| # | Spec said | What I did | Reason |
|---|-----------|-----------|--------|
| 2 | invalid input raises | skipped | user approved — input unreachable in production |

### Tests written
- `<test path>` — N cases (M parametrized)

### Test results
- Passed: X · Failed: Y · Skipped: Z (awaiting implementation)

### Failures (if any)
| Test | Expected (spec) | Actual (code) | Root cause | Fix direction |
|------|-----------------|---------------|------------|---------------|

How this fits the pipeline

  • /prepare → plan → /test-spec → /implement — the recommended TDD flow: derive failing spec tests from the plan, then implement until they pass (the plan is the shared spec).
  • Post-implementation — run /test-spec <plan> after /implement to prove the code conforms to the spec it was built from.

Cross-reference

  • /tdd — drives new code red→green→refactor one slice at a time. /test-spec writes the spec tests up front from a written plan; use /tdd when there is no spec and you're discovering the design as you go.
  • /test — code-first: reads an existing module to author/refactor tests for coverage, fixtures, async, and antipatterns. /test-spec deliberately does not read the code.
  • /implement — executes the plan /test-spec derived tests from; mirrors its Commit Message pattern for the block below.

Persist to the artifact

(Mandatory when $ARGUMENTS or the session brief names a plan, card or spec file.) Follow ../implement/reference/work-log.md. Keep a ledger on disk from the first phase and record deviations the moment they are decided. Before the final reply, append ## Test-Spec Log — <date> — <verdict> to that file; its ### Result is the extracted-cases table, the spec deviation report, the results, and the failures with their root-cause direction. Anything you could not observe yourself goes under Re-check later, with its command and today's baseline: a post-deploy log grep, a soak count, a UI gesture. The chat output is a copy of the log, never the only record. No planning artifact → skip this section.

Commit

(Only if test files were written, and only if tracked files changed)

Offer a copy-paste git add <explicit test paths> + plus the plan/card file the log was appended to + git commit block — follow the Commit Message pattern in /implement: explicit paths only (never -A / . / a bare directory), text the user pastes (never run it), no Co-Authored-By trailer.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.