Skip to content

refactor(rules): split negative-parallelism variants by confidence - #6

Merged
benjaminjackson merged 1 commit into
mainfrom
negative-parallelism-variants
Jul 28, 2026
Merged

refactor(rules): split negative-parallelism variants by confidence#6
benjaminjackson merged 1 commit into
mainfrom
negative-parallelism-variants

Conversation

@benjaminjackson

Copy link
Copy Markdown
Owner

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-y now covers the fragment form of the cadence — "No fluff. No filler." — but as a separate rule at info, not folded into the comma chain at warning. 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-y gains merely, simply, solely alongside just/only, plus "not because A, but because B", and keeps warning. The bare corrective — "is not A but B", no escalation word — becomes not-x-but-y at info.

That split is the point of the PR. An info flag with a rationale behind it is useful to an agent deciding whether to act. The same flag at warning, next to rules that are nearly always right, is just noise that teaches you to ignore the tool.

The honest part

not-x-but-y cannot 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-y says the same thing to whoever reads the flag. Shipping at info is 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:

  • A fragment link had to start a sentence, so "There was no bread. No milk either." no longer donates a tail to a chain it was never part of.
  • The link separator is capped at two spaces, so an inline code span blanked by --markdown can't weld two distant fragments into a chain the source doesn't contain.
  • Both not…but rules 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 unused just|only tail is gone.

sloplint explain no 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.md entries rewritten for both rules, and the README's stale explain sample replaced with real output. The "Adding a rule" worked example is now a generic placeholder instead of a copy of no-x-no-y that 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 an examples_ok fixture.

Follow-up, not in this PR

check doesn't emit the rationale — an agent gets a one-line message and has to know to run explain separately. That's the piece that makes info flags actually useful, and it's worth doing on its own. Related: 21 of 27 rules are still warning, which is worth a pass now that the tier means something.

🤖 Generated with Claude Code

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>
@benjaminjackson
benjaminjackson merged commit cad46b1 into main Jul 28, 2026
2 checks 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