acecc63dff
A skip-worktree or sparse path is absent without being deleted, and the filter skipped it, so its ids were never read and the audit passed. The xargs comment no longer claims 124, which is GNU only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
106 lines
3.8 KiB
Bash
Executable File
106 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# The dead-ID audit: every improvise-<id> the tree cites must be a ticket bd
|
|
# knows. See AGENTS.md, "Cite a ticket ID you have read back" (improvise-52eq).
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat >&2 <<'EOF'
|
|
usage: bd-audit-ids
|
|
|
|
Run from anywhere inside the repository. Takes no arguments.
|
|
|
|
exit 0 every cited id is a ticket bd lists
|
|
exit 1 at least one cited id is not; each is printed
|
|
exit 3 bd could not answer: missing, failing, or listing nothing
|
|
exit 4 usage error, not inside a git repository, or a cited file
|
|
could not be read or is absent (only a file `git ls-files -d`
|
|
reports as deleted is skipped)
|
|
|
|
The comparison is POSITIVE: a cited id passes only by appearing in what
|
|
`bd list --all` returns. The recipe this replaced looked for bd's "not found"
|
|
lines and reported "all resolve" when there were none, so a bd that never ran
|
|
read as a clean audit.
|
|
|
|
THIS SCRIPT'S `$?` MUST BE THE ONE YOU READ. Nothing may follow it in the same
|
|
pipeline or `;` list.
|
|
EOF
|
|
exit 4
|
|
}
|
|
[ $# -eq 0 ] || usage
|
|
|
|
BD="${BD_AUDIT_BD:-bd}"
|
|
ROOTS=(context README.md AGENTS.md CLAUDE.md crates src tests examples web
|
|
harness docs .agents .claude)
|
|
# Crate, package, artifact and file names that are shaped like ids. Anchored,
|
|
# because an unanchored `gp` would silently exclude any real ticket id starting with it.
|
|
EXCLUDE='^improvise-(core|formula|io|protocol|command|gp|ws|worker|wasm|harness|registry|report|side|web)$'
|
|
|
|
work=$(mktemp -d)
|
|
trap 'rm -rf "$work"' EXIT
|
|
|
|
top=$(git rev-parse --show-toplevel 2>/dev/null) || {
|
|
echo "bd-audit-ids: not inside a git repository, so nothing was checked." >&2
|
|
exit 4
|
|
}
|
|
cd "$top"
|
|
# A deleted tracked file is skipped ON PURPOSE: its ids are leaving the tree.
|
|
# Only `ls-files -d` says deleted; any other absent path is exit 4 (lqs0, tdfd).
|
|
: > "$work/absent"
|
|
git ls-files -z --cached --others --exclude-standard -- "${ROOTS[@]}" |
|
|
while IFS= read -r -d '' f; do
|
|
if [ -e "$f" ] || [ -L "$f" ]; then printf '%s\0' "$f"
|
|
elif [ -z "$(git --literal-pathspecs ls-files -d -- "$f")" ]; then
|
|
printf '%s\n' "$f" >> "$work/absent"
|
|
fi
|
|
done > "$work/files"
|
|
if [ -s "$work/absent" ]; then
|
|
echo "bd-audit-ids: tracked but absent, and not deleted, so never read:" >&2
|
|
sed 's/^/ /' "$work/absent" >&2
|
|
exit 4
|
|
fi
|
|
|
|
# xargs reports grep's no-match (1) and its read error (2) alike, as 123, so
|
|
# each batch maps 1 to success and 2 to 255: xargs stops, nonzero (GNU 124, BSD 1).
|
|
: > "$work/raw"
|
|
set +e
|
|
if [ -s "$work/files" ]; then
|
|
xargs -0 bash -c 'grep -d skip -ohE "$0" "$@"; [ $? -le 1 ] || exit 255' \
|
|
'improvise-[a-z0-9]{3,8}\b' < "$work/files" > "$work/raw"
|
|
fi
|
|
rc=$?
|
|
set -e
|
|
[ "$rc" -eq 0 ] || {
|
|
echo "bd-audit-ids: a cited file could not be read (xargs $rc), so the audit is incomplete." >&2
|
|
exit 4
|
|
}
|
|
sort -u "$work/raw" | { grep -vE "$EXCLUDE" || true; } > "$work/cited"
|
|
|
|
if ! command -v "$BD" >/dev/null 2>&1; then
|
|
echo "bd-audit-ids: '$BD' is not on PATH, so nothing was checked." >&2
|
|
exit 3
|
|
fi
|
|
if ! "$BD" list --all --limit 0 --json > "$work/known.json" 2> "$work/bd.err"; then
|
|
echo "bd-audit-ids: '$BD list' failed, so nothing was checked:" >&2
|
|
cat "$work/bd.err" >&2
|
|
exit 3
|
|
fi
|
|
if ! jq -e 'type == "array" and all(.[]; (.id | type) == "string")' \
|
|
"$work/known.json" > /dev/null 2>&1; then
|
|
echo "bd-audit-ids: '$BD list' did not print a JSON list of issues with ids." >&2
|
|
exit 3
|
|
fi
|
|
jq -r '.[].id' "$work/known.json" | sort -u > "$work/known"
|
|
if [ ! -s "$work/known" ]; then
|
|
echo "bd-audit-ids: '$BD list' returned no issues; refusing to call that a pass." >&2
|
|
exit 3
|
|
fi
|
|
|
|
comm -23 "$work/cited" "$work/known" > "$work/dead"
|
|
if [ -s "$work/dead" ]; then
|
|
echo "bd-audit-ids: cited but not a ticket bd knows:"
|
|
sed 's/^/ /' "$work/dead"
|
|
exit 1
|
|
fi
|
|
printf 'bd-audit-ids: all %d cited ids resolve (bd knows %d)\n' \
|
|
"$(wc -l < "$work/cited" | tr -d ' ')" "$(wc -l < "$work/known" | tr -d ' ')"
|