bd-audit-ids: deleted means a deletion git will record
improvise-cota, found in the delta review of #244. The tdfd fix skipped an
absent tracked path whenever `ls-files -d` listed it. `ls-files -d` also
lists an absent --assume-unchanged path. `status` hides that path, and
`commit -a` never records the deletion, so its citations stayed in HEAD
unread and the audit exited 0.
The deletion oracle is now `diff --name-only --diff-filter=D`. It honours
both index flags and still lists a plain unstaged delete.
The new case in bd-audit-ids-test.sh was red at 33d563a9. A rival that
treats every absent path as unread fails only the deliberate
deleted-file control.
Stacked on #244 (tooling/lqs0-audit-exits).
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:
@@ -919,3 +919,32 @@ 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.
|
||||
|
||||
### Deleted means git will record it — `scripts/bd-audit-ids-test.sh` (improvise-cota)
|
||||
|
||||
**What broke.** The tdfd fix above asked `git ls-files -d` whether an absent path
|
||||
was deleted. `ls-files -d` also lists an absent path marked
|
||||
`--assume-unchanged`. But `git status` shows nothing for that path, and
|
||||
`commit -a` would never record the deletion, so its citations stay in `HEAD`.
|
||||
The audit skipped the file and exited 0. This is the tdfd shape again: absent,
|
||||
not a deletion git will record, and never read. It was found in the delta
|
||||
review of PR #244 at `33d563a9`.
|
||||
|
||||
**Fix, the reviewer's oracle.** A path counts as deleted only when
|
||||
`git diff --name-only --diff-filter=D` lists it. That compares the index
|
||||
with the working tree and honours both index flags: it hides a
|
||||
skip-worktree path and an assume-unchanged path alike, and lists a plain
|
||||
unstaged delete. A staged `git rm` never reaches the question, because the path
|
||||
has already left the index that `ls-files --cached` enumerates.
|
||||
|
||||
**Red first.** "an assume-unchanged file missing from the tree is exit 4, and
|
||||
named" exited 0 against `33d563a9`, reporting "all 1 cited ids resolve".
|
||||
|
||||
**Rivals.**
|
||||
- The `ls-files -d` oracle, which is the red state above.
|
||||
- Every absent path reported as unread (`elif true`). It fails "a tracked file
|
||||
deleted from the working tree is not scanned" and nothing else, so the
|
||||
deliberate skip of a real deletion survives the stricter oracle.
|
||||
|
||||
This rival was edited in place in the worktree script, not copied to `/tmp`, for
|
||||
the reason the tdfd entry gives.
|
||||
|
||||
@@ -13,8 +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 or is absent (only a file `git ls-files -d`
|
||||
reports as deleted is skipped)
|
||||
could not be read or is absent (only a file `git diff
|
||||
--diff-filter=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"
|
||||
@@ -43,13 +43,13 @@ top=$(git rev-parse --show-toplevel 2>/dev/null) || {
|
||||
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).
|
||||
# A deleted tracked file is skipped ON PURPOSE: its ids are leaving the tree. Only
|
||||
# `diff --diff-filter=D` says deleted; any other absent path is exit 4 (tdfd, cota).
|
||||
: > "$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
|
||||
elif [ -z "$(git --literal-pathspecs diff --name-only --diff-filter=D -- "$f")" ]; then
|
||||
printf '%s\n' "$f" >> "$work/absent"
|
||||
fi
|
||||
done > "$work/files"
|
||||
|
||||
@@ -132,6 +132,18 @@ git -C "$r2" update-index --no-skip-worktree context/b.md
|
||||
&& 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")"
|
||||
|
||||
# ls-files -d DOES list an absent assume-unchanged path, yet status hides it and
|
||||
# commit -a never records the deletion (improvise-cota).
|
||||
git -C "$r2" update-index --assume-unchanged 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-assume-unchanged context/b.md
|
||||
[ "$got" = 4 ] && grep -q 'context/b.md' "$work/out" \
|
||||
&& ok "an assume-unchanged file missing from the tree is exit 4, and named" \
|
||||
|| bad "an assume-unchanged 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