diff --git a/.gitignore b/.gitignore index b672072e..2bf2a0f5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ regression.out .pgc_source_stamp.* __pycache__/ *.pyc + +# Git bundles. A transfer artifact, not a build one: they are how a change gets from +# a container to a clone, they are named after whatever branch was in flight, and +# nothing ever reads them again. Nine of them rode into c697c8cd under `git add -A`. +*.bundle diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f0ed23..e6c003c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1979,6 +1979,39 @@ true until the next version shipped. than replace it, so each renamed line still matches its own old form. Anchoring on the closing quote gives 1, which is the one that matters. +- Nine git bundles are out of the tree, `*.bundle` is ignored, and + `310-a-compiled-artifact-must-not-be.sh` now covers transfer artifacts as well as + compiled ones. + + **I put them there.** 76,194 bytes across nine files went into `c697c8cd` -- a merged + commit whose subject is a check name in `sorted_pathkeys.sh`. I create bundles in my clone + to move a branch into the audit container, and I staged with `git add -A`. That is the + same mechanism the existing comment in part 310 calls out for a stray `.pyc`: *a tracked + build artifact joins whichever commit is next.* + + **Nothing caught it.** Five suites and the whole selftest ran green either side, because + no suite has an opinion about files it does not read. What found it was a later rebase + printing the filenames in a list I happened to read. + + Part 310's scope note said Python only, and deferred the wider question: + + > Whether every derived file in the tree deserves one rule is a larger judgement and is + > deliberately not decided here. + + This decides it for one more class, and only that class. **A bundle is a transfer + artifact**, which is why it belongs beside the `.pyc` rather than beside the Parquet + fixtures: it is derived from commits already in the history, it is named after whatever + branch was in flight, nothing in the tree opens one, and the next person to make one will + choose a different name -- so it can never become a fixture anything depends on. + + Same two-part rule, same `no-repo` discipline as the Python arms, and a control: a source + file merely *named* like a bundle (`test/bundle_notes.sh`) must not be ignored, or the + suffix rule is broader than it claims. + + The blobs stay reachable in the repository's history -- removing a file from the tree does + not unwrite it, and rewriting `main` is not something a stray artifact justifies. What this + stops is the tree carrying them, and the next `git add -A` re-adding them. + ## [1.0-alpha3] - 2026-09-02 ### Added diff --git a/b983.bundle b/b983.bundle deleted file mode 100644 index 8842e06b..00000000 Binary files a/b983.bundle and /dev/null differ diff --git a/b983r.bundle b/b983r.bundle deleted file mode 100644 index 3cfac2ea..00000000 Binary files a/b983r.bundle and /dev/null differ diff --git a/b990.bundle b/b990.bundle deleted file mode 100644 index ff52307e..00000000 Binary files a/b990.bundle and /dev/null differ diff --git a/b991.bundle b/b991.bundle deleted file mode 100644 index 006d4719..00000000 Binary files a/b991.bundle and /dev/null differ diff --git a/b993r2.bundle b/b993r2.bundle deleted file mode 100644 index d5aba8fb..00000000 Binary files a/b993r2.bundle and /dev/null differ diff --git a/b995.bundle b/b995.bundle deleted file mode 100644 index 2b5ee77f..00000000 Binary files a/b995.bundle and /dev/null differ diff --git a/b997r.bundle b/b997r.bundle deleted file mode 100644 index 4967e66c..00000000 Binary files a/b997r.bundle and /dev/null differ diff --git a/b998.bundle b/b998.bundle deleted file mode 100644 index c7eaada6..00000000 Binary files a/b998.bundle and /dev/null differ diff --git a/b998b.bundle b/b998b.bundle deleted file mode 100644 index b1bc8b89..00000000 Binary files a/b998b.bundle and /dev/null differ diff --git a/test/check_ledger.tsv b/test/check_ledger.tsv index 755ed3ed..8511e774 100644 --- a/test/check_ledger.tsv +++ b/test/check_ledger.tsv @@ -244,9 +244,13 @@ harness_selftest 300-a-test-script-must-be-runnable premise: the documents name harness_selftest 300-a-test-script-must-be-runnable premise: the sourced parts are inside the population, not pruned never - harness_selftest 300-a-test-script-must-be-runnable premise: the sweep reads a population of scripts, not an empty find never - harness_selftest 310-a-compiled-artifact-must-not-be and a compiled artifact written beside its source never - +harness_selftest 310-a-compiled-artifact-must-not-be and the tracked BUNDLE list names none of them never - harness_selftest 310-a-compiled-artifact-must-not-be and the tracked list names none of them never - +harness_selftest 310-a-compiled-artifact-must-not-be and the tree ignores a git bundle, so the next add cannot re-add it never - harness_selftest 310-a-compiled-artifact-must-not-be and the tree ignores the directory Python writes them to never - +harness_selftest 310-a-compiled-artifact-must-not-be control: a source file named like a bundle is not ignored never - harness_selftest 310-a-compiled-artifact-must-not-be no compiled Python artifact is tracked never - +harness_selftest 310-a-compiled-artifact-must-not-be no git bundle is tracked never - harness_selftest 310-a-compiled-artifact-must-not-be premise: and git ls-files sees the harness it is being asked about never - harness_selftest 310-a-compiled-artifact-must-not-be premise: and that a tracked source file is not never - harness_selftest 310-a-compiled-artifact-must-not-be premise: check-ignore agrees a build object is already ignored never - diff --git a/test/check_ledger_budget.txt b/test/check_ledger_budget.txt index 05cd37ff..762e8b5d 100644 --- a/test/check_ledger_budget.txt +++ b/test/check_ledger_budget.txt @@ -34,4 +34,4 @@ suites_not_covered 250 # Without that it is a hand-maintained count that drifts, which is the failure # this repository has spent a day proving. It is not a ceiling; it is a # measurement that must be true. -checks_never_observed_red 909 +checks_never_observed_red 913 diff --git a/test/selftest/310-a-compiled-artifact-must-not-be.sh b/test/selftest/310-a-compiled-artifact-must-not-be.sh index 9c75b34a..4cb09579 100644 --- a/test/selftest/310-a-compiled-artifact-must-not-be.sh +++ b/test/selftest/310-a-compiled-artifact-must-not-be.sh @@ -50,11 +50,27 @@ # writes a one-line gitfile into the build dir, which # costs no bytes and makes the question answerable. ok # -# SCOPE. Python only. The tree tracks Iceberg .avro/.puffin and Parquet -# fixtures, which are inputs rather than output and are meant to be there; -# .gitignore already covers the C artifacts (*.o, *.so, *.bc). Whether every -# derived file in the tree deserves one rule is a larger judgement and is -# deliberately not decided here. +# SCOPE. Python artifacts, and git bundles. The tree tracks Iceberg +# .avro/.puffin and Parquet fixtures, which are inputs rather than output and are +# meant to be there; .gitignore already covers the C artifacts (*.o, *.so, *.bc). +# Whether every derived file deserves one rule is still a larger judgement and is +# still not decided here. +# +# THE SECOND CLASS WAS ADDED THE SAME WAY AS THE FIRST: expensively. Nine git +# bundles, 76,194 bytes, went into c697c8cd -- a merged commit whose subject is a +# check name in sorted_pathkeys.sh. I made them in my clone to move a branch into a +# container and then staged with `git add -A`, which is the same mechanism the +# comment above calls out for the .pyc: a tracked artifact joins whichever commit is +# next. Nothing caught it. Five suites and the whole selftest ran green either side, +# because no suite has any opinion about files it does not read. +# +# A BUNDLE IS A TRANSFER ARTIFACT, which is why it belongs with the .pyc and not +# with the Parquet fixtures. It is derived from commits that are already in the +# history, it is named after whatever branch was in flight, nothing in the tree +# opens one, and the next person to make one will give it a different name -- so it +# can never be a fixture somebody depends on. The same two-part rule therefore +# applies: not tracked, and ignored, because ignoring is what stops the deletion +# being undone by the next `git add -A`. _pyc_root="$(cd "$PGC_TESTDIR/.." && pwd)" _pyc_repo="$(git -C "$_pyc_root" rev-parse --is-inside-work-tree 2>/dev/null || echo no)" @@ -71,6 +87,11 @@ _pyc_ignored() { # _pyc_ignored PATH -> ignored | not-ignored | no-repo git -C "$_pyc_root" check-ignore -q -- "$1" && echo ignored || echo not-ignored } +_pyc_bundles() { # -> the tracked git bundles, or `no-repo` + [ "$_pyc_repo" = true ] || { printf 'no-repo'; return; } + git -C "$_pyc_root" ls-files -- '*.bundle' | sort | tr '\n' ' ' +} + # PREMISE. git has to be able to answer, and it has to be answering about THIS # tree. check_text "premise: the source tree is a git checkout" "$_pyc_repo" "true" @@ -122,5 +143,36 @@ check_text "and the tree ignores the directory Python writes them to" \ check_text "and a compiled artifact written beside its source" \ "$(_pyc_ignored test/x.pyc)" "ignored" -unset _pyc_root _pyc_tracked _pyc_repo -unset -f _pyc_tracked_list _pyc_ignored +# ---- and a transfer artifact is the same rule, for the same reason ------------ + +# Counted rather than compared against an empty string: `check_text` refuses a side +# that is empty, because "nothing was compared" and "the two agreed" are the same +# observation otherwise. My first version of these three arms compared against "" and +# all three were refused on exactly that ground -- the harness catching an arm that +# asserted nothing. +_pyc_bund="$(_pyc_bundles)" +check_text "no git bundle is tracked" \ + "$([ "$_pyc_bund" = no-repo ] && echo no-repo \ + || printf '%s tracked' "$(printf '%s' "$_pyc_bund" | wc -w)")" \ + "0 tracked" +# Named for the thing it lists, not "them": the Python half four arms up already owns +# `and the tracked list names none of them`, and the ledger's duplicate-name detector +# caught the collision on the first merge -- `distinct checks this merge=866` against +# `checks run=867`. #982's defect, created in the session that finished removing the +# last of its 24 instances. +check_text "and the tracked BUNDLE list names none of them" \ + "[${_pyc_bund}]" "[]" + +# The other half, as for the .pyc: without the ignore rule the deletion lasts until +# the next `git add -A` in a clone where somebody has moved a branch about. +check_text "and the tree ignores a git bundle, so the next add cannot re-add it" \ + "$(_pyc_ignored some-branch.bundle)" "ignored" + +# CONTROL. The rule keys on the SUFFIX, so a source file merely named like one must +# not be swept up -- and without this, a check-ignore answering "ignored" to +# everything would make the arm above vacuous. +check_text "control: a source file named like a bundle is not ignored" \ + "$(_pyc_ignored test/bundle_notes.sh)" "not-ignored" + +unset _pyc_root _pyc_tracked _pyc_repo _pyc_bund +unset -f _pyc_tracked_list _pyc_ignored _pyc_bundles