forked from bchanot/claude
fix(memory): test covers CLAUDE.global.md guard entry; doctor asserts exact global symlink target
This commit is contained in:
@@ -7,6 +7,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- BREAKING(layout): repo-root global memory renamed CLAUDE.md → CLAUDE.global.md; run `bash link.sh` once after pulling (doctor.sh now checks the exact target)
|
||||
- graphify skill dist refreshed 0.8.45 → 0.9.6 (out-of-band `make plugin`; SKILL.md + query/extraction references updated by the generator).
|
||||
- `/deploy` checklist reshaped on first-real-run feedback, in two passes: runbook steps are **one command per line, interactive-session style** (an early step opens the ssh session; later lines run on the box; local steps say "from your machine") instead of folded `ssh host "cd … && …"` one-liners — step = comment header + command lines up to the next blank line, a `@delta:` directive governs the whole block; and the checklist is now **display-only** — `NEXT.sh` is no longer written at all (throwaway artifact; `PENDING.json` + the live runbook regenerate it in any session) and every hand-back **ends the turn with the full checklist as the final text, no tool call after it** (a checklist printed above a blocking question tool was observed never reaching the user). Template `templates/deploy/PROCEDURE.md` restyled to match.
|
||||
- `settings.json`: `inputNeededNotifEnabled: true` adopted (harness notification toggle); committed layout otherwise unchanged.
|
||||
|
||||
@@ -63,6 +63,17 @@ check_symlink() {
|
||||
}
|
||||
|
||||
check_symlink "CLAUDE.md"
|
||||
# check_symlink only asserts the canonical path lands inside $REPO — after a
|
||||
# `git pull` without `link.sh`, ~/.claude/CLAUDE.md can still resolve inside
|
||||
# $REPO but at the wrong file (the 29-line project CLAUDE.md instead of
|
||||
# CLAUDE.global.md), passing green while the global doctrine is silently gone.
|
||||
_claude_md_target=$(readlink "$HOME/.claude/CLAUDE.md" 2>/dev/null || true)
|
||||
if [ "$_claude_md_target" != "$REPO/CLAUDE.global.md" ]; then
|
||||
# shellcheck disable=SC2088 # literal label, not a tilde-expansion attempt
|
||||
warn "~/.claude/CLAUDE.md points to $_claude_md_target — expected \
|
||||
$REPO/CLAUDE.global.md; run: bash link.sh"
|
||||
fi
|
||||
unset _claude_md_target
|
||||
check_symlink "settings.json"
|
||||
check_symlink "agents"
|
||||
check_symlink "skills"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# single-occurrence + column-0 closing brace) so drift in install-plugins.sh
|
||||
# propagates into this test instead of testing a stale copy. GUARDED_CONFIGS,
|
||||
# CFG_SNAPSHOT, REPO and an info() stub are defined here — the array literal
|
||||
# at install-plugins.sh:41 is outside the extracted range.
|
||||
# at install-plugins.sh:43-44 is outside the extracted range.
|
||||
set -u
|
||||
INSTALL_SH="$(cd "$(dirname "$0")/../.." && pwd)/install-plugins.sh"
|
||||
pass=0; fail=0
|
||||
@@ -19,13 +19,14 @@ awk '/^restore_curated_configs\(\) \{/,/^\}/' "$INSTALL_SH" > "$SUT"
|
||||
REPO="$(mktemp -d)"
|
||||
CFG_SNAPSHOT="$(mktemp -d)"
|
||||
EXPECT="$(mktemp -d)" # our own reference copy — independent of CFG_SNAPSHOT (SUT rm -rf's it)
|
||||
GUARDED_CONFIGS=("CLAUDE.md" ".claude/settings.json" "settings.json")
|
||||
GUARDED_CONFIGS=("CLAUDE.md" "CLAUDE.global.md" ".claude/settings.json" "settings.json")
|
||||
info() { :; } # stub — extracted body calls info(), irrelevant to the assertions
|
||||
|
||||
mkdir -p "$REPO/.claude"
|
||||
printf 'CLAUDE original\n' > "$REPO/CLAUDE.md"
|
||||
printf '{"a":1}\n' > "$REPO/.claude/settings.json"
|
||||
printf '{"b":2}\n' > "$REPO/settings.json"
|
||||
printf 'CLAUDE original\n' > "$REPO/CLAUDE.md"
|
||||
printf 'CLAUDE.global original\n' > "$REPO/CLAUDE.global.md"
|
||||
printf '{"a":1}\n' > "$REPO/.claude/settings.json"
|
||||
printf '{"b":2}\n' > "$REPO/settings.json"
|
||||
|
||||
for f in "${GUARDED_CONFIGS[@]}"; do
|
||||
mkdir -p "$CFG_SNAPSHOT/$(dirname "$f")" "$EXPECT/$(dirname "$f")"
|
||||
@@ -33,7 +34,7 @@ for f in "${GUARDED_CONFIGS[@]}"; do
|
||||
cp "$REPO/$f" "$EXPECT/$f"
|
||||
done
|
||||
|
||||
# simulate installer drift: mutate ONE guarded file, leave the other two alone
|
||||
# simulate installer drift: mutate ONE guarded file, leave the other three alone
|
||||
printf 'CLAUDE CLOBBERED BY INSTALLER\n' > "$REPO/CLAUDE.md"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
@@ -42,20 +43,22 @@ restore_curated_configs
|
||||
|
||||
cmp -s "$REPO/CLAUDE.md" "$EXPECT/CLAUDE.md"
|
||||
check T1-mutated-file-restored "$?" 0
|
||||
cmp -s "$REPO/CLAUDE.global.md" "$EXPECT/CLAUDE.global.md"
|
||||
check T2-untouched-global-md-unchanged "$?" 0
|
||||
cmp -s "$REPO/.claude/settings.json" "$EXPECT/.claude/settings.json"
|
||||
check T2-untouched-local-settings-unchanged "$?" 0
|
||||
check T3-untouched-local-settings-unchanged "$?" 0
|
||||
cmp -s "$REPO/settings.json" "$EXPECT/settings.json"
|
||||
check T3-untouched-settings-unchanged "$?" 0
|
||||
if [ -d "$CFG_SNAPSHOT" ]; then r4=present; else r4=gone; fi
|
||||
check T4-snapshot-dir-removed "$r4" gone
|
||||
check T4-untouched-settings-unchanged "$?" 0
|
||||
if [ -d "$CFG_SNAPSHOT" ]; then r5=present; else r5=gone; fi
|
||||
check T5-snapshot-dir-removed "$r5" gone
|
||||
|
||||
# --- T5: mktemp failure -> fail-closed (install-plugins.sh, the header block
|
||||
# --- T6: mktemp failure -> fail-closed (install-plugins.sh, the header block
|
||||
# that builds CFG_SNAPSHOT) — refuses to run unguarded instead of warning and
|
||||
# continuing. Extracted with a WIDER range than the SUT above: this logic
|
||||
# lives in the top-level if/else, outside restore_curated_configs().
|
||||
SUT2="$(mktemp)"
|
||||
awk '/^GUARDED_CONFIGS=/,/^fi$/' "$INSTALL_SH" > "$SUT2"
|
||||
ERR5="$(mktemp)"
|
||||
ERR6="$(mktemp)"
|
||||
(
|
||||
# shellcheck disable=SC2329 # invoked indirectly by the sourced snippet below
|
||||
mktemp() { return 1; } # force the header's CFG_SNAPSHOT creation to fail
|
||||
@@ -68,11 +71,11 @@ ERR5="$(mktemp)"
|
||||
REPO="$(command mktemp -d)"
|
||||
# shellcheck source=/dev/null
|
||||
source "$SUT2"
|
||||
) >/dev/null 2>"$ERR5"
|
||||
rc5=$?
|
||||
check T5-mktemp-failure-aborts "$rc5" 1
|
||||
if grep -qi 'mktemp failed' "$ERR5"; then r5msg=yes; else r5msg=no; fi
|
||||
check T5-mktemp-failure-loud "$r5msg" yes
|
||||
rm -f "$ERR5" "$SUT2"
|
||||
) >/dev/null 2>"$ERR6"
|
||||
rc6=$?
|
||||
check T6-mktemp-failure-aborts "$rc6" 1
|
||||
if grep -qi 'mktemp failed' "$ERR6"; then r6msg=yes; else r6msg=no; fi
|
||||
check T6-mktemp-failure-loud "$r6msg" yes
|
||||
rm -f "$ERR6" "$SUT2"
|
||||
|
||||
printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ]
|
||||
|
||||
Reference in New Issue
Block a user