refactor(rules): split negative-parallelism variants by confidence - #6
Merged
Merged
Conversation
Both rules widened on this branch stretched one severity over two very different levels of confidence. Split each into a confident rule and a quiet one instead. no-x-no-y keeps the comma chain at warning -- the comma is the evidence that a writer authored the parallelism. The fragment form moves to a new no-x-no-y-frag at info, because two short "no" sentences in a row is also just writing. not-just-x-but-y keeps the escalation branch at warning and gains merely, simply, solely, plus "not because A but because B". The bare corrective moves to a new not-x-but-y at info, and its comment now says plainly that the B-guard is a filter rather than a decision procedure: a concession with a noun-phrase subject or an elided one still gets through, and the fix is not to keep growing the blocklist. Also fixes three ways the widened patterns matched text that was not there: a fragment link may no longer start mid-sentence and donate an ordinary sentence's tail to a chain, the link separator is capped at two spaces so a code span blanked by --markdown cannot weld distant fragments together, and both not-but rules stop at a paragraph break. CRLF input now reaches the fragment branch, "It's not a bug but a feature" is no longer missed, and dropping the unused just/only tail settles the count that said 2 items while bracketing 3. sloplint explain no longer breaks its aligned block on a multi-line fixture. README and SPEC.md follow the catalog; the README's worked example is now a generic placeholder so it stops going stale on every rule tweak. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Jul 28, 2026
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.
Widens two rules to catch negative-parallelism variants, then splits each one so the confident half and the ambiguous half don't ship at the same severity.
What changed
no-x-no-ynow covers the fragment form of the cadence — "No fluff. No filler." — but as a separate rule atinfo, not folded into the comma chain atwarning. The comma is real evidence that a writer authored the parallelism; a period is just how sentences end. Two short "no" sentences in a row is also, frequently, a novelist.not-just-x-but-ygainsmerely,simply,solelyalongsidejust/only, plus "not because A, but because B", and keepswarning. The bare corrective — "is not A but B", no escalation word — becomesnot-x-but-yatinfo.That split is the point of the PR. An
infoflag with a rationale behind it is useful to an agent deciding whether to act. The same flag atwarning, next to rules that are nearly always right, is just noise that teaches you to ignore the tool.The honest part
not-x-but-ycannot do what it claims to do. Telling a correction ("not an accident but a strategy") from a concession ("not warm but the fire helped") is syntactic, and the rule is a regex with a hand-written list of words that can't start clause B. That list already leaks in two directions: a concession whose second clause opens with a noun phrase gets through, and so does one with a bare lexical verb — "was not perfect but got us there."I've written that into the rule's comment and rationale rather than papering over it, including a note not to chase these by growing the blocklist, since every word added silently narrows recall with nothing pinning it.
sloplint explain not-x-but-ysays the same thing to whoever reads the flag. Shipping atinfois what makes that honest instead of broken.The rationale on the old combined rule claimed all 15 corpus hits were deliberate antitheses. That wasn't true — some are concessions with an elided subject, and the new rationale names one.
Bugs fixed
Three cases where the widened patterns reported a chain or a frame that wasn't in the text:
--markdowncan't weld two distant fragments into a chain the source doesn't contain.not…butrules stop at a paragraph break, so an unpunctuated heading no longer joins the next paragraph's "But …".Plus: CRLF input reaches the fragment branch (it silently didn't),
"It's not a bug but a feature."is no longer missed entirely — branch 3 had dropped the contracted subjects branch 1 carries — and the item count no longer says 2 while bracketing 3, since the unusedjust|onlytail is gone.sloplint explainno longer breaks its aligned fixture block when a fixture contains a newline. The README says agents parse that output, so a stray newline reading as end-of-list was a real problem.Docs
README counts and breakdown updated (25 → 27 rules),
docs/SPEC.mdentries rewritten for both rules, and the README's staleexplainsample replaced with real output. The "Adding a rule" worked example is now a generic placeholder instead of a copy ofno-x-no-ythat went stale every time that rule was touched.Testing
rspec— 224 examples, 0 failures. Every new pattern was probed against the false positives before shipping, and each narrowing is pinned by anexamples_okfixture.Follow-up, not in this PR
checkdoesn't emit the rationale — an agent gets a one-line message and has to know to runexplainseparately. That's the piece that makesinfoflags actually useful, and it's worth doing on its own. Related: 21 of 27 rules are stillwarning, which is worth a pass now that the tier means something.🤖 Generated with Claude Code