Refuse an exemption whose anchor no longer names live code, and say which way it rotted - #26
Merged
Merged
Conversation
…hich way it rotted cf-exemptions holds two halves of one contract: every suppression traces to a reasoned entry, AND every entry still points at the code it blessed. Only the first half existed. The matcher flagged an entry covering more than one suppression and tolerated an entry covering NOTHING in silence, and frozen_count ratchets entries rather than live coverage, so the ratchet stayed satisfied. Rename an enclosing def and two wrongs happen at once. The blessed site is accused -- "a self-issued suppression is not an exemption" -- which is convincing and wrong, because the site WAS blessed and the registry pointer is what rotted; that class of message has cost real review time. And the orphaned entry is reported not at all. Worse, rename some OTHER def into the orphaned name with the same rule and its suppression is silently blessed by an entry whose reason and approver describe different code: an approval transferred to code nobody approved. A dead entry is now a violation, and the message says which of the three world-states it is, because each has a different remedy: the anchored file is gone; the anchored symbol no longer exists in the file, renamed or removed; or the symbol is alive but carries no such suppression. A line anchor past end of file, or on a line that no longer carries the suppression, is named as its own case. The contested group -- an entry claiming a site while a sibling site in the same file and rule is unregistered -- is refused, because from one snapshot the gate cannot tell which site the entry was written for. The unregistered accusation stops lying. When a suppression has no entry AND the registry holds a stale anchor for the same file and rule, the message says it is very probably a rename, names the stale anchor, and gives the qualified symbol to re-anchor to. Where no rot exists the original strict wording stands byte for byte, at the same code, path, line and exit level, so nothing is softened. Line anchors are reported loudly and are NOT a violation. The registry cannot express "this pin is deliberate, here is why", so the gate has no oracle for "documented" and promoting them would fail a consumer for reasoned decisions it wrote down and defended. The audit publishes its own denominator on every run -- entries graded against live gated suppressions, anchors live, dead, unmeasured -- so a run that graded nothing cannot read as clean. Two consumer-visible shapes were restored after they broke a consumer's resolver cross-check: _scan_src keeps returning exactly two values, and _matches keeps its original argument order as a pure adapter over the single resolution rule. A shared library does not change a published shape for internal convenience, and patching the consumer instead would have deadlocked both repos, since a consumer edited for the new API fails against the currently pinned kit. Three rods pin that contract against recurrence. The 500-line file law forced the anchor half and the measured-surface half into their own modules; the import contract declares both as one-way helper strata below the gates, and a reverse import is refused. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
CONTRACT
cf-exemptionsenforces two halves of one contract: every suppression traces to a reasoned entry inexemptions.json, and every entry still points at the code it blessed.WORLD — only the first half existed
_match_suppressionsflagged an entry covering more than one suppression and tolerated an entry covering nothing in complete silence. Andfrozen_countratchets entries, not live coverage, so the ratchet stayed satisfied over a dead registry.Rename an enclosing
defand two wrongs happen at once:And the bystander case is worse: rename some other
definto the orphaned name with the same rule, and its suppression is silently blessed by an entry whosereasonandapproverdescribe entirely different code. An approval transferred to code nobody approved.Measured on the flagship
bonfireai/mainwith this kit's own resolver: 52 entries, 49 live symbol anchors, 0 dead, 3 line-anchored.The failure taxonomy — one message per world-state, because each has a different remedy
EXEMPTION_FILE_MISSINGEXEMPTION_SYMBOL_MISSINGEXEMPTION_SUPPRESSION_GONEEXEMPTION_SUPPRESSION_GONEEXEMPTION_ANCHOR_CONTESTED"The anchored symbol no longer exists" is a true, actionable message. Accusing a bystander is not.
The unregistered accusation stops lying
When a suppression has no entry and the registry holds a stale anchor for the same
file+rule, the message says it is very probably a rename, names the stale anchor, and gives the qualified symbol to re-anchor to. Where no rot exists, the original strict wording stands byte for byte, at the same code, path, line and exit level — so nothing is softened. The rot branch is reachable only when the orphan entry has already emitted its own violation, so it can never subtract a finding.Non-vacuity
The audit publishes its own denominator on every run —
G entries graded vs S live gated suppression(s) — L live, D dead, U unmeasured. A run that graded nothing cannot read as clean.🔴 The consumer break this PR had to fix, and why it was fixed HERE
The first cut changed two consumer-visible shapes, and it broke the flagship's repo-local pin — the resolver cross-check whose entire job is "the mirror cannot silently drift." Reproduced by installing this kit into a clean flagship checkout:
It was masked by
importorskipin that worktree, because the kit was not installed there. A skipped test and a passing test are indistinguishable in a summary.Fixed at the source, not downstream:
_scan_src(root)returns exactly two values again — original order, types, body._matches(suppression, entry)is restored in place with its original argument order, as a pure adapter overcovers, so the single-resolution-rule property is intact. Its docstring names the consumer pin and says it is a contract, not dead code.exemption_surface.discover_scan_paths(root)instead of riding a third element on_scan_src— same oracle, same discovery call, no arity change.Anti-dead-code guards against speculative code; it does not license changing a published shape a consumer's test demonstrably calls. The decisive argument is the deadlock: a consumer patched for a new API fails against the currently pinned kit, so neither repo could merge alone.
Acceptance condition, verified by re-installing this kit into the flagship checkout and running the consumer's pin:
4 passed, not 3 passed and 1 skipped. Three new rods (
TestConsumerResolverContract) pin the arity, the argument order in both directions, and_matches/coversagreement across four anchor shapes, so this cannot regress.FAILURE — the rods
20 rods in
tests/test_exemption_anchors.py. The two that matter most assert on message text, because the honesty of the message is the contract here:the anchored symbol 'old_name' no longer exists in src/mod.py (renamed or removed)and that the self-issued accusation is absent for that site;EXEMPTION_ANCHOR_CONTESTED, names the claimed site and the unregistered one, and asserts the bystander is not silently blessed — which today it is.Against the unfixed gate, 16 of 17 original rods go red.
The import-layer constraint is non-vacuous — I proved it can fail. Making the lowest helper import a gate:
The gate at harvest
The single red is environmental, and I isolated it:
tests/test_packaging.pycallsvenv.create(..., with_pip=True), which fails on this machine becauseensurepipis absent system-wide (a missingpython3.12-venv). With that one file excluded: 479 passed. Those three tests touch no file in this diff, and CI'ssetup-pythonprovidesensurepip, soself-cishould be green — but I have not seen them pass, and that is stated as unverified rather than assumed.ruff-formatwas red on two new files and fixed with the kit's own pinned formatter; the board above is post-fix.Structure
The 500-line file law forced the split.
exemptions.py494 → 468 (net −26); newexemption_anchors.py484; newexemption_surface.py78; newtests/test_exemption_anchors.py390. All under the cap. The kit ships nofile-budget.json, so only the 500-line new-file rule applies andcf-file-budgetexits 0 — there is no number to declare and none was moved.The import contract declares both new modules as one-way helper strata below the gates:
gates > exemption_anchors > exemption_surface > repo_config > errors. They ship no console script;exemptionsimports them, they import no gate, and anchors imports surface and never the reverse.No existing test was edited. 46/46 existing
test_exemptions*assertions pass.Questions and residue
exemptions.jsonhas no field asserting "this pin is deliberate, here is why", so the gate has no oracle for "documented", and promoting it would red the flagship's 3 of 52 pins, all of which are documented and defended. Recommendation, logged as DESIGN.md Open issue 18: promote only after a review-gated"line_anchored_by_design": "<why>"field exists, and only after consumers have migrated the anchors a symbol can express. Not mine to decide.reasonto open with the qualified symbol — are recorded and deliberately not built.bonfireai/main(52 / 3). Measure the live remote branch, never a checkout that happens to be on disk. The design conclusion survived; the numbers did not.BLE001entries whose sites moved and were re-registered elsewhere. This gate would name them.Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com