sloplint 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0d26e3bebafd7184f09aa41f70d1013e8ca6d9f460d4e0229815c18db08263a
4
- data.tar.gz: 944923cfab5a213d08a5367bae1dfd75fb4fc71aa9a004fbb59806b5dace1376
3
+ metadata.gz: 0aabc7314411211ed5adcbb5e09bb81a4291b2ffb7748e8d07d15f0150e6c43c
4
+ data.tar.gz: f8c9af283d490a6acb2d4cd6260ccc776e868542be3f1b10066ec6232e856ea0
5
5
  SHA512:
6
- metadata.gz: 19ad341fcb7a415b737bc4e1fdd3f355d4b6bd91429209477b4ac4605a2f18b7372bf1791e34e9e0e69b6d50b17a02abf959981b7bd32b5345a30ebc3151cb87
7
- data.tar.gz: 9f0732fe535cc7753ed2b8380687575c4b109b5f9be31409e1d207c9ccb3b7ffbcb69a833427e68bb73c905369b47dd920ce7dd7162e456a61dd7a07c468c853
6
+ metadata.gz: 508f10329c7698ab4cce5b1dd09902984975ed2baeaa5646b7c288d33ee913f1a8f19e2aba36ab860a77a7b2ea2acde07748ce11db39367958c6ec86af3b4b1f
7
+ data.tar.gz: b75def69bddf045ddab9f99798985cf210ae7b3997266f9199600cf77638b5db8759738879b51949f31945b2ad183706b34654736cfdd7420f292c5442d2445d
data/CHANGELOG.md CHANGED
@@ -3,6 +3,137 @@
3
3
  All notable changes to this project are documented here. Format loosely
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
+ ## [Unreleased]
7
+
8
+ ## [0.8.0] - 2026-09-15
9
+
10
+ ### Changed (breaking)
11
+
12
+ - The four old categories are gone: `rhetorical-tic`, `structure`, `puffery`
13
+ and `hedging`. Nine new categories replace them, each named for the move
14
+ the construct makes: `self-rating` (the writer grades their own prose or
15
+ claim), `closer` (closes by restating or announcing the point), `cadence`
16
+ (rhythm: repetition, parallelism, the long-then-short kicker), `puffery`
17
+ (inflates the subject), `false-correction` (corrects a reading nobody
18
+ offered), `false-concession` (performs balance or candor and gives nothing
19
+ up), `reader-address` (instructs or flatters the reader),
20
+ `borrowed-metaphor` (an engineering term applied to an argument), and
21
+ `punctuation` (the mark itself). Every note, `--select`, and `--ignore` now
22
+ use these nine names; the four old names are gone, not aliased, so a
23
+ script still passing one gets a usage error instead of a silent no-op.
24
+ - The rule `ellipsis-closer` is renamed `bare-auxiliary-closer`. Nothing
25
+ about its pattern, message, or fixtures changed, only the id.
26
+ - `severity` now rates only what the construct costs the prose (`error`,
27
+ `warning`, `info`). A new field, `confidence`, rates how likely a match is
28
+ a false positive (`high`, `medium`, `low`), and a `low` rule replaces what
29
+ used to be `default_on: false` — it stays out of a normal run and needs
30
+ `--strict` or its own id named directly to turn on.
31
+ - `sloplint rules --json` drops the `default_on` field and adds `confidence`
32
+ and `rationale` for every rule. Each note in `check` output also gains a
33
+ `confidence` field alongside `severity`.
34
+ - `--select <category>` no longer turns on that category's low-confidence
35
+ rules. Naming a category now selects only its default-on rules; to run a
36
+ low-confidence rule, pass `--strict` or name the rule's own id.
37
+ - Every rule's severity was re-rated for what the construct costs the prose,
38
+ now that confidence carries the false-positive question on its own. The
39
+ catalog reads 11 `error`, 56 `warning`, 13 `info`. Nothing shipped at
40
+ `error` before: the eleven that do now are the ones that hurt a sentence in
41
+ any register, the puffery family (`puffery-words`, `rich-tapestry`,
42
+ `vital-role`, `impact-noun-vague`,
43
+ `trailing-significance-participle`), the tautology and self-ranking moves
44
+ (`the-x-is-the-x`, `cleanest-x`, `most-honest-x`), the fake balance
45
+ (`two-things-true`, `none-of-this-is-to-say`) and `vague-attribution`.
46
+ Twenty rules moved from `info` to `warning`, among them `em-dash-overuse`:
47
+ one em dash is a style choice, three in a paragraph is the tell, so the
48
+ dense form now costs more than `em-dash`. Any tool that keys off severity
49
+ sees different values for the same text.
50
+
51
+ ### Fixed
52
+
53
+ - The test suite failed with no locale set, because `spec/plugin_spec.rb`
54
+ read files without forcing UTF-8. Fixed to read as UTF-8 regardless of the
55
+ environment's locale.
56
+ - The README and SPEC quoted an outdated rationale for `no-x-no-y` and an
57
+ outdated sample of `sloplint check` output. Both are corrected and now
58
+ pinned by tests, so a future drift between the docs and the code fails the
59
+ build instead of sitting unnoticed.
60
+ - SPEC's description of the `Rule` model and of the package's file layout
61
+ had fallen out of step with the code. Both are corrected to match.
62
+ - `--help` was missing `count` from its list of note keys, even though a
63
+ note already includes it for rules that tally items. Added.
64
+
65
+ ### Added
66
+
67
+ - A test asserting that no rule id ever matches a category name, since
68
+ `--select` and `--ignore` resolve a name against both and a collision
69
+ would make one shadow the other.
70
+
71
+ ## [0.7.0] - 2026-09-15
72
+
73
+ ### Added
74
+
75
+ - `--strict` runs the full catalog, including the five rules that ship off
76
+ by default. Before this, the only way to turn one on was to name it in
77
+ `--select`, which also turned off every other rule unless you listed
78
+ those too. `--ignore` still subtracts on top of `--strict`, and
79
+ `--select` is unchanged.
80
+ - `ellipsis-closer` (structure, info) flags the long-sentence-then-short-closer
81
+ kicker `mic-drop-closer` catches, but built on the opposite verb shape: the
82
+ closer's verb phrase is elided down to a bare auxiliary with no object,
83
+ "The agent did." rather than a quantifier plus a full verb. No subject list
84
+ is needed — the tell is the missing verb, not the subject — so "That",
85
+ "This" and "It" are not excluded the way `mic-drop-closer` excludes them.
86
+ A negative lookahead drops a closer that still holds a wh-word, since that
87
+ marks a subordinate clause with its own complement rather than an elided
88
+ one. Reuses `mic-drop-closer`'s long-sentence prefix.
89
+ - `actually-not-x`: the adverb and a trailing "…, not X" in one clause, as in
90
+ "The disclosure actually covered two incidents, not one". Either marker
91
+ alone is ordinary technical English and neither is matched on its own; the
92
+ tell is the two of them doubled up, correcting an alternative the reader was
93
+ never offered. The narrowing is structural, not a word list: the comma in
94
+ front of "not" has to be the first comma of its clause and has to follow a
95
+ word, so a fronted setup ("Despite the name, …") and a parenthetical both
96
+ drop it. Nothing crosses a line break, so two rows of a table cannot weld
97
+ into one correction.
98
+ - `real-x-real-y` (rhetorical-tic, info) flags the same "real" used twice
99
+ attributively in one sentence, in front of two different nouns: "it can
100
+ trigger real API calls or hold real credentials". Bare "real" is an
101
+ ordinary word, so the narrowing is the repetition itself, not a noun
102
+ list. A hyphen on either side takes it out ("real-time", "non-real"), a
103
+ backreference requires the second noun to differ from the first, and a
104
+ short closed list drops the fixed senses of this register (real time,
105
+ real-world, real numbers, real user monitoring, real estate, real money).
106
+ - `phrase-echo` (rhetorical-tic, info, off by default) flags a three-word
107
+ phrase that comes back within a few hundred words, the model reusing a
108
+ phrase it has just minted. Each word must be four characters or more and
109
+ lowercase-led, and one of them six letters with nothing but letters, so "in
110
+ order to", "couldn't have been" and "New York City" never match. The window
111
+ does not cross into a list item or a table row. Off by default: a term of
112
+ art repeats because it must, and in reference prose the pattern fires on
113
+ names by the thousand per million words.
114
+ - `trailing-restatement` (structure, info, off by default) flags the tail
115
+ that says the sentence again in other words: ", which means …", ", which
116
+ is to say …", ", meaning …", and four participles that hang a result off
117
+ the sentence (", making it easier", ", allowing us to", ", giving them
118
+ more", ", leaving you with"). The connective is all a pattern can see, and the
119
+ same connective states a real consequence in careful prose, so the rule
120
+ runs only when selected.
121
+
122
+ ### Fixed
123
+
124
+ - `check`'s options now work without the command word: `sloplint --markdown -`
125
+ and `sloplint --strict -` scan, as the README has said `sloplint -` does.
126
+ Before, the global parser rejected any option it did not own with
127
+ `invalid option`, so `check` had to be spelled out whenever an option
128
+ came first. An option no command knows still exits 2.
129
+ - `--markdown` now blanks `<!-- -->` comment blocks along with fenced code,
130
+ inline code and URLs. Planning notes kept in comments never render, so
131
+ every rule that fired inside one was a permanent false positive.
132
+ - `rule-of-three`'s message, rationale, README and SPEC entries said it
133
+ flagged three parallel comma items. The pattern requires single words in
134
+ the closing two slots, so a triad of phrases never matched; the text now
135
+ says that.
136
+
6
137
  ## [0.6.0] - 2026-09-08
7
138
 
8
139
  The catalog grows from 50 rules to 75, and sloplint ships as a Claude Code
data/README.md CHANGED
@@ -60,24 +60,24 @@ The recipe sloplint is built around, and the one an agent should use:
60
60
  cat draft.md | sloplint check --markdown -o json -
61
61
  ```
62
62
 
63
- `--markdown` blanks out code and URLs first, `-o json` emits the machine-readable form, and `-` reads stdin. Exit 0 means clean, 1 means notes found, anything higher is an error. `check` is the default command, so `sloplint draft.md`, `sloplint -`, and a bare `sloplint` with piped stdin all scan.
63
+ `--markdown` blanks out code, HTML comments, and URLs first, `-o json` emits the machine-readable form, and `-` reads stdin. Exit 0 means clean, 1 means notes found, anything higher is an error. `check` is the default command, so `sloplint draft.md`, `sloplint -`, and a bare `sloplint` with piped stdin all scan.
64
64
 
65
65
  The human-readable form drops `-o json`:
66
66
 
67
67
  ```
68
68
  $ printf 'The report is a rich tapestry of vibrant detail.\nThat is exactly the point I keep making about it.\n' | sloplint check -
69
- -:1:17: warning rich-tapestry "rich tapestry"/"tapestry of" is a signature AI cliché.
69
+ -:1:17: error rich-tapestry "rich tapestry"/"tapestry of" is a signature AI cliché.
70
70
  excerpt: The report is a [rich tapestry] of vibrant detail. That is exactly the…
71
71
  why: 'tapestry of' is one of the most reliable single-phrase model tells.
72
72
  fix: Cut the metaphor; name the actual things.
73
73
 
74
- -:1:34: warning puffery-words Wikipedia-style puffery word/phrase — a common AI tell.
74
+ -:1:34: error puffery-words Wikipedia-style puffery word/phrase — a common AI tell.
75
75
  excerpt: The report is a rich tapestry of [vibrant] detail. That is exactly the point I…
76
76
  why: Travel-brochure adjectives and phrases that models reach for and careful writers avoid.
77
77
  fix: Replace with a concrete, specific detail or cut it.
78
78
 
79
- -:2:9: info exact-exactly "exact/exactly" is reflexive emphasis unless it names something checkable.
80
- excerpt: …tapestry of vibrant detail. That is [exactly] the point I keep making about it.
79
+ -:2:1: info exact-exactly "exact/exactly" is reflexive emphasis unless it names something checkable.
80
+ excerpt: …is a rich tapestry of vibrant detail. [That is exactly] the point I keep making about it.
81
81
  why: Models reach for 'exact/exactly' as filler emphasis on a claim with nothing to check; it earns its place only next to a number, a name, or a stated identity.
82
82
  fix: Cut it, or replace with the number, name, or match it's supposed to be precise about.
83
83
  ```
@@ -98,19 +98,20 @@ version print the sloplint version
98
98
 
99
99
  `check` takes files as arguments, or `-` (or nothing) to read stdin, and these options:
100
100
 
101
- - `--markdown` skips fenced code, inline code, and URLs before scanning. Off by default so it never silently eats prose.
101
+ - `--markdown` skips fenced code, inline code, HTML comments, and URLs before scanning. Off by default so it never silently eats prose.
102
102
  - `--select IDS` runs only these rules. Accepts comma-separated rule ids or category names.
103
103
  - `--ignore IDS` skips these rules. Same id-or-category form.
104
+ - `--strict` runs every rule, including the five that are off by default. `--ignore` still applies on top.
104
105
 
105
106
  `explain` is the command an agent calls to decide whether a flag is worth acting on:
106
107
 
107
108
  ```
108
109
  $ sloplint explain no-x-no-y
109
- no-x-no-y (rhetorical-tic, warning)
110
+ no-x-no-y (cadence, warning, high confidence)
110
111
 
111
112
  "No X, no Y" chain (%{count} items) reads as AI cadence.
112
113
 
113
- Why: Asyndetic negation chains are a signature model cadence, near-absent from human prose at any length -- 24 hits in 1.02M words across Austen, Melville, Madison, Thoreau, and Emerson combined. A careful writer occasionally stacks two (and, rarely, more), but a model reaches for the pattern constantly.
114
+ Why: Asyndetic negation chains are a signature model cadence, near-absent from human prose at any length. A careful writer occasionally stacks two (and, rarely, more), but a model reaches for the pattern constantly.
114
115
  Fix: Cut the chain or make it one plain sentence.
115
116
 
116
117
  Flags: No fluff, no filler, no jargon.
@@ -127,18 +128,19 @@ One match is one note. JSON output is an array of these, or an object keyed by p
127
128
  "line": 12,
128
129
  "column": 5,
129
130
  "severity": "warning",
131
+ "confidence": "high",
130
132
  "rule": "no-x-no-y",
131
- "category": "rhetorical-tic",
133
+ "category": "cadence",
132
134
  "message": "\"No X, no Y\" chain (3 items) reads as AI cadence.",
133
135
  "excerpt": "No fluff, no filler, no jargon",
134
136
  "context": "The report was blunt. [No fluff, no filler, no jargon]. Nothing held back at all.",
135
137
  "count": 3,
136
- "rationale": "Asyndetic negation chains are a signature model cadence, near-absent from human prose at any length -- 24 hits in 1.02M words across Austen, Melville, Madison, Thoreau, and Emerson combined. A careful writer occasionally stacks two (and, rarely, more), but a model reaches for the pattern constantly.",
138
+ "rationale": "Asyndetic negation chains are a signature model cadence, near-absent from human prose at any length. A careful writer occasionally stacks two (and, rarely, more), but a model reaches for the pattern constantly.",
137
139
  "suggestion": "Cut the chain or make it one plain sentence."
138
140
  }
