Files
ObsidianDragon/scripts/check-source-hygiene.sh
DanS a78a13edf3 docs(lite): add v2 implementation plan, source-hygiene guard, and CLAUDE.md
- docs/lite-wallet-implementation-plan-v2-2026-06-04.md: vertical-slice plan that
  supersedes the v1 plan (now banner-marked); carries over the inherited artifact/
  signing/phase-2 design docs for reference.
- scripts/check-source-hygiene.sh: pre-commit/CI guard rejecting >80-char filenames
  and chained churn-token names, to stop the deleted "_plan"/"_batch" scaffolding
  from regrowing.
- CLAUDE.md: repository guidance for future sessions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:15:11 -05:00

57 lines
2.2 KiB
Bash
Executable File

#!/bin/bash
# Source-tree hygiene guard.
#
# Blocks two failure modes that an AI coding session previously introduced in
# src/wallet/ (the lite-wallet "_plan"/"_batch" churn): pathologically long
# filenames (which also break the Windows MAX_PATH 260-char limit during the
# cross-build) and the runaway "receipt/custody/handoff/stewardship" naming
# explosion where each session wrapped the previous artifact in one more layer.
#
# Usage:
# scripts/check-source-hygiene.sh # check working-tree src/
# scripts/check-source-hygiene.sh --staged # check staged files (pre-commit)
#
# Install as a git pre-commit hook:
# ln -sf ../../scripts/check-source-hygiene.sh .git/hooks/pre-commit
# # (the hook invokes it with --staged automatically when named pre-commit)
set -euo pipefail
MAX_LEN=80
# Naming-explosion tokens. Two or more chained in one basename is the smell.
CHURN_RE='receipt|custody|handoff|stewardship|promotion_activation|acceptance_confirmation|archive_handoff|post_closure'
mode="${1:-}"
if [[ "$mode" == "--staged" || "$(basename "$0")" == "pre-commit" ]]; then
mapfile -t files < <(git diff --cached --name-only --diff-filter=AR | grep -E '\.(cpp|h|hpp|cc)$' || true)
else
mapfile -t files < <(git ls-files 'src/**/*.cpp' 'src/**/*.h' 2>/dev/null; \
find src -type f \( -name '*.cpp' -o -name '*.h' \) 2>/dev/null)
# de-dup
mapfile -t files < <(printf '%s\n' "${files[@]}" | sort -u)
fi
fail=0
for f in "${files[@]}"; do
[[ -z "$f" ]] && continue
base="$(basename "$f")"
len=${#base}
if (( len > MAX_LEN )); then
echo "✗ filename too long ($len > $MAX_LEN chars): $f" >&2
fail=1
fi
# count distinct churn tokens in the basename ( || true: grep exits 1 on no match)
n=$(printf '%s' "$base" | grep -oE "$CHURN_RE" | sort -u | wc -l || true)
if (( n >= 2 )); then
echo "✗ runaway naming pattern ($n churn tokens) — refactor in place, don't add a layer: $f" >&2
fail=1
fi
done
if (( fail )); then
echo "" >&2
echo "Source hygiene check failed. See docs in scripts/check-source-hygiene.sh." >&2
exit 1
fi
echo "source hygiene OK (${#files[@]} files checked)"