diff options
| author | Craig Jennings <c@cjennings.net> | 2026-04-19 17:07:29 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-04-19 17:07:29 -0500 |
| commit | c5b41a3fb69b61d8c43fa814b349d02672c0c66e (patch) | |
| tree | 7caec38ad3418f7fbf51d071e6373c4fd150544d /.claude | |
| parent | 7eb56084cc543d3455d277ef766302b1ad922b74 (diff) | |
| download | chime-c5b41a3fb69b61d8c43fa814b349d02672c0c66e.tar.gz chime-c5b41a3fb69b61d8c43fa814b349d02672c0c66e.zip | |
chore(claude): sync validate-el.sh JSON channel + pairwise rule from rulesets
Diffstat (limited to '.claude')
| -rwxr-xr-x | .claude/hooks/validate-el.sh | 33 | ||||
| -rw-r--r-- | .claude/rules/testing.md | 20 |
2 files changed, 44 insertions, 9 deletions
diff --git a/.claude/hooks/validate-el.sh b/.claude/hooks/validate-el.sh index 6f93d48..803badf 100755 --- a/.claude/hooks/validate-el.sh +++ b/.claude/hooks/validate-el.sh @@ -1,14 +1,32 @@ #!/usr/bin/env bash # Validate and test .el files after Edit/Write/MultiEdit. # PostToolUse hook: receives tool-call JSON on stdin. -# Silent on success; on failure, prints emacs output and exits 2 -# so Claude sees the error and can correct it. +# +# On success: exit 0 silent. +# On failure: emit JSON with hookSpecificOutput.additionalContext so Claude +# sees a structured error in its context, THEN exit 2 to block the tool +# pipeline. stderr still echoes the error for terminal visibility. # # Phase 1: check-parens + byte-compile -# Phase 2: for modules/*.el, run matching tests/test-<stem>*.el +# Phase 2: for non-test .el files, run matching tests/test-<stem>*.el set -u +# Emit a JSON failure payload and exit 2. Arguments: +# $1 — short failure type (e.g. "PAREN CHECK FAILED") +# $2 — file path +# $3 — emacs output (error body) +fail_json() { + local ctx + ctx="$(printf '%s: %s\n\n%s\n\nFix before proceeding.' "$1" "$2" "$3" \ + | jq -Rs .)" + cat <<EOF +{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": $ctx}} +EOF + printf '%s: %s\n%s\n' "$1" "$2" "$3" >&2 + exit 2 +} + # Portable project root: prefer Claude Code's env var, fall back to deriving # from this script's location ($project/.claude/hooks/validate-el.sh). PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}" @@ -25,8 +43,7 @@ case "$f" in # Byte-compile here would load the full package graph. Parens only. if ! output="$(emacs --batch --no-site-file --no-site-lisp "$f" \ --eval '(check-parens)' 2>&1)"; then - printf 'PAREN CHECK FAILED: %s\n%s\n' "$f" "$output" >&2 - exit 2 + fail_json "PAREN CHECK FAILED" "$f" "$output" fi ;; *.el) @@ -38,8 +55,7 @@ case "$f" in "$f" \ --eval '(check-parens)' \ --eval "(or (byte-compile-file \"$f\") (kill-emacs 1))" 2>&1)"; then - printf 'VALIDATION FAILED: %s\n%s\n' "$f" "$output" >&2 - exit 2 + fail_json "VALIDATION FAILED" "$f" "$output" fi ;; esac @@ -79,8 +95,7 @@ if [ "$count" -ge 1 ] && [ "$count" -le "$MAX_AUTO_TEST_FILES" ]; then --eval '(package-initialize)' \ -l ert "${load_args[@]}" \ --eval "(ert-run-tests-batch-and-exit '(not (tag :slow)))" 2>&1)"; then - printf 'TESTS FAILED for %s (%d test file(s)):\n%s\n' "$f" "$count" "$output" >&2 - exit 2 + fail_json "TESTS FAILED ($count test file(s))" "$f" "$output" fi fi diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md index f67ace2..b91b76c 100644 --- a/.claude/rules/testing.md +++ b/.claude/rules/testing.md @@ -58,6 +58,26 @@ Every unit under test requires coverage across three categories: - Resource exhaustion - Malformed data +## Combinatorial Coverage + +For functions with 3+ parameters that each take multiple values (feature-flag +combinations, config matrices, permission/role interactions, multi-field +form validation, API parameter spaces), the exhaustive test count explodes +(M^N) while 3-5 ad-hoc cases miss pair interactions. Use **pairwise / +combinatorial testing** — generate a minimal matrix that hits every 2-way +combination of parameter values. Empirically catches 60-90% of combinatorial +bugs with 80-99% fewer tests. + +Invoke `/pairwise-tests` on the offending function; continue using `/add-tests` +and the Normal/Boundary/Error discipline for the rest. The two approaches +complement: pairwise covers parameter *interactions*; category discipline +covers each parameter's individual edge space. + +Skip pairwise when: the function has 1-2 parameters (just write the cases), +the context requires *provably* exhaustive coverage (regulated systems — document +in an ADR), or the testing target is non-parametric (single happy path, +performance regression, a specific error). + ## Test Organization Typical layout: |