139
141
  ```
140
142
 
141
- `line` and `column` are 1-indexed and point at the start of the match. `excerpt` is the bare match; `context` is the same match bracketed inside about 40 characters of surrounding prose, which is what you want when the match is a single word or a lone em dash. A match already 40 characters long carries its own context, so `context` returns it alone rather than padding it further. `count` appears only when the rule tallies items (a "no X, no Y" chain, a "did not, did not" chain). `rationale` is why the pattern is a tell — the same text `sloplint explain` prints — so an agent deciding whether an `info` flag is worth acting on doesn't have to run `explain` separately to find out. `suggestion` is a short fix hint.
143
+ `severity` is what the construct costs the prose; `confidence` is how likely the match is a false positive. The two are separate, so a cheap tell we are sure about and an expensive one we are guessing at no longer collapse into the same word. `line` and `column` are 1-indexed and point at the start of the match. `excerpt` is the bare match; `context` is the same match bracketed inside about 40 characters of surrounding prose, which is what you want when the match is a single word or a lone em dash. A match already 40 characters long carries its own context, so `context` returns it alone rather than padding it further. `count` appears only when the rule tallies items (a "no X, no Y" chain, a "did not, did not" chain). `rationale` is why the pattern is a tell — the same text `sloplint explain` prints — so an agent deciding whether a flag is worth acting on doesn't have to run `explain` separately to find out. `suggestion` is a short fix hint.
142
144
 
143
145
  ## Exit codes
144
146
 
@@ -154,24 +156,29 @@ An unknown id or category in `--select`/`--ignore` is a usage error (exit 2, nam
154
156
 
155
157
  ## The rule catalog
156
158
 
157
- 75 rules across four categories. `sloplint rules` prints them; `sloplint rules --json` gives an agent the enumerable form.
159
+ 80 rules across nine categories, each named for the rhetorical move the construct makes. `sloplint rules` prints them; `sloplint rules --json` gives an agent the enumerable form.
158
160
 
159
- - **rhetorical-tic** (53) the cadence patterns: `no-x-no-y`, `no-x-no-y-frag`, `from-x-to-y-chain` ("from guessing to measuring, from hoping to knowing"), `one-x-one-y` ("one reviewer, one queue, one deadline"), `same-determiner-chain` (any other repeated determiner, at `info`), `and-what-it-should` (the elliptical tail: "…, and what it should."), `abstract-lives-in` ("the value sits in the follow-up", at `info`), `the-x-is-the-x` ("the problem with A is the problem with B"), `bare-equative` ("The lesson is the handoff.", at `info`), `thats-the-whole`, `is-the-whole-x` (the same closer on any subject: "Consistency is the real test.", at `info`), `thats-how-x`, `announced-takeaway`, `exact-exactly`, `load-bearing`, `intersection-of`, `you-already-know`, `sit-with-that`, `hold-onto-that`, `cleanly`, `clean-count`, `cleanest-x`, `clean-x`, `not-nothing`, `is-is` (doubled copula), `if-im-being-honest` (the candor preamble, from slopwash.com's "false intimacy"), `and-nothing-else` (the trailing "…, and nothing else"), `honestly`, `honest-x`, `most-honest-x` (the honesty family, built the same way as the four `clean` rules above), `impact-verb` ("the outage impacted four thousand accounts"), `impact-noun-bare` ("the impact of X", at `info` because research prose uses it straight), and more.
160
- - **puffery** (6) five from Wikipedia's "signs of AI writing" `puffery-words` (vibrant, nestled, groundbreaking, in the heart of), `rich-tapestry`, `vital-role`, `stands-serves-as`, `underscores-highlights` plus `impact-noun-vague` ("a significant impact", "make an impact").
161
- - **structure** (15) `everyone-nobody` (the comma-spliced antithesis: "Everyone wants the dashboard, nobody maintains it."), `np-fragment-and` (the verbless "A named owner and a quarterly review.", at `info`), `quip-question` (the verbless "No invite?", at `info`), `mic-drop-closer` (the short quantifier-led sentence that ends a paragraph after a long one, at `info`; a draft full of them is a warning), `short-run` (three sentences of thirty characters or fewer in a row, at `info`, same caveat), `not-just-x-but-y`, `not-x-but-y` (the bare corrective), `isnt-x-its-y` (the same corrective split across two clauses: "It isn't the tool. It's the habit."), `not-by-x-but-by-y` (the corrective on a repeated preposition: "not by luck, but by design"), `em-dash` (any em dash), `em-dash-overuse` (three or more in one paragraph), `question-isnt` (the corrective frame in interrogative dress), `less-about-more-about`, `trailing-significance-participle` (the "…, showcasing its importance" clause), and `rule-of-three`.
162
- - **hedging** (1) `vague-attribution`: "some critics argue," "it is widely regarded."
161
+ - **self-rating** (15) the writer grades their own prose or claim: `clean-x`, `clean-count`, `cleanest-x`, `cleanly`, `honest-x`, `most-honest-x`, `honestly` (the honesty family, built the same way as the four `clean` rules), `worth-naming`, `worth-saying-plainly`, `earns-its-place`, `does-a-lot-of-work`, `exact-exactly`, `genuinely` (off by default), `the-punchline-is`, `announced-takeaway`.
162
+ - **closer** (12) closes by restating or announcing the point: `thats-the-whole`, `is-the-whole-x` (the same closer on any subject: "Consistency is the real test.", at `medium` confidence), `is-the-entire`, `the-entire-is`, `thats-how-x`, `thats-the-tension`, `right-up-until`, `and-nothing-else` (the trailing "…, and nothing else"), `nothing-else-frag`, `bare-equative` ("The lesson is the handoff.", at `medium` confidence), `trailing-restatement` (the "…, which means …" tail that says the sentence again, off by default), `and-what-it-should` (the elliptical tail: "…, and what it should.").
163
+ - **cadence** (17) rhythm: repetition, parallelism, and the long-then-short kicker: `no-x-no-y`, `no-x-no-y-frag`, `did-not-x-did-not-y`, `one-x-one-y` ("one reviewer, one queue, one deadline"), `from-x-to-y-chain` ("from guessing to measuring, from hoping to knowing"), `same-determiner-chain` (any other repeated determiner, at `medium` confidence), `real-x-real-y`, `epistrophe` (off by default), `phrase-echo` (off by default), `is-is` (doubled copula), `the-x-is-the-x` ("the problem with A is the problem with B"), `rule-of-three` (off by default), `everyone-nobody` (the comma-spliced antithesis: "Everyone wants the dashboard, nobody maintains it."), `short-run` (three sentences of thirty characters or fewer in a row, at `medium` confidence), `mic-drop-closer` (the short quantifier-led sentence that ends a paragraph after a long one, at `medium` confidence), `bare-auxiliary-closer` (the same shape, but the closer's verb is elided down to a bare auxiliary: "The agent did.", at `medium` confidence), `np-fragment-and` (the verbless "A named owner and a quarterly review.", at `medium` confidence).
164
+ - **puffery** (8) inflates the subject: `puffery-words` (vibrant, nestled, groundbreaking, in the heart of), `rich-tapestry`, `vital-role`, `stands-serves-as`, `underscores-highlights`, `impact-noun-vague` ("a significant impact", "make an impact"), `trailing-significance-participle` (the "…, showcasing its importance" clause), `abstract-lives-in` ("the value sits in the follow-up", at `medium` confidence).
165
+ - **false-correction** (8) corrects a reading nobody offered: `not-just-x-but-y`, `not-x-but-y` (the bare corrective), `not-by-x-but-by-y` ("not by luck, but by design"), `isnt-x-its-y` (the same corrective split across two clauses: "It isn't the tool. It's the habit."), `question-isnt` (the corrective frame in interrogative dress), `less-about-more-about`, `actually-not-x`, `dont-verb-it`.
166
+ - **false-concession** (7) performs balance or candour and gives nothing up: `two-things-true`, `none-of-this-is-to-say`, `is-real-and-not`, `not-nothing`, `vague-attribution` ("some critics argue", "it is widely regarded"), `if-im-being-honest` (the candor preamble, from slopwash.com's "false intimacy"), `and-thats-fine`.
167
+ - **reader-address** (6) instructs or flatters the reader: `you-already-know`, `sit-with-that`, `hold-onto-that`, `notice-what`, `notice-what-there`, `quip-question` (the verbless "No invite?", at `medium` confidence).
168
+ - **borrowed-metaphor** (5) an engineering term applied to an argument: `load-bearing`, `failure-mode-here`, `intersection-of`, `impact-verb` ("the outage impacted four thousand accounts"), `impact-noun-bare` ("the impact of X", at `medium` confidence because research prose uses it straight).
169
+ - **punctuation** (2) the mark itself: `em-dash` (any em dash), `em-dash-overuse` (three or more in one paragraph).
163
170
 
164
- Severity is `warning` for strong tells, `info` for weak or contextual ones. No rule currently ships at `error`; the tier is reserved for a pattern with essentially zero false-positive risk, and none has earned that yet.
171
+ Every rule carries two ratings, and they answer different questions. **Severity** is what the construct costs the prose: `error` when the sentence is worse for it in any register (`rich-tapestry`, `puffery-words`, `vague-attribution`), `warning` when it dates the draft as model output but the sentence still says something, `info` when it is mostly harmless and worth knowing (`em-dash`). **Confidence** is how likely the match is a false positive: `high` when almost every hit is the real tell, `medium` when ordinary prose produces the same shape often enough that an agent should read the rationale first, `low` when the pattern cannot tell the tell from the ordinary use at all.
165
172
 
166
- Some tells come in a confident form and an ambiguous one, and those ship as a pair rather than as one rule stretched over both. `no-x-no-y` wants the comma chain a writer clearly authored; `no-x-no-y-frag` takes the same cadence built from sentence fragments, which ordinary prose also produces, and ships at `info`. Same with `not-just-x-but-y` and `not-x-but-y`, and with `notice-what-there` and `notice-what`. The quiet half is still worth flagging — an agent that reads the rationale can judge but it should not carry the same weight as the half we're sure about.
173
+ The two used to be one word, so a cheap tell we were sure about and an expensive one we were guessing at both came out as `warning`. They no longer do. `error` is in use: the puffery family, the tautology closers, and the self-ranking superlatives all cost the sentence something wherever they appear, however sure or unsure we are of the match.
167
174
 
168
- `and-nothing-else` and `nothing-else-frag` are a pair of the same shape, but both ship at `warning`. That is a deliberate exception: the fragment half carries a capital letter and a whole-sentence requirement that the comma half has no equivalent of, so it is the *narrower* of the two rather than the quieter one.
175
+ Some tells come in a confident form and an ambiguous one, and those ship as a pair rather than as one rule stretched over both. `no-x-no-y` wants the comma chain a writer clearly authored; `no-x-no-y-frag` takes the same cadence built from sentence fragments, which ordinary prose also produces, so it ships at `medium` confidence. Same with `not-just-x-but-y` and `not-x-but-y`, and with `notice-what-there` and `notice-what`. The quiet half is still worth flagging — an agent that reads the rationale can judge — but it should not carry the same weight as the half we're sure about. `and-nothing-else` and `nothing-else-frag` are a pair of the same shape and both sit at `high`, because the fragment half carries a capital letter and a whole-sentence requirement that the comma half has no equivalent of, so it is the narrower of the two rather than the quieter one.
169
176
 
170
- Three rules ship **off by default**, and they run only when you name them: `sloplint check --select rule-of-three -`. `rule-of-three` flags three parallel comma items closing a sentence, which humans do all the time. `genuinely` flags every occurrence of the word; as an intensifier it rates the writer's sincerity, but it still does real work when it draws a contrast, and nothing in the sentence separates the two. `epistrophe` flags two clauses ending on the same phrase, a named figure that careful writers use on purpose and that, on Hacker News, is mostly plain phrase reuse.
177
+ The five `low` rules are the ones that run **off by default**. They run when you name them `sloplint check --select rule-of-three -` — or when you pass `--strict`, which runs the whole catalog when you give it no `--select`. `rule-of-three` flags three single words in a comma series closing a sentence, which humans do all the time; the closing two items must be single words, so a triad of phrases does not match, because a regex cannot tell one from an ordinary list. `genuinely` flags every occurrence of the word; as an intensifier it rates the writer's sincerity, but it still does real work when it draws a contrast, and nothing in the sentence separates the two. `epistrophe` flags two clauses ending on the same phrase, a named figure that careful writers use on purpose and that, on Hacker News, is mostly plain phrase reuse. `trailing-restatement` flags the "…, which means …" tail and the participles that hang a result off the sentence ("…, making it easier"); the connective is visible and the restatement is not, so a real consequence flags the same way. `phrase-echo` flags a three-word phrase that comes back within a few hundred words; a term of art comes back because it must, and the pattern cannot tell one from a phrase the writer coined. Naming a category in `--select` only turns on that category's non-low rules; naming the rule's own id runs it regardless. `--strict` on its own runs the whole catalog, but alongside `--select` it only widens the named categories to include their low-confidence members. `sloplint rules --json` lists every rule's `severity`, `confidence` and `rationale`, so an agent can tell which rules are off by default without reading this file.
171
178
 
172
179
  ### Markdown handling
173
180
 
174
- `--markdown` replaces fenced code, inline code, and URLs with same-length whitespace before scanning, so line and column stay correct. Without it, sloplint treats the whole file as prose and will flag text inside your code fences. Pass `--markdown` whenever the input is Markdown.
181
+ `--markdown` replaces fenced code, inline code, HTML comments, and URLs with same-length whitespace before scanning, so line and column stay correct. Without it, sloplint treats the whole file as prose and will flag text inside your code fences. Pass `--markdown` whenever the input is Markdown.
175
182
 
176
183
  ## Adding a rule
177
184
 
@@ -180,14 +187,14 @@ Rules are data, not code. Each is a `Data.define` object in `lib/sloplint/rules.
180
187
  ```ruby
181
188
  Rule.new(
182
189
  id: "rule-id",
183
- category: "rhetorical-tic", # or puffery, structure, hedging
184
- severity: "warning", # or info
190
+ category: "cadence", # one of the nine in the catalog above
191
+ severity: "warning", # what it costs the prose: error, warning, info
192
+ confidence: "high", # false-positive risk: high, medium, low
185
193
  pattern: /.../i,
186
194
  message: "What the reader sees. %{count} interpolates the tally.",
187
195
  suggestion: "One short fix hint.",
188
196
  count_group: /.../i, # optional: a regex tallied over the match
189
197
  skip: [/.../i], # optional: drop the note if these match
190
- default_on: false, # optional: runs only when named in --select
191
198
  examples_bad: ["A sentence the rule must flag."],
192
199
  examples_ok: ["A sentence it must leave alone."],
193
200
  rationale: "Why this is a tell, and what it costs when it's wrong."