diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-28 09:16:39 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-28 09:16:39 -0500 |
| commit | 5c0c7a6f213609f5be8258f07b763201ad182876 (patch) | |
| tree | 9d7c0d54cde859607fb1910b57395f4408900906 | |
| parent | bdf755d33aa6a207a538c85f18e38cc03f14e529 (diff) | |
| download | rulesets-5c0c7a6f213609f5be8258f07b763201ad182876.tar.gz rulesets-5c0c7a6f213609f5be8258f07b763201ad182876.zip | |
fix(sync-check): ignore generated python and elisp artifacts
Pre-commit caught a false-positive on its first real-world run. The
.ai/scripts/__pycache__ directory created by make test (pytest writes
.pyc and .pytest_cache, emacs writes .elc) was flagged as drift
against the canonical's clean tree.
Added matching --exclude patterns to the diff -rq check and the --fix
rsync calls. Patterns: __pycache__, *.pyc, *.pyo, .pytest_cache, *.elc.
The --fix excludes prevent rsync's --delete from wiping the mirror's
__pycache__ when the canonical has none.
Four new bats tests cover the exclusions. All 12 pass.
| -rw-r--r-- | claude-templates/Makefile | 39 | ||||
| -rwxr-xr-x | scripts/sync-check.sh | 28 | ||||
| -rw-r--r-- | scripts/tests/sync-check.bats | 30 | ||||
| -rw-r--r-- | todo.org | 3 |
4 files changed, 56 insertions, 44 deletions
diff --git a/claude-templates/Makefile b/claude-templates/Makefile deleted file mode 100644 index e097cc2..0000000 --- a/claude-templates/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -.DEFAULT_GOAL := help - -PREFIX ?= $(HOME)/.local/bin -SRC := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) - -.PHONY: help install uninstall list test-scripts - -help: - @printf 'claude-templates — session launcher + project seed\n\n' - @printf 'Targets:\n' - @printf ' make install symlink bin/ai into %s\n' "$(PREFIX)" - @printf ' make uninstall remove the symlink\n' - @printf ' make list show installed symlink\n' - @printf ' make test-scripts run pytest + ERT suites under .ai/scripts/tests/\n' - -install: - @mkdir -p $(PREFIX) - @chmod +x $(SRC)/bin/ai - @ln -sfn $(SRC)/bin/ai $(PREFIX)/ai - @printf 'installed %s/ai -> %s/bin/ai\n' "$(PREFIX)" "$(SRC)" - -uninstall: - @if [ -L $(PREFIX)/ai ]; then \ - rm $(PREFIX)/ai; \ - printf 'removed %s/ai\n' "$(PREFIX)"; \ - else \ - printf '%s/ai is not a symlink; nothing to remove\n' "$(PREFIX)"; \ - fi - -list: - @ls -la $(PREFIX)/ai 2>/dev/null || printf 'not installed\n' - -test-scripts: - @cd $(SRC)/.ai/scripts/tests && python -m pytest - @set -e; for f in $(SRC)/.ai/scripts/tests/test-*.el; do \ - [ -e "$$f" ] || continue; \ - echo "ert: $$(basename "$$f")"; \ - emacs --batch -q -L $(SRC)/.ai/scripts -l ert -l "$$f" -f ert-run-tests-batch-and-exit; \ - done diff --git a/scripts/sync-check.sh b/scripts/sync-check.sh index 8fb9ab0..cc7bc62 100755 --- a/scripts/sync-check.sh +++ b/scripts/sync-check.sh @@ -35,12 +35,23 @@ fi paths=(protocols.org workflows scripts) +# Generated artifacts that should never count as drift. These appear on the +# mirror side when tests run (pytest writes .pyc and .pytest_cache; emacs +# writes .elc) but aren't part of the canonical source. +exclude_args=( + --exclude='__pycache__' + --exclude='*.pyc' + --exclude='*.pyo' + --exclude='.pytest_cache' + --exclude='*.elc' +) + check_drift() { local drift=0 for relpath in "${paths[@]}"; do - if ! diff -rq "$canonical/$relpath" "$mirror/$relpath" >/dev/null 2>&1; then + if ! diff -rq "${exclude_args[@]}" "$canonical/$relpath" "$mirror/$relpath" >/dev/null 2>&1; then echo "drift: claude-templates/.ai/$relpath ↔ .ai/$relpath" >&2 - diff -rq "$canonical/$relpath" "$mirror/$relpath" 2>&1 | head -20 >&2 + diff -rq "${exclude_args[@]}" "$canonical/$relpath" "$mirror/$relpath" 2>&1 | head -20 >&2 drift=1 fi done @@ -54,9 +65,18 @@ fi if [ "${1:-}" = "--fix" ]; then echo "" >&2 echo "sync-check --fix: syncing canonical → mirror..." >&2 + # Same exclude patterns as the diff so generated files in the mirror + # aren't wiped by --delete when canonical has no counterpart. + rsync_excludes=( + --exclude='__pycache__' + --exclude='*.pyc' + --exclude='*.pyo' + --exclude='.pytest_cache' + --exclude='*.elc' + ) rsync -a "$canonical/protocols.org" "$mirror/protocols.org" - rsync -a --delete "$canonical/workflows/" "$mirror/workflows/" - rsync -a --delete "$canonical/scripts/" "$mirror/scripts/" + rsync -a --delete "${rsync_excludes[@]}" "$canonical/workflows/" "$mirror/workflows/" + rsync -a --delete "${rsync_excludes[@]}" "$canonical/scripts/" "$mirror/scripts/" if check_drift; then echo "sync-check --fix: resolved." >&2 echo "Re-stage the synced files and retry the commit." >&2 diff --git a/scripts/tests/sync-check.bats b/scripts/tests/sync-check.bats index df775b3..17c9189 100644 --- a/scripts/tests/sync-check.bats +++ b/scripts/tests/sync-check.bats @@ -84,3 +84,33 @@ setup() { [ "$status" -eq 2 ] [[ "$output" == *"not inside a git checkout"* ]] } + +@test "generated Python artifacts in mirror don't count as drift" { + mkdir -p .ai/scripts/__pycache__ + touch .ai/scripts/__pycache__/foo.cpython-314.pyc + touch .ai/scripts/some.pyc + run scripts/sync-check.sh + [ "$status" -eq 0 ] +} + +@test "compiled elisp artifacts in mirror don't count as drift" { + touch .ai/scripts/foo.elc + run scripts/sync-check.sh + [ "$status" -eq 0 ] +} + +@test "pytest cache in mirror doesn't count as drift" { + mkdir -p .ai/scripts/.pytest_cache + touch .ai/scripts/.pytest_cache/CACHEDIR.TAG + run scripts/sync-check.sh + [ "$status" -eq 0 ] +} + +@test "--fix preserves generated artifacts in mirror" { + mkdir -p .ai/scripts/__pycache__ + touch .ai/scripts/__pycache__/foo.cpython-314.pyc + echo "drift" > .ai/protocols.org + run scripts/sync-check.sh --fix + [ "$status" -eq 0 ] + [ -f .ai/scripts/__pycache__/foo.cpython-314.pyc ] +} @@ -1125,7 +1125,8 @@ The four canonical rules (=commits=, =testing=, =verification=, =subagents=) are The Elisp pair is the most suspicious — three repos using essentially the same rules. Audit: diff these across the projects, check for drift, then decide whether to canonicalize them under =~/code/rulesets/claude-rules/languages/<lang>/= and symlink, or leave them as project-local. -** TODO [#C] Consolidate =claude-templates/Makefile= after fold :chore:quick:solo: +** DONE [#C] Consolidate =claude-templates/Makefile= after fold :chore:quick:solo: +CLOSED: [2026-05-28 Thu] :PROPERTIES: :LAST_REVIEWED: 2026-05-28 :END: |
