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
This commit is contained in:
@@ -894,3 +894,28 @@ case passed before and after.
|
||||
|
||||
The `chmod 000` case is skipped when the suite runs as root, where the file
|
||||
stays readable. The dangling-symlink case covers the same path for every user.
|
||||
|
||||
### Absent is not deleted — `scripts/bd-audit-ids-test.sh` (improvise-tdfd)
|
||||
|
||||
**What broke.** The file filter `[ -e "$f" ] || [ -L "$f" ]` dropped every
|
||||
tracked path missing from the tree, and took each one to be a deletion. A path
|
||||
marked `--skip-worktree` (or left out by a sparse checkout) is absent too, but
|
||||
it is not deleted. Its ids were never read, and the audit passed. ChatGPT
|
||||
Codex found this on PR #244. The adversarial review reproduced it with
|
||||
`context/adr/001-concurrent-edits.md`, the only citation of one id: exit 1 → 0.
|
||||
|
||||
**Fix, Codex's suggestion.** An absent path is skipped only when
|
||||
`git ls-files -d` lists it. Any other absent tracked path is exit 4, and the
|
||||
path is named. The xargs comment no longer claims 124. That is GNU; BSD exits
|
||||
1. The script tests nonzero, so both work.
|
||||
|
||||
**Red first.** "a skip-worktree file missing from the tree is exit 4, and
|
||||
named" exited 0 against the pre-fix script, reporting "all 1 cited ids
|
||||
resolve".
|
||||
|
||||
**Rival:** every absent path reported as unread (the `ls-files -d` test
|
||||
removed). It fails "a tracked file deleted from the working tree is not
|
||||
scanned" alone, so the deleted-file case is what stops the fix from
|
||||
over-refusing. The rival ran from an ignored copy inside the worktree. A copy
|
||||
under `/tmp` fails "the real tree does not pass against a silent bd" for a
|
||||
reason unrelated to the rival: there is no repository there.
|
||||
|
||||
+15
-5
@@ -13,7 +13,8 @@ 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 (a tracked file deleted from the tree is skipped)
|
||||
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"
|
||||
@@ -42,15 +43,24 @@ top=$(git rev-parse --show-toplevel 2>/dev/null) || {
|
||||
exit 4
|
||||
}
|
||||
cd "$top"
|
||||
# A tracked file deleted from the working tree is left out ON PURPOSE: its ids
|
||||
# are leaving the tree. Anything else grep cannot read is exit 4 (improvise-lqs0).
|
||||
# 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"; fi
|
||||
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, which makes xargs stop with 124.
|
||||
# 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
|
||||
|
||||
@@ -120,6 +120,18 @@ mv "$work/b.md.away" "$r2/context/b.md"
|
||||
[ "$got" = 0 ] && ok "a tracked file deleted from the working tree is not scanned" \
|
||||
|| bad "a tracked file deleted from the working tree is not scanned" "exit $got: $(head -c 200 "$work/out")"
|
||||
|
||||
# Absent is not deleted: a skip-worktree path is missing too, but ls-files -d
|
||||
# does not list it, so its ids were never read (improvise-tdfd).
|
||||
git -C "$r2" update-index --skip-worktree context/b.md
|
||||
mv "$r2/context/b.md" "$work/b.md.away"
|
||||
(cd "$r2" && "$AUDIT") > "$work/out" 2>&1
|
||||
got=$?
|
||||
mv "$work/b.md.away" "$r2/context/b.md"
|
||||
git -C "$r2" update-index --no-skip-worktree context/b.md
|
||||
[ "$got" = 4 ] && grep -q 'context/b.md' "$work/out" \
|
||||
&& ok "a skip-worktree file missing from the tree is exit 4, and named" \
|
||||
|| bad "a skip-worktree file missing from the tree is exit 4, and named" "exit $got: $(head -c 200 "$work/out")"
|
||||
|
||||
mkdir -p "$work/not-a-repo"
|
||||
(cd "$work/not-a-repo" && GIT_CEILING_DIRECTORIES="$work" "$AUDIT") > "$work/out" 2>&1
|
||||
got=$?
|
||||
|
||||
Reference in New Issue
Block a user