testsAndMisc/meta/scripts/check_repo_size.sh
Krzysztof kuhy Rudnicki 0a1e43fc11 Wire the depth and size gates, exempting structural depth
The depth cap had 104 violations. 57 are structural: whole projects with
their own layout (C/, dwm/, artgate/), a tool split into modules to satisfy
the line cap, prose trees, and directories whose name an external format
dictates (systemd, hooks, workflows, patches, fixtures). Those are exempted
the same way lib/ and tests/ already were.

The other 47 all sit under periodic_background/{hosts,digital_wellbeing},
which can only come down by extracting those units - blocked on a manual
guard repoint. So the hook runs --warn: the number stays visible on every
commit without blocking unrelated work. Enforcement is one flag away.

Also guards the argument order: `--all --warn` used to ignore --warn and
exit 1, which as a hook entry would have blocked every commit.

check_repo_size.sh is the companion gate - depth stops one subtree growing
a taxonomy, this stops the repo absorbing everything. It counts tracked
files (git ls-files, never find: the tree holds ~30k untracked extraction
leftovers) minus vendored and hook-generated trees: 1049 against a 1200
ceiling, printed every run so the threshold is auditable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
2026-08-23 19:26:16 +02:00

107 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# ============================================================================
# Enforce a ceiling on the number of source files in the repo.
#
# The companion to the directory-depth cap. Depth stops any one subtree from
# growing its own taxonomy; this stops the repo as a whole from quietly
# becoming the place everything lands. When the count reaches the ceiling the
# answer is to extract a unit into its own repository - not to raise the
# number because the commit is inconvenient.
#
# "Source" means tracked files that a human wrote and maintains here. Three
# categories are therefore excluded from the count:
#
# third_party/ vendored; upstream decides how many files it has
# docs/superpowers/ hook-generated evidence/contract bookkeeping, which
# grows once per commit and would dominate the number
# .hippo/ agent-generated store, same argument
#
# Counting is done with `git ls-files`, never `find`: the working tree also
# holds untracked extraction leftovers running to tens of thousands of files,
# and a `find`-based count would be meaningless.
#
# The count is always printed, so the threshold can be audited from any CI log
# rather than being taken on trust.
#
# check_repo_size.sh # count and enforce
# check_repo_size.sh --count # print the number only, always exit 0
#
# Exits 0 when at or under the ceiling, 1 when over.
# ============================================================================
set -euo pipefail
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
# Set from the 1049 files counted when this gate was written, plus room to
# work. Extract a unit rather than raising it; see the header.
readonly MAX_SOURCE_FILES=1200
readonly EXCLUDED_PREFIXES=(
third_party/
docs/superpowers/
.hippo/
)
COUNT_ONLY=0
usage() {
echo "Usage: $SCRIPT_NAME [--count]"
echo "Options:"
echo " --count Print the source-file count and exit 0"
echo " -h, --help Show this help"
echo
echo "Fails when tracked source files exceed $MAX_SOURCE_FILES."
exit 0
}
# Tracked files minus the generated and vendored trees. Printed one per line.
source_files() {
local -a filter=()
local prefix
for prefix in "${EXCLUDED_PREFIXES[@]}"; do
filter+=(-e "^${prefix}")
done
# grep exits 1 when it filters everything out; that is not an error here.
git ls-files | grep -v "${filter[@]}" || true
}
main() {
local count
count="$(source_files | wc -l)"
if ((COUNT_ONLY)); then
echo "$count"
return 0
fi
if ((count > MAX_SOURCE_FILES)); then
echo "check_repo_size: $count source files, over the $MAX_SOURCE_FILES ceiling" >&2
echo "Extract a unit into its own repo rather than raising the cap." >&2
return 1
fi
echo "check_repo_size: $count source files (ceiling $MAX_SOURCE_FILES)"
return 0
}
while [[ $# -gt 0 ]]; do
case "$1" in
-h | --help)
usage
;;
--count)
COUNT_ONLY=1
shift
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
main