mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 19:07:04 +01:00
Give the artifact cap a --prune escape hatch
A gate that blocks a commit with no tooling to clear it just moves the problem to whoever hits it. --prune stages the removal of the oldest artifacts, keeping the newest 20 per directory plus the template, and leaves the commit to the operator. Running it caught a bug that reading it would not: sorting on %cs (date only) ties every artifact committed the same day, so sort fell back to the path and the prune deleted alphabetically - it picked one of today's newest files instead of the oldest. Sorts on %ct with -rn now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
This commit is contained in:
parent
17d6b36776
commit
77f2eb9f11
@ -0,0 +1,36 @@
|
||||
{
|
||||
"intent": "Give the artifact cap a one-command fix, so the gate can never block a commit with no way out except reconstructing today's selection logic by hand.",
|
||||
"scope": [
|
||||
"meta/scripts/check_repo_size.sh - adds --prune",
|
||||
"Non-goal: pruning anything now. The tree is at 21/21, well under the 60 cap."
|
||||
],
|
||||
"changes": [
|
||||
"Added --prune: stages the removal of the oldest artifacts, keeping the newest KEEP_ARTIFACTS=20 per directory plus template.json, and leaves the commit to the operator.",
|
||||
"Fixed a same-day ordering bug found by running it: the first version sorted on %cs (date only), so every artifact committed on the same day tied, sort fell back to comparing the path, and the prune deleted alphabetically. It removed cap-artifact-growth-2026-08-23.json - one of the newest files - instead of the oldest. Now sorts on %ct (unix seconds) with sort -rn."
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "./meta/scripts/check_repo_size.sh --prune (in a detached worktree)",
|
||||
"result": "pass",
|
||||
"evidence": "First run staged 2 deletions but they were WRONG: cap-artifact-growth-2026-08-23.json and flatten-linux-configuration-2026-08-23.json, both same-day files chosen alphabetically. This is what exposed the %cs tie."
|
||||
},
|
||||
{
|
||||
"command": "./meta/scripts/check_repo_size.sh --prune after the %ct fix (fresh worktree)",
|
||||
"result": "pass",
|
||||
"evidence": "Now stages quarantine-arch-sysctl-cases-2026-08-22.json and thorium-repairs-tests-2026-08-23.json - the genuinely oldest. Templates survive; contracts correctly reports 'nothing to prune' at 20 + template."
|
||||
},
|
||||
{
|
||||
"command": "./meta/scripts/check_repo_size.sh; pre-commit run --files meta/scripts/check_repo_size.sh",
|
||||
"result": "pass",
|
||||
"evidence": "'1050 source files (ceiling 1200)' EXIT=0; shfmt and shellcheck clean. Tested in a throwaway worktree so the real tree was never modified."
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"--prune stages deletions rather than committing them, so an operator who runs it and forgets to review still has git diff --cached as the checkpoint.",
|
||||
"KEEP_ARTIFACTS=20 is below MAX_ARTIFACTS_PER_DIR=60 on purpose; a prune therefore buys headroom instead of landing back on the limit."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert the commit. --prune is additive and off by default; the enforcing path is unchanged.",
|
||||
"After rollback, confirm ./meta/scripts/check_repo_size.sh still exits 0 and prints the count."
|
||||
]
|
||||
}
|
||||
@ -31,6 +31,11 @@
|
||||
#
|
||||
# check_repo_size.sh # count and enforce
|
||||
# check_repo_size.sh --count # print the number only, always exit 0
|
||||
# check_repo_size.sh --prune # stage the removal of the oldest artifacts
|
||||
#
|
||||
# --prune is the fix when the artifact cap fails: it stages the deletions and
|
||||
# leaves committing to you, so the gate never blocks a commit without a
|
||||
# one-command way out.
|
||||
#
|
||||
# Exits 0 when at or under every ceiling, 1 when over any of them.
|
||||
# ============================================================================
|
||||
@ -60,18 +65,58 @@ readonly ARTIFACT_DIRS=(
|
||||
)
|
||||
readonly MAX_ARTIFACTS_PER_DIR=60
|
||||
|
||||
# What --prune keeps per directory. Below the cap on purpose, so a prune
|
||||
# buys real headroom instead of landing back on the limit.
|
||||
readonly KEEP_ARTIFACTS=20
|
||||
|
||||
COUNT_ONLY=0
|
||||
PRUNE=0
|
||||
|
||||
usage() {
|
||||
echo "Usage: $SCRIPT_NAME [--count]"
|
||||
echo "Usage: $SCRIPT_NAME [--count | --prune]"
|
||||
echo "Options:"
|
||||
echo " --count Print the source-file count and exit 0"
|
||||
echo " --prune git rm the oldest artifacts, keeping the newest"
|
||||
echo " $KEEP_ARTIFACTS per directory plus template.json"
|
||||
echo " -h, --help Show this help"
|
||||
echo
|
||||
echo "Fails when tracked source files exceed $MAX_SOURCE_FILES."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Remove the oldest artifacts, keeping the newest KEEP_ARTIFACTS per
|
||||
# directory plus template.json. Ordered by git commit date rather than by
|
||||
# filename: the corpus mixes -2026-05, -20260604 and undated slugs, so a
|
||||
# filename sort silently mis-orders a chunk of it. Deleted files remain
|
||||
# available in git history.
|
||||
#
|
||||
# The sort key is %ct (unix seconds), NOT %cs (date only). With %cs every
|
||||
# artifact committed on the same day ties, sort falls back to comparing the
|
||||
# path, and the prune deletes alphabetically - which cost the newest file in
|
||||
# a same-day batch when this was first written.
|
||||
prune_artifacts() {
|
||||
local dir removed=0
|
||||
for dir in "${ARTIFACT_DIRS[@]}"; do
|
||||
local -a doomed=()
|
||||
mapfile -t doomed < <(
|
||||
git ls-files "$dir" |
|
||||
grep -v '/template\.json$' |
|
||||
while read -r f; do
|
||||
printf '%s\t%s\n' "$(git log -1 --format=%ct -- "$f")" "$f"
|
||||
done |
|
||||
sort -rn | tail -n "+$((KEEP_ARTIFACTS + 1))" | cut -f2
|
||||
)
|
||||
if ((${#doomed[@]} == 0)); then
|
||||
echo "$dir: nothing to prune"
|
||||
continue
|
||||
fi
|
||||
git rm -q -- "${doomed[@]}"
|
||||
echo "$dir: pruned ${#doomed[@]}, kept $KEEP_ARTIFACTS + template"
|
||||
removed=$((removed + ${#doomed[@]}))
|
||||
done
|
||||
echo "Pruned $removed file(s). Review with 'git diff --cached --stat', then commit."
|
||||
}
|
||||
|
||||
# Tracked files minus the generated and vendored trees. Printed one per line.
|
||||
source_files() {
|
||||
local -a filter=()
|
||||
@ -102,6 +147,11 @@ check_artifact_dirs() {
|
||||
}
|
||||
|
||||
main() {
|
||||
if ((PRUNE)); then
|
||||
prune_artifacts
|
||||
return 0
|
||||
fi
|
||||
|
||||
local count
|
||||
count="$(source_files | wc -l)"
|
||||
|
||||
@ -135,6 +185,10 @@ while [[ $# -gt 0 ]]; do
|
||||
COUNT_ONLY=1
|
||||
shift
|
||||
;;
|
||||
--prune)
|
||||
PRUNE=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
exit 1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user