Files
claude-skills/skills/tdd-criteria/SKILL.md

87 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: tdd-criteria
version: 0.1.0
description: >
TDD by default with four bright-line carve-outs. Applies before any code
change the agent didn't author this session. Triggers: "TDD",
"test-driven", "следуй TDD", "use TDD", "should I write tests",
"skip tdd", "[skip-tdd: ...]", "[test-modify: ...]", "tdd-criteria".
Cross-agent policy — no tool refs. Full rationale:
.wiki/concepts/tdd-criteria-design.md
---
# tdd-criteria
> TDD by default. Skip only with a bright-line marker. Tests defend code from silent deletion; rule 4 defends tests from silent rewriting.
## When this runs
**At session start** — when `CLAUDE.md` contains the line `follow tdd-criteria`.
**Before any code change** the agent didn't author this session — touching a `*.ts`, `*.js`, `*.py`, or similar source file triggers the decision algorithm below.
**On explicit reference** — when the user says "TDD", "test-driven", "следуй TDD", "use TDD", "should I write tests", "skip tdd", "tdd-criteria", or includes `[skip-tdd: ...]` or `[test-modify: ...]` in a commit subject.
## Default mode
TDD by default. Skip only if one of four bright-line carve-outs matches and is marked in the commit subject.
## Decision algorithm (8 questions, top-down)
Walk through in order. First «yes» determines mode. All «no» → TDD by default.
1. **Bug fix?** → TDD (red-test first)
2. **Consuming external contract** (SDK, REST API, чужая schema)? → TDD (contract-test)
3. **Security / auth / money / identifiers?** → TDD
4. **Pure logic** — function (input → output) without I/O, global state, bounded inputs? → TDD
5. **Visual / config** — CSS, layout, design tokens, `.env.example`, prompts, wiki, README? → SKIP, `[skip-tdd: visual]`
6. **Spike** — explicit POC «throwaway» in commit/PR/task subject? → SKIP, `[skip-tdd: spike]` + spike-survivor task if code survives
7. **One-shot** — migration, ETL backfill, ad-hoc cleanup, runs once? → SKIP, `[skip-tdd: oneshot]`
8. **Transit wrapper** ≤10 lines — no branching, re-export / glue? → SKIP, `[skip-tdd: wrapper]`
(default) → TDD
## Ironclad rules (TDD obligatory)
1. **Bug fix** — if there's an issue / failure log / repro, write a red-test codifying the repro. Marginal cost: 5 min. Marginal benefit: regression test forever.
2. **Pure logic, bounded inputs** — no fixtures, no mocks, no setup. Test = input/output pair. Skipping is gratuitous.
3. **Third-party contract** — SDK bumps change signatures silently. Contract-test pins known input → known shape. Catches break at first install, not days later.
4. **Security / auth / money / IDs** — asymmetric blast radius: false positive ≪ false negative. TDD = insurance.
In all four, recovery cost from silent deletion is high. The test is the only artefact that makes deletion visible.
## Permissive carve-outs (skip + marker required)
| # | Category | Trigger | Marker |
|---|----------|---------|--------|
| 5 | Visual / config | CSS, layout, tokens, `.env.example`, prompts, wiki | `[skip-tdd: visual]` |
| 6 | Spike | «POC, throwaway» in commit/PR/task subject | `[skip-tdd: spike]` |
| 7 | One-shot | Migration, ETL, ad-hoc cleanup; runs once | `[skip-tdd: oneshot]` |
| 8 | Wrapper | ≤10 lines, no branching, re-export / glue | `[skip-tdd: wrapper]` |
These are **accepted-risk zones** — you accept that an agent can vandalise without immediate signal, because recovery is cheap (eyeball next render; throwaway by contract; runs once; reconstruct ≤ delete).
## Anti-loophole
1. **Skip without category is invalid.** One of four explicit categories required — not «other reasons». No marker = violation.
2. **Spike survivor rule.** Merged spike → same merge-commit creates `[backfill-tests-<slug>]` task. Otherwise «spike» becomes «skipped tests forever».
3. **Friction is the point.** `[skip-tdd: visual]` 50× in a design-system rework is irritating — that's the fence. Re-evaluate after ≥2 weeks, not before.
4. **Tests are append-only by default.** Modifying an assertion, deleting a test, or disabling it (`it.skip`/`xit`/`@pytest.mark.skip`/`@Disabled`) requires:
- **Marker in commit subject:** `[test-modify: <test-name>: was <X>; is <Y>; reason: <Z>]``<X>` and `<Y>` are **literal assertion expressions**, not paraphrased. Example: `[test-modify: validates email: was expect(isValid("a@b")).toBe(true); is expect(isValid("a@b.com")).toBe(true); reason: tightened spec to require TLD]`
- **Separate commit from impl changes.** A commit must not modify both `*.test.*` and `src/*` files (or project-equivalents). `git log --grep '\[test-modify'` must show a clean test-only audit trail.
- **Why literal was/is:** an agent forced to write the literal assertion publishes exactly what they're rewriting. «Updated to match new behaviour» hides everything — agents will use that whenever allowed.
## Cross-agent applicability
Pure policy — no agent-specific tool references in this body. Works on Claude, Gemini, Copilot, or any future agent. Hermes mapping: `mode: auto`, `category: software-development`, no replace-rules.
## Out of scope
- Does not enforce via git hooks (separate optional task: `tdd-criteria-precommit-hook`).
- Does not modify project `CLAUDE.md` (that's `project-bootstrap`'s job).
- Does not run tests.
- Does not apply rule 4 retroactively to tests written before the rule was adopted.
## Why this exists
Tests make behaviour an invariant; without them, code is an artefact silent-deletable by agents. AND: the test itself must be defended too (rule 4) — otherwise the contract collapses back into an artefact when the agent rewrites the failing test. Full rationale: `.wiki/concepts/tdd-criteria-design.md`.