A directory that was emptied for good is not a directory that might refill - #29
Merged
Conversation
…efill `paths.py` skips a trailing-slash directory claim when the parent is tracked, because git stores files and not directories, so an empty one is indistinguishable from an absent one. The reason is real: posthog-python's RELEASING.md says changesets live in `.sampo/changesets/`, and every release empties that directory as the bot consumes them. The guard's own comment claimed the tracked-parent requirement "keeps the case this must still catch: a documented directory whose entire tree really did go". It keeps none of them. A removed SUBdirectory of a live tree has a tracked parent too - toolhive documents `pkg/container/verifier/` for Sigstore verification, `pkg/container` is alive, and `verifier` went in 7095e8e1 "Remove /verifier in favour of one coming from toolhive-core". Measured over the 47 clones of batches 10 and 11, every --show-skips run captured to disk: 38 directory claims silenced, 31 never tracked at all and the guard right about every one, 7 populated and wholly emptied across toolhive, hive, onyx and openmed. So the skip keeps its reason and gains a receipt, which is the soundness rule the rest of the verifier already runs on. `Git.emptied_and_stayed` replays the paths OLDEST FIRST and counts how many times the live set falls to empty; once means it stayed empty, more than once is a lifecycle. The forwards replay is not incidental. The first version of the measurement walked newest-first and called it a refill at the first add after a delete - but an add seen later in a newest-first walk is older, so every directory created before it was deleted scored as churn. That run reported ZERO emptied directories and nothing about the output looked wrong. Caught only because one case had been verified by hand first. The posthog test moved to tests/test_emptied_directory.py and now builds a real fill-consume-fill-consume history, because the old fixture committed one file and deleted it once, which is not what a changeset directory does. Also checked against the live repository: emptied_and_stayed returns None there. 215 tests. Verified on the real toolhive clone: 13 findings to 15, both new ones naming the commit that removed the subsystem.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
paths.pyskips a trailing-slash directory claim when the parent is tracked, because git stores files and not directories, so an empty directory is indistinguishable from an absent one. The reason is real -PostHog/posthog-python's RELEASING.md says changesets live in.sampo/changesets/, and every release empties it as the bot consumes them. The sentence says wheresampo addPUTS files.The guard's own comment then claims the tracked-parent requirement "keeps the case this must still catch: a documented directory whose entire tree really did go".
It keeps none of them. A removed subdirectory of a live tree has a tracked parent too.
pkg/containeris alive and documented.verifieris gone. The tool said nothing - two lines under a finding on the same paragraph that it did report.Measured
Every
--show-skipsrun over the 47 clones of sweep batches 10 and 11, captured to disk rather than sampled:The 7 are in four repositories: toolhive x2, hive x2, onyx x2, openmed x1. The churning shape the guard exists for does not appear in these 47, though it is real -
composio/.changesethas it, and the test suite builds it.The fix
The skip keeps its reason and gains a receipt, which is the soundness rule the rest of this verifier already runs on: a path is called broken only when the repository can be shown to have HAD it and dropped it.
Git.emptied_and_stayedreplays the paths oldest first and counts how many times the live set falls to empty. Once means it stayed empty. More than once is a lifecycle and stays skipped.The replay direction is not incidental
The first version of the measurement walked newest-first, set a flag on the first
D, and called it a refill at the nextA. AnAseen later in a newest-first walk is older, so every directory that was created before it was deleted scored as churn - which is all of them. That run reported:Zero emptied. Nothing about that output looks wrong, and it is the exact opposite of the truth. It was caught only because one case had been verified by hand first, which is the argument for checking a new measurement against a known answer before believing its totals.
Tests
The posthog case moved to
tests/test_emptied_directory.pyand now builds a real fill-consume-fill-consume history. The old fixture committed one file and deleted it once, which is not what a changeset directory does - so it asserted the posthog verdict over a history posthog does not have. Also checked against the live repository:emptied_and_stayedreturns None for.sampo/changesetsthere.215 tests. Verified end to end on the real toolhive clone: 13 findings to 15, both new ones naming the commit that removed the subsystem.