Skip to content

fix(lint): stop 109 autofixes rewriting hard-quoted data - #128

Merged
takeokunn merged 1 commit into
mainfrom
fix/quote-guard-conditional
Aug 4, 2026
Merged

fix(lint): stop 109 autofixes rewriting hard-quoted data#128
takeokunn merged 1 commit into
mainfrom
fix/quote-guard-conditional

Conversation

@takeokunn

Copy link
Copy Markdown
Collaborator

Seventeen Fixable rules in lint-conditional fired inside hard-quoted data and rewrote a data literal as if it were code.

Measured over 6,474 SHA-256-deduplicated Common Lisp files

91.5% of emitted fixes classified by quote state.

counter before → after
hard-quoted fixes 332 → 223 (109 eliminated)
unquoted-code fixes 9,112 → 9,112 (not one lost)
quasiquote-template fixes 707 → 707 (not one lost)

The two unmoved counters are the point — over-suppression is the default failure mode when fixing false positives.

Why the guard tests hard only

A quasiquote template is code: (if ,c nil ,e) in a macro body must still be fixed. Every guarded rule carries a still_fires_inside_a_quasiquote_template test asserting the rewritten source, generated from an oracle binary running the real dispatch rather than guessed.

A mutation harness kills 6 mutants, including state.hardstate.is_data() — the obvious wrong fix.

Exclusion

one-armed-if is deliberately left unguarded: 6 of its 16 hard-quoted findings sit under a #. read-eval ancestor or inside an SBCL deftransform/defoptimizer template, where the quoted text is spliced back as live code. Every rule guarded here measured zero such exposure.

Four guards (cond-t-clause, negated-if, nested-when, nested-unless) had no measured misfires and are preventive, not evidence-driven.

Verification

cargo fmt --all --check 0 · cargo clippy --workspace --all-targets -D warnings 0 · cargo test --workspace 0 (178 suites)

No rule count changes; no registry, presentation, docs or bench file touched.

Seventeen `Fixable` rules in `lint-conditional` fired inside hard-quoted
data and rewrote a data literal as if it were code. `--fix` then corrupted
the file silently: every round-trip property still passed, because a
consistently wrong parse is a fixed point of its own round-trip.

Measured over 6,474 SHA-256-deduplicated Common Lisp files, with 91.5% of
emitted fixes classified by quote state:

  hard-quoted fixes         332 -> 223   (109 eliminated)
  unquoted-code fixes     9,112 -> 9,112 (not one lost)
  quasiquote-template       707 -> 707   (not one lost)

The two unmoved counters are the point. Over-suppression is the default
failure mode when fixing false positives, so each guarded rule carries a
`still_fires_inside_a_quasiquote_template` test asserting the rewritten
source, generated from an oracle binary running the real dispatch rather
than guessed. A quasiquote template is code: `(if ,c nil ,e)` in a macro
body must still be fixed. The guard therefore tests `hard` only, never a
combined is-data predicate -- a mutation harness kills exactly that mutant,
along with five others (guard always true, always false, inverted, skipping
the target's own prefixes, ignoring long-hand `(quote ...)`).

`one-armed-if` is deliberately left unguarded: 6 of its 16 hard-quoted
findings sit under a `#.` read-eval ancestor or inside an SBCL
`deftransform`/`defoptimizer` template, where the "quoted" text is spliced
back as live code. Every rule guarded here measured zero such exposure.

Four of the seventeen guards -- `cond-t-clause`, `negated-if`,
`nested-when`, `nested-unless` -- had no measured misfires and are
preventive rather than evidence-driven.

No rule count changes; no registry, presentation, docs or bench file is
touched.
@takeokunn
takeokunn merged commit a1aad5c into main Aug 4, 2026
2 of 3 checks passed
@takeokunn
takeokunn deleted the fix/quote-guard-conditional branch August 4, 2026 09:19
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