aboutsummaryrefslogtreecommitdiff
path: root/scripts/tests/sync-language-bundle.bats
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/tests/sync-language-bundle.bats')
-rw-r--r--scripts/tests/sync-language-bundle.bats75
1 files changed, 69 insertions, 6 deletions
diff --git a/scripts/tests/sync-language-bundle.bats b/scripts/tests/sync-language-bundle.bats
index 1871444..0eb3ae2 100644
--- a/scripts/tests/sync-language-bundle.bats
+++ b/scripts/tests/sync-language-bundle.bats
@@ -19,7 +19,20 @@ teardown() {
rm -rf "$PROJ"
}
-# Mirror install-lang.sh: copy the bundle's files into a synthetic project.
+# Mirror what a CURRENT install-lang.sh leaves: language rules only, no copies
+# of the generic rules (those live once at ~/.claude/rules/).
+install_bundle_current() {
+ install_bundle "$1" "$2"
+ local f
+ for f in "$REAL_REPO/claude-rules"/*.md; do
+ [ -f "$f" ] || continue
+ rm -f "$2/.claude/rules/$(basename "$f")"
+ done
+}
+
+# Mirror what an OLDER install-lang.sh left behind: language rules PLUS copies
+# of every generic rule. This is the state the sweep exists to clean up, and
+# real projects are still in it until their next startup.
install_bundle() {
local lang="$1" proj="$2"
mkdir -p "$proj/.claude/rules"
@@ -67,14 +80,14 @@ install_team_overlay() {
}
@test "sync: clean elisp bundle is a quiet no-op (exit 0)" {
- install_bundle elisp "$PROJ"
+ install_bundle_current elisp "$PROJ"
run bash "$SCRIPT" "$PROJ"
[ "$status" -eq 0 ]
[ -z "$output" ]
}
@test "sync: absent CLAUDE.md is not flagged as drift (seed-only/project-owned)" {
- install_bundle elisp "$PROJ" # helper never seeds CLAUDE.md
+ install_bundle_current elisp "$PROJ" # helper never seeds CLAUDE.md
[ ! -f "$PROJ/CLAUDE.md" ]
run bash "$SCRIPT" "$PROJ"
[ "$status" -eq 0 ]
@@ -94,13 +107,17 @@ install_team_overlay() {
matches_canonical ".claude/rules/elisp.md" "$REAL_REPO/languages/elisp/claude/rules/elisp.md"
}
-@test "sync: drifted generic rule is auto-fixed and restored" {
+# Generic rules are no longer auto-fixed in place: they are swept, because the
+# global copy at ~/.claude/rules/ is the one that loads. A drifted project copy
+# is not repaired, it is removed — which is the stronger fix, since the drifted
+# copy outranked the global rule while it existed.
+@test "sync: a drifted generic rule copy is swept, not repaired" {
install_bundle elisp "$PROJ"
echo "junk" >> "$PROJ/.claude/rules/commits.md"
run bash "$SCRIPT" "$PROJ"
[ "$status" -eq 0 ]
- [[ "$output" == *".claude/rules/commits.md"* ]]
- matches_canonical ".claude/rules/commits.md" "$REAL_REPO/claude-rules/commits.md"
+ [[ "$output" == *"swept"* ]]
+ [ ! -f "$PROJ/.claude/rules/commits.md" ]
}
@test "sync: missing rule is re-copied" {
@@ -276,3 +293,49 @@ install_team_overlay() {
[ ! -f "$PROJ/.claude/rules/commits.md" ]
[ ! -f "$PROJ/.claude/rules/testing.md" ]
}
+
+# --- generic-rule de-duplication -------------------------------------------
+#
+# Generic rules live at ~/.claude/rules/ (symlinked by `make install`) and load
+# in every session. Copying them into each project as well made Claude Code
+# load them twice, and project copies take priority — so a stale project copy
+# silently overrode the fresh global one. The bundle now ships only its own
+# language rules and sweeps the duplicates it previously installed.
+
+@test "sync: sweeps generic rule copies that duplicate the global set" {
+ install_bundle python "$PROJ"
+ [ -f "$PROJ/.claude/rules/commits.md" ]
+ HOME_RULES="$(mktemp -d)" ; mkdir -p "$HOME_RULES/.claude/rules"
+ cp "$REAL_REPO/claude-rules"/*.md "$HOME_RULES/.claude/rules/"
+ run env HOME="$HOME_RULES" bash "$SCRIPT" "$PROJ"
+ [ "$status" -eq 0 ]
+ [ ! -f "$PROJ/.claude/rules/commits.md" ]
+ [ ! -f "$PROJ/.claude/rules/todo-format.md" ]
+}
+
+@test "sync: keeps the language bundle's own rules while sweeping generics" {
+ install_bundle python "$PROJ"
+ HOME_RULES="$(mktemp -d)" ; mkdir -p "$HOME_RULES/.claude/rules"
+ cp "$REAL_REPO/claude-rules"/*.md "$HOME_RULES/.claude/rules/"
+ run env HOME="$HOME_RULES" bash "$SCRIPT" "$PROJ"
+ [ "$status" -eq 0 ]
+ [ -f "$PROJ/.claude/rules/python-testing.md" ]
+}
+
+@test "sync: keeps a project-owned overlay rule the bundle does not own" {
+ install_bundle python "$PROJ"
+ printf '# Publishing\n\nApplies to: `**/*`\n' > "$PROJ/.claude/rules/publishing.md"
+ HOME_RULES="$(mktemp -d)" ; mkdir -p "$HOME_RULES/.claude/rules"
+ cp "$REAL_REPO/claude-rules"/*.md "$HOME_RULES/.claude/rules/"
+ run env HOME="$HOME_RULES" bash "$SCRIPT" "$PROJ"
+ [ "$status" -eq 0 ]
+ [ -f "$PROJ/.claude/rules/publishing.md" ]
+}
+
+@test "sync: does NOT sweep when the global rule is absent (nothing takes over)" {
+ install_bundle python "$PROJ"
+ HOME_RULES="$(mktemp -d)" # no ~/.claude/rules/ at all
+ run env HOME="$HOME_RULES" bash "$SCRIPT" "$PROJ"
+ [ "$status" -eq 0 ]
+ [ -f "$PROJ/.claude/rules/commits.md" ]
+}