Skip to content

Refuse an exemption whose anchor no longer names live code, and say which way it rotted - #26

Merged
Antawari merged 1 commit into
mainfrom
catrina/gates-r5-honest-anchor-failure
Jul 29, 2026
Merged

Refuse an exemption whose anchor no longer names live code, and say which way it rotted#26
Antawari merged 1 commit into
mainfrom
catrina/gates-r5-honest-anchor-failure

Conversation

@Antawari

Copy link
Copy Markdown
Contributor

CONTRACT

cf-exemptions enforces two halves of one contract: every suppression traces to a reasoned entry in exemptions.json, and every entry still points at the code it blessed.

WORLD — only the first half existed

_match_suppressions flagged an entry covering more than one suppression and tolerated an entry covering nothing in complete silence. And frozen_count ratchets entries, not live coverage, so the ratchet stayed satisfied over a dead registry.

Rename an enclosing def and two wrongs happen at once:

  1. The blessed site is accused — "a self-issued suppression is not an exemption." That message is convincing and it is wrong: the site was blessed; the registry pointer rotted. The flagship's own notes record that this class of misleading message "has cost real review time and nearly provoked rewrites of load-bearing error barriers."
  2. The orphaned entry is reported not at all.

And the bystander case is 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 entirely different code. An approval transferred to code nobody approved.

Measured on the flagship bonfireai/main with 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

world-state code exit
the anchored file is gone EXEMPTION_FILE_MISSING 1
the anchored symbol no longer exists in the file (renamed or removed) EXEMPTION_SYMBOL_MISSING 1
the symbol is alive but carries no such suppression EXEMPTION_SUPPRESSION_GONE 1
a line anchor on a line that no longer carries the suppression, or past end of file EXEMPTION_SUPPRESSION_GONE 1
an entry claims a site while a sibling site in the same file+rule is unregistered — the bystander EXEMPTION_ANCHOR_CONTESTED 1
an ungradeable entry (outside the scanned surface, ungated rule, unreadable file) notice, not a violation 0
any line-anchored entry notice, with the migration path 0

"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:

>       suppressions, _ = exemptions._scan_src(_REPO_ROOT)
E       ValueError: too many values to unpack (expected 2)
tests/unit/test_exemption_anchors_are_drift_proof.py:235: ValueError
1 failed, 3 passed

It was masked by importorskip in 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 over covers, so the single-resolution-rule property is intact. Its docstring names the consumer pin and says it is a contract, not dead code.
  • The audit takes its surface from 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:

tests/unit/test_exemption_anchors_are_drift_proof.py::test_every_anchor_is_a_symbol_except_the_documented_line_pins PASSED
tests/unit/test_exemption_anchors_are_drift_proof.py::test_no_exemption_entry_covers_more_than_one_suppression PASSED
tests/unit/test_exemption_anchors_are_drift_proof.py::test_the_ambiguity_measure_reports_two_for_a_deliberately_ambiguous_anchor PASSED
tests/unit/test_exemption_anchors_are_drift_proof.py::test_the_local_resolver_agrees_with_the_installed_quality_kit PASSED

4 passed

4 passed, not 3 passed and 1 skipped. Three new rods (TestConsumerResolverContract) pin the arity, the argument order in both directions, and _matches/covers agreement 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 rename rod asserts the message contains 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;
  • the bystander rod asserts 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:

pyproject.toml: CONTRACT_BROKEN: lint-imports reports the committed contract violated: - cf_quality.exemption_surface -> cf_quality.exemptions (l.28)
ROD_EXIT=1

The gate at harvest

PASS  ruff-check          PASS  cf-exemptions        PASS  mypy
PASS  ruff-format         PASS  cf-no-bon-ref        PASS  complexipy
PASS  cf-sticky-check     PASS  cf-import-contract   FAIL  pytest
PASS  cf-file-budget      PASS  cf-recursion-check

cf-gate: FAIL — 1 of 11 gate(s) red (exit 1)

The single red is environmental, and I isolated it: tests/test_packaging.py calls venv.create(..., with_pip=True), which fails on this machine because ensurepip is absent system-wide (a missing python3.12-venv). With that one file excluded: 479 passed. Those three tests touch no file in this diff, and CI's setup-python provides ensurepip, so self-ci should be green — but I have not seen them pass, and that is stated as unverified rather than assumed.

ruff-format was 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.py 494 → 468 (net −26); new exemption_anchors.py 484; new exemption_surface.py 78; new tests/test_exemption_anchors.py 390. All under the cap. The kit ships no file-budget.json, so only the 500-line new-file rule applies and cf-file-budget exits 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; exemptions imports 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

  1. 🔴 Should an undocumented line anchor be a violation? It cannot be expressed today — exemptions.json has 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.
  2. Honest residue, disclosed rather than hidden: a rename-into whose original site is deleted in the same commit leaves one live anchor covering one live suppression, and is indistinguishable from an honest entry in a single snapshot. No message can honestly claim otherwise. Candidate closures — a content fingerprint of the suppressed statement, or requiring reason to open with the qualified symbol — are recorded and deliberately not built.
  3. A recon correction worth carrying: the first measurement of the consumer registry read a working checkout that happened to be sitting on an unmerged branch (91 entries, 82 line-anchored) rather than 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.
  4. A finding about that unmerged branch, not about main: it carries two rotted duplicate BLE001 entries whose sites moved and were re-registered elsewhere. This gate would name them.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

…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>
@Antawari
Antawari merged commit 18ffbaf into main Jul 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant