aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-08-20 09:45:58 -0700
committerCraig Jennings <c@cjennings.net>2026-08-20 09:45:58 -0700
commit3fbf3e022a364fe30609fb2d8dbc49ad6c961f70 (patch)
tree1c198dde0b6dada8c718d968c1e86affc2053af6
parentc588b0841df440e1a5290c7150ee245f90d1788e (diff)
downloadarchsetup-3fbf3e022a364fe30609fb2d8dbc49ad6c961f70.tar.gz
archsetup-3fbf3e022a364fe30609fb2d8dbc49ad6c961f70.zip
fix(post-rebuild-check): stop expecting a .claude directory every project names
Check 4 expects a tooling path wherever the project's own .gitignore names it, on the reasoning that the ignore file records what the project means to hold untracked. That holds for .ai and todo.org. It doesn't hold for .claude, because the bootstrap and the gitignore sweep write that line into every gitignore-mode project whether or not one ever exists there. The entry is aspirational, not a promise. pearl, rsyncshot and yt-sync each name it and none has ever had one. Ratio is missing the identical directory in the identical three, and ratio was never rebuilt, so this is the steady state rather than drift. That is the same test CLAUDE.md is already excluded by, one comment above. Dropping it costs no real signal. A project that genuinely carries a .claude, with rules and hooks from a language bundle, has it re-synced by sync-language-bundle.sh at every session start, so a true absence heals before this check would run. velox now reports one finding instead of eight. Seven of the eight were this checker being wrong rather than the machine.
-rwxr-xr-xscripts/post-rebuild-check11
-rw-r--r--tests/post-rebuild-check/test_post_rebuild_check.py23
2 files changed, 31 insertions, 3 deletions
diff --git a/scripts/post-rebuild-check b/scripts/post-rebuild-check
index ee77a19..aa7ef83 100755
--- a/scripts/post-rebuild-check
+++ b/scripts/post-rebuild-check
@@ -428,6 +428,16 @@ printf '%s\n' "$projects" > "$WORK/projects" 2>/dev/null || {
# steady state rather than reinstall drift, and flagging it would put nine
# standing findings in front of every real one.
#
+# .claude/ is absent for the same reason and proven the same way. The
+# bootstrap and the gitignore sweep write it into the ignore set of every
+# gitignore-mode project whether or not one ever exists there, so the entry is
+# aspirational rather than a promise -- pearl, rsyncshot and yt-sync each name
+# it and none of the three has ever had one, on velox or on ratio. Dropping it
+# loses no real signal either: a project that genuinely carries a .claude/
+# (rules and hooks from a language bundle) has it re-synced by
+# sync-language-bundle.sh at every session start, so a true absence heals
+# itself before this check would run.
+#
# The list is fed to the inner loop straight from a heredoc rather than
# staged through a file. It is a constant, so a file bought nothing and cost
# a fifth unguarded write: had it failed (a full tmpfs, say) the inner loop
@@ -458,7 +468,6 @@ while IFS= read -r proj; do
esac
done <<'EOF'
.ai \.ai
-.claude \.claude
todo.org todo\.org
inbox inbox
EOF
diff --git a/tests/post-rebuild-check/test_post_rebuild_check.py b/tests/post-rebuild-check/test_post_rebuild_check.py
index a034f87..bc887c6 100644
--- a/tests/post-rebuild-check/test_post_rebuild_check.py
+++ b/tests/post-rebuild-check/test_post_rebuild_check.py
@@ -765,12 +765,31 @@ class ProjectTooling(unittest.TestCase):
def test_ignored_but_absent_tooling_flags(self):
with tempfile.TemporaryDirectory() as root:
- self.project(root, [".ai/", ".claude/", "todo.org"])
+ self.project(root, [".ai/", "todo.org"])
r = run_check(project_roots=root)
self.assertEqual(r.returncode, 1)
- for missing in (".ai", ".claude", "todo.org"):
+ for missing in (".ai", "todo.org"):
self.assertIn(missing, r.stdout)
+ def test_claude_dir_absence_never_flags(self):
+ # Same shape as CLAUDE.md below, and proven the same way. The bootstrap
+ # and the gitignore sweep write `.claude/` into the ignore set of every
+ # gitignore-mode project whether or not one ever exists there, so the
+ # entry is aspirational rather than a promise. Three projects tripped
+ # this on velox, and ratio is missing the identical directory in the
+ # identical three, which is what proves it is the steady state and not
+ # reinstall drift.
+ #
+ # Nor does dropping it lose a real signal. A project that genuinely
+ # carries one (rules and hooks from a language bundle) has it re-synced
+ # by sync-language-bundle.sh at every session start, so a true absence
+ # heals itself before this check would ever run.
+ with tempfile.TemporaryDirectory() as root:
+ self.project(root, [".ai/", ".claude/"], present=(".ai/",))
+ r = run_check(project_roots=root)
+ self.assertEqual(r.returncode, 0, r.stdout)
+ self.assertNotIn(".claude", r.stdout)
+
def test_ignored_and_present_tooling_passes(self):
with tempfile.TemporaryDirectory() as root:
self.project(root, [".ai/", "CLAUDE.md"],