From d440bb52c1d72b9b01691d3b5ec1651d19219f22 Mon Sep 17 00:00:00 2001 From: OpeItcLoc03 Date: Thu, 7 May 2026 05:10:29 +0000 Subject: [PATCH] meta(tasks): create [tdd-criteria-precommit-hook] in claude-skills --- .tasks/STATUS.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index 9f2968a..8c3be8b 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -508,3 +508,76 @@ Both layers are needed. Either alone leaves a path-of-least-resistance route to --- + +## ⚪ [tdd-criteria-precommit-hook] — Optional pre-commit hook script that automates the bright-line checks from `tdd-criteria` Anti-loophole rules 1 and 4. Project owner opts in per-repo by symlinking / copying to `.git/hooks/pre-commit` (or via `husky` / `lefthook` integration if the project uses them). + +**Two checks** (both bright-line, both fail-closed): + +**Check 1 — `[skip-tdd: ]` validation.** If `git diff --cached --name-only` includes a `*.ts` / `*.js` / `*.py` / similar code file (excluding tests and Permissive-zoned paths like `*.css` / `*.env*` / `*.md` / `*.yaml`), require either: +- A `*.test.*` / `*.spec.*` / `test_*.py` / similar file present in the same diff, OR +- The commit subject (read from `$1` arg, line 1 of `$1` = msg path) matches `\[skip-tdd: (visual|spike|oneshot|wrapper)\]`. + +If neither holds → block with message: +``` +TDD policy violation: code change without test or skip marker. +Add a test, or include [skip-tdd: ] in commit subject. +See claude-skills/.wiki/concepts/tdd-criteria-design.md for which category applies. +``` + +**Check 2 — Test-modification audit (`[test-modify]` rule 4).** Detect test-modifying changes in `git diff --cached`: +- Removed line matching `^-\s*(expect|assert|assertThat|chai\.)\(` (assertion deletion) +- Added/removed lines that change argument values inside `expect(...)` / `assert(...)` calls +- Added `.skip` / `\.xit\b` / `@pytest\.mark\.skip` / `@Disabled` / `@Ignore` annotations +- Deleted `it(...)` / `test(...)` / `def test_*` definitions (matches `^-\s*(it|test|describe)\(` or `^-def test_`) + +If any matched → require commit subject matches `\[test-modify: [^:]+: was .+; is .+; reason: .+\]`. Block otherwise with message: +``` +Test-modification without [test-modify: ...] marker. +Required format: [test-modify: : was ; is ; reason: ] +The was/is must be the LITERAL assertion expressions, not paraphrased. +See tdd-criteria Anti-loophole rule 4. +``` + +ALSO: if `git diff --cached --name-only` includes both a test-pattern file AND an impl-pattern file → block: +``` +Test changes must be in a separate commit from impl changes (tdd-criteria rule 4b). +Run: git reset HEAD && git commit (test-only) && git add && git commit (impl-only). +``` + +**Implementation:** +- Bash script (single file). Cross-platform: works on Linux/macOS and on Windows under git-bash (which Claude/Hermes both already run on). +- Path: `~/projects/claude-skills/scripts/tdd-criteria-precommit-hook.sh`. Plus a Windows wrapper `.ps1` that delegates if needed. +- Tested on a real repo before commit (`books` is a good candidate — it has Jest tests + `*.test.js` convention). +- Documented in `claude-skills/.wiki/concepts/tdd-criteria-design.md` «See also» section (already linked). + +**Activation pattern (per-repo):** +```bash +# Symlink or copy the hook +ln -sf ~/projects/claude-skills/scripts/tdd-criteria-precommit-hook.sh \ + .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit +``` + +Or via `lefthook.yml` / `.husky/pre-commit` if the project already uses one of those. + +**Out of scope:** +- Mutation testing (Stryker, mutmut) — separate heavyweight infra, not this hook. +- Coverage gates — different mechanism, different cost/benefit. +- Visual regression infra (Percy, Chromatic) — Permissive-5 acknowledges this is heavyweight; not bundled. +- Auto-fixing the violation — hook only blocks; fix is human's job. + +**Why this is optional, not required by the SKILL.md:** + +The skill is **policy** that lives in claude-skills and gets pulled into agent context per project. The hook is **enforcement** that needs per-project setup. Some projects opt out of pre-commit hooks entirely (e.g. `karu` if it's pure CSS — no code surface to enforce). Forcing the hook into the skill would couple policy to tooling. + +**Bypass:** + +Pre-commit hooks have `--no-verify`. Per `project-discipline` Rule 4 («never skip hooks unless user explicitly asks») agents must not use `--no-verify` — but humans can in emergencies. Each `--no-verify` use should be self-flagged in the commit body («bypassed pre-commit because: ...»). Not enforceable by the hook itself; this is a higher-level audit. + +**Status:** ready +**Where I stopped:** (not started) +**Next action:** Решить, нужен ли hook (он опционален) — если да, написать `~/projects/claude-skills/scripts/tdd-criteria-precommit-hook.sh` по спеке в description, протестировать на `books` (Jest-конвенция `*.test.js`), задокументировать activation pattern. Если нет — закрыть как `wontfix` с пометкой что fence чисто социальная (commit subject visible в `git log`). +**Branch:** master + + +---