feat(memory): guards, doctor stats and doc-commit exclusions follow CLAUDE.global.md

This commit is contained in:
Bastien Chanot
2026-07-14 03:55:25 +02:00
parent 040c88ee40
commit c20ad4763a
4 changed files with 21 additions and 16 deletions
+3 -3
View File
@@ -241,14 +241,14 @@ echo ""
# 6. Token budget estimate # 6. Token budget estimate
# ──────────────────────────────────────────────────────────── # ────────────────────────────────────────────────────────────
echo "── Token budget estimate ──" echo "── Token budget estimate ──"
# The passive footprint (CLAUDE.md + skill descriptions + plugin session-injects) # The passive footprint (CLAUDE.global.md + skill descriptions + plugin session-injects)
# loads into the CONTEXT WINDOW every session — it competes with the ~200k default # loads into the CONTEXT WINDOW every session — it competes with the ~200k default
# context, NOT a per-session token quota (the old "~11k/5h budget" denominator was # context, NOT a per-session token quota (the old "~11k/5h budget" denominator was
# a category error → false "92% CRITICAL", LRN-047). Measured ~11.4k post-audit # a category error → false "92% CRITICAL", LRN-047). Measured ~11.4k post-audit
# 2026-07-02 (LRN-088); the chars/4 sum below is a coarse proxy of that footprint. # 2026-07-02 (LRN-088); the chars/4 sum below is a coarse proxy of that footprint.
# Thresholds: WARNING >15% of context (~30k), CRITICAL >25% (~50k). # Thresholds: WARNING >15% of context (~30k), CRITICAL >25% (~50k).
CLAUDE_MD_CHARS=$(wc -c < "$REPO/CLAUDE.md" 2>/dev/null || echo 0) CLAUDE_MD_CHARS=$(wc -c < "$REPO/CLAUDE.global.md" 2>/dev/null || echo 0)
CLAUDE_MD_TOKENS=$((CLAUDE_MD_CHARS / 4)) CLAUDE_MD_TOKENS=$((CLAUDE_MD_CHARS / 4))
# Skill descriptions only (frontmatter description field — loaded passively at startup) # Skill descriptions only (frontmatter description field — loaded passively at startup)
@@ -274,7 +274,7 @@ CONTEXT_WINDOW=200000 # Claude Code default context window (conservative; 1M i
PCT=$((TOTAL_TOKENS * 100 / CONTEXT_WINDOW)) PCT=$((TOTAL_TOKENS * 100 / CONTEXT_WINDOW))
echo "" echo ""
echo " CLAUDE.md: ~${CLAUDE_MD_TOKENS}t" echo " CLAUDE.global.md: ~${CLAUDE_MD_TOKENS}t"
echo " Skill descriptions: ~${SKILL_DESC_TOKENS}t (${SKILL_COUNT} skills)" echo " Skill descriptions: ~${SKILL_DESC_TOKENS}t (${SKILL_COUNT} skills)"
echo " Plugin passive cost: ~${PLUGIN_TOKENS}t (active plugins)" echo " Plugin passive cost: ~${PLUGIN_TOKENS}t (active plugins)"
echo " ─────────────────────────────────────────" echo " ─────────────────────────────────────────"
+6 -6
View File
@@ -199,13 +199,13 @@ unset _active_count _inactive_count
printf "│ 🖥️ CLI : %-40s│\n" "$GSD_STATUS" printf "│ 🖥️ CLI : %-40s│\n" "$GSD_STATUS"
[ -n "$TOKEN_WARN" ] && printf "│ 💰 %-44s│\n" "${TOKEN_WARN:0:44}" [ -n "$TOKEN_WARN" ] && printf "│ 💰 %-44s│\n" "${TOKEN_WARN:0:44}"
printf "│ 📦 v%-45s│\n" "$CONFIG_VERSION" printf "│ 📦 v%-45s│\n" "$CONFIG_VERSION"
# CLAUDE.md line-count guard (anti-regression). BDR-062 supersedes BDR-031's # CLAUDE.global.md line-count guard (anti-regression). BDR-062 supersedes
# 275 target: 305 is the assumed reality (extraction already done at job1; # BDR-031's 275 target: 305 is the assumed reality (extraction done at
# further compression costs clarity > token gain) — warn only past a 320 margin. # job1; further compression costs clarity > token gain) — warn past 320.
if [ -n "$REPO_DIR" ] && [ -f "$REPO_DIR/CLAUDE.md" ]; then if [ -n "$REPO_DIR" ] && [ -f "$REPO_DIR/CLAUDE.global.md" ]; then
_claude_lines=$(wc -l < "$REPO_DIR/CLAUDE.md") _claude_lines=$(wc -l < "$REPO_DIR/CLAUDE.global.md")
if [ "$_claude_lines" -gt 320 ]; then if [ "$_claude_lines" -gt 320 ]; then
_cmd_warn="CLAUDE.md ${_claude_lines}L (>320) — density pass requis" _cmd_warn="CLAUDE.global.md ${_claude_lines}L (>320) — density pass"
printf "│ ⚠️ %-44s│\n" "${_cmd_warn:0:44}" printf "│ ⚠️ %-44s│\n" "${_cmd_warn:0:44}"
unset _cmd_warn unset _cmd_warn
fi fi
+7 -4
View File
@@ -33,12 +33,15 @@ source "$REPO/lib/detect-plugins.sh"
# graphify's installer (Step 7) rewrites CLAUDE.md + .claude/settings.json # graphify's installer (Step 7) rewrites CLAUDE.md + .claude/settings.json
# (clobbers the curated graphify section + injects aggressive MANDATORY # (clobbers the curated graphify section + injects aggressive MANDATORY
# hooks), and `claude plugin install` (Step 5) flips enable-states in # hooks), and `claude plugin install` (Step 5) flips enable-states in
# settings.json. These 3 files are maintained by hand + commit, never by # settings.json. These 4 files are maintained by hand + commit, never by
# the installer. Snapshot them now and restore on exit so a run leaves them # the installer. Snapshot them now and restore on exit so a run leaves them
# exactly as it found them. Pre-existing local edits are preserved; only the # exactly as it found them. Pre-existing local edits are preserved; only the
# installer's drift is undone. NOTE: this makes these files install-immutable # installer's drift is undone. NOTE: this makes these files install-immutable
# — anything the installer should add to them must be committed by hand. # — anything the installer should add to them must be committed by hand.
GUARDED_CONFIGS=("CLAUDE.md" ".claude/settings.json" "settings.json") # CLAUDE.md = project memory (graphify's rewrite target); CLAUDE.global.md
# = user-scope global memory (deployed as ~/.claude/CLAUDE.md).
GUARDED_CONFIGS=("CLAUDE.md" "CLAUDE.global.md" ".claude/settings.json"
"settings.json")
CFG_SNAPSHOT="$(mktemp -d 2>/dev/null || true)" CFG_SNAPSHOT="$(mktemp -d 2>/dev/null || true)"
restore_curated_configs() { restore_curated_configs() {
@@ -63,8 +66,8 @@ if [ -n "$CFG_SNAPSHOT" ]; then
trap restore_curated_configs EXIT trap restore_curated_configs EXIT
else else
err "Config guard could not be created (mktemp failed) — refusing to run" \ err "Config guard could not be created (mktemp failed) — refusing to run" \
"unguarded: CLAUDE.md/.claude/settings.json/settings.json could be" \ "unguarded: CLAUDE.md/CLAUDE.global.md/.claude/settings.json/settings.json" \
"silently rewritten by the installer. Fix mktemp/TMPDIR and retry." "could be silently rewritten by the installer. Fix mktemp/TMPDIR and retry."
exit 1 exit 1
fi fi
+5 -3
View File
@@ -41,11 +41,13 @@ _unsafe_state() {
} }
# True (0) when a path is OUT OF SCOPE for a doc commit: anything under .claude/ # True (0) when a path is OUT OF SCOPE for a doc commit: anything under .claude/
# (any depth) or a CLAUDE.md (root or nested). These are doc-syncer's read-only # (any depth) or a CLAUDE.md / CLAUDE.global.md memory file (root or nested).
# context, never sync targets (BDR-022) — their presence is an upstream anomaly. # These are doc-syncer's read-only context, never sync targets (BDR-022) —
# their presence is an upstream anomaly.
_forbidden_path() { _forbidden_path() {
case "$1" in case "$1" in
.claude | .claude/* | */.claude/* | CLAUDE.md | */CLAUDE.md) return 0 ;; .claude | .claude/* | */.claude/* | CLAUDE.md | */CLAUDE.md | \
CLAUDE.global.md | */CLAUDE.global.md) return 0 ;;
*) return 1 ;; *) return 1 ;;
esac esac
} }