Cap artifact growth instead of recommending a future prune

The prune commit's evidence noted that "a recurring prune or a hard cap
would be the durable fix if this recurs" - which is advice, not a fix. The
tree would have regrown at one artifact per commit and been noticed months
later, exactly as it was this time.

check_repo_size.sh now caps evidence/ and contracts/ at 60 files each: the
headroom the prune bought, against 21 today. main accumulates failures
rather than returning on the first, so tripping both the source ceiling and
the artifact cap reports both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
This commit is contained in:
Krzysztof Rudnicki 2026-08-23 19:33:53 +02:00
parent 7597831915
commit f8f81ecac0
2 changed files with 78 additions and 2 deletions

View File

@ -0,0 +1,37 @@
{
"intent": "Stop the superpowers bookkeeping tree from silently regrowing to the 695 files that made a 655-file prune necessary, by capping it in the gate instead of leaving a note recommending it.",
"scope": [
"meta/scripts/check_repo_size.sh - adds a per-directory artifact cap",
"Non-goal: changing the source-file ceiling or the excluded prefixes, both unchanged."
],
"changes": [
"Added ARTIFACT_DIRS + MAX_ARTIFACTS_PER_DIR=60, checked by a new check_artifact_dirs helper wired into main alongside the existing source-file ceiling.",
"main now accumulates failures rather than returning on the first, so a commit that trips both the source ceiling and the artifact cap reports both.",
"60 is the headroom the prune bought (21 files per dir today). The header says to prune rather than raise it when it fails."
],
"verification": [
{
"command": "./meta/scripts/check_repo_size.sh",
"result": "pass",
"evidence": "'1050 source files (ceiling 1200)' EXIT=0 with evidence/contracts at 21 each, under the 60 cap. --count still prints the bare number, EXIT=0."
},
{
"command": "MAX_ARTIFACTS_PER_DIR=5 variant",
"result": "pass",
"evidence": "EXIT=1 listing BOTH dirs (evidence 22, contracts 21) plus the prune hint - confirms the new branch fires and that it does not stop at the first offender."
},
{
"command": "pre-commit run repo-size-cap --all-files; pre-commit run --files meta/scripts/check_repo_size.sh",
"result": "pass",
"evidence": "Hook Passed; shfmt and shellcheck clean on the modified script."
}
],
"risks": [
"A legitimate burst of commits can now trip the cap and block a commit until artifacts are pruned. That is the intended trade: the previous behaviour was unbounded growth noticed only months later.",
"The cap counts tracked files per directory, so it does not distinguish a needed recent artifact from an old one; the operator chooses what to prune."
],
"rollback": [
"git revert the commit; the source-file ceiling and all other behaviour are untouched by this change.",
"After rollback, confirm ./meta/scripts/check_repo_size.sh still exits 0 and prints the source count."
]
}

View File

@ -24,10 +24,15 @@
# The count is always printed, so the threshold can be audited from any CI log
# rather than being taken on trust.
#
# The generated trees are excluded from that count but capped separately: they
# grow about one file per commit, which is what made a 655-file prune
# necessary in the first place. Capping them here means the next overflow
# fails a commit instead of being noticed months later.
#
# 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.
# Exits 0 when at or under every ceiling, 1 when over any of them.
# ============================================================================
set -euo pipefail
@ -45,6 +50,16 @@ readonly EXCLUDED_PREFIXES=(
.hippo/
)
# Per-commit bookkeeping. Pruned to 20 each (plus a template) on 2026-08-23;
# the cap is the headroom that prune bought, so the tree cannot silently
# return to the 695 files it held before. When this fails, prune - do not
# raise it.
readonly ARTIFACT_DIRS=(
docs/superpowers/evidence
docs/superpowers/contracts
)
readonly MAX_ARTIFACTS_PER_DIR=60
COUNT_ONLY=0
usage() {
@ -68,6 +83,24 @@ source_files() {
git ls-files | grep -v "${filter[@]}" || true
}
# Fail when a bookkeeping directory has grown past its cap. Reports every
# offending directory rather than stopping at the first.
check_artifact_dirs() {
local dir n over=0
for dir in "${ARTIFACT_DIRS[@]}"; do
n="$(git ls-files "$dir" | wc -l)"
if ((n > MAX_ARTIFACTS_PER_DIR)); then
echo "check_repo_size: $dir holds $n files, over the $MAX_ARTIFACTS_PER_DIR cap" >&2
over=1
fi
done
((over)) && {
echo "Prune the oldest artifacts; they stay available in git history." >&2
return 1
}
return 0
}
main() {
local count
count="$(source_files | wc -l)"
@ -77,12 +110,18 @@ main() {
return 0
fi
local failed=0
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
failed=1
fi
check_artifact_dirs || failed=1
((failed)) && return 1
echo "check_repo_size: $count source files (ceiling $MAX_SOURCE_FILES)"
return 0
}