Files
improvise/scripts/bd-audit-ids
T
Edward Langley acecc63dff bd-audit-ids: only ls-files -d says deleted; other absent paths are exit 4 (tdfd)
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
2026-09-23 11:14:24 -07:00

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 ' ')"