sloplint 0.4.0 → 0.5.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 +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +5 -4
- data/docs/SPEC.md +7 -3
- data/lib/sloplint/cli.rb +5 -4
- data/lib/sloplint/rules.rb +78 -0
- data/lib/sloplint/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74566267ccb2ee1d4caec464d3098809e24f232f75872a7df2ac61ef7d583153
|
|
4
|
+
data.tar.gz: 4e3b6196aeb6604d212d00be14032e530a644d4250820424774244fe7298fa9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 41e707ec52643d3f57abe04867d399fef77c8e567378394e4c1e0e2ca541d8aefaa2cb908b9d0e419fc9af9f0a1aedb55adce9ef87fc187628be4a90641a4809
|
|
7
|
+
data.tar.gz: ed1b87c4a32490d582100343d2e7a4b114067737de3761fa3fb768e669f398e69b8c4e3ce4cb33d3138702d533818f5dd53b2b778d8736f848ca71c8166e61f8
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.5.0] - 2026-08-27
|
|
9
|
+
|
|
10
|
+
The catalog grows from 49 rules to 50, and `check` becomes the default
|
|
11
|
+
command.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- A first argument that is not a command name is now taken as a path, so
|
|
16
|
+
`sloplint draft.md` and `sloplint -` scan instead of failing with
|
|
17
|
+
`unknown command`. A mistyped command fails as a missing file, still exit 2.
|
|
18
|
+
|
|
19
|
+
### New rules
|
|
20
|
+
|
|
21
|
+
- `trailing-significance-participle` (`structure`, `warning`): the participle
|
|
22
|
+
clause hung off the end of a sentence to say what a fact means, "the sign
|
|
23
|
+
carries both names, showcasing the range of travellers it draws". An event
|
|
24
|
+
cannot showcase anything, so the claim belongs to a narrator who never
|
|
25
|
+
appears in the text.
|
|
26
|
+
|
|
27
|
+
The verb list is closed and narrow: `highlighting`, `showcasing`,
|
|
28
|
+
`reinforcing`, `shaping`, `enhancing`, `cementing`, `solidifying`,
|
|
29
|
+
`embodying`, `fostering`, `facilitating`, `signalling`. Verbs humans write
|
|
30
|
+
in the same position -- `driving`, `representing`, `reflecting`, `marking`,
|
|
31
|
+
`contributing`, `illustrating`, `demonstrating`, `emphasising`, `echoing`,
|
|
32
|
+
`affirming` -- stay out, because they usually take a person as the subject
|
|
33
|
+
and a regex cannot see the subject. `underscoring` is left to
|
|
34
|
+
`underscores-highlights`.
|
|
35
|
+
|
|
36
|
+
Two guards drop gerund lists: a preceding -ing word means the match is a
|
|
37
|
+
middle list item, and a following comma, "and" or "or" means it is not the
|
|
38
|
+
last item. "signalling to" is the physical gesture and does not flag.
|
|
39
|
+
|
|
8
40
|
## [0.4.0] - 2026-08-26
|
|
9
41
|
|
|
10
42
|
The catalog grows from 29 rules to 49. Every new rule was probed against
|
data/README.md
CHANGED
|
@@ -35,7 +35,7 @@ The recipe sloplint is built around, and the one an agent should use:
|
|
|
35
35
|
cat draft.md | sloplint check --markdown -o json -
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
`--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.
|
|
38
|
+
`--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.
|
|
39
39
|
|
|
40
40
|
The human-readable form drops `-o json`:
|
|
41
41
|
|
|
@@ -62,9 +62,10 @@ The brackets mark the match; the rest is there so you can see what you're fixing
|
|
|
62
62
|
## Commands
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
-
sloplint [-o full|json]
|
|
65
|
+
sloplint [-o full|json] [command] [args]
|
|
66
66
|
|
|
67
67
|
check scan paths (or stdin) for AI-slop tells and report notes [default]
|
|
68
|
+
anything that is not a command name is taken as a path: `sloplint draft.md`
|
|
68
69
|
rules list the rule catalog (add --json for the machine-readable form)
|
|
69
70
|
explain ID print one rule's message, rationale, and a bad/ok example
|
|
70
71
|
version print the sloplint version
|
|
@@ -128,11 +129,11 @@ An unknown id or category in `--select`/`--ignore` is a usage error (exit 2, nam
|
|
|
128
129
|
|
|
129
130
|
## The rule catalog
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
50 rules across four categories. `sloplint rules` prints them; `sloplint rules --json` gives an agent the enumerable form.
|
|
132
133
|
|
|
133
134
|
- **rhetorical-tic** (36) the cadence patterns: `no-x-no-y`, `no-x-no-y-frag`, `thats-the-whole`, `thats-how-x`, `announced-takeaway`, `exact-exactly`, `load-bearing`, `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 more.
|
|
134
135
|
- **puffery** (5) Wikipedia's "signs of AI writing": `puffery-words` (vibrant, nestled, groundbreaking, in the heart of), `rich-tapestry`, `vital-role`, `stands-serves-as`, `underscores-highlights`.
|
|
135
|
-
- **structure** (
|
|
136
|
+
- **structure** (8) `not-just-x-but-y`, `not-x-but-y` (the bare corrective), `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`.
|
|
136
137
|
- **hedging** (1) `vague-attribution`: "some critics argue," "it is widely regarded."
|
|
137
138
|
|
|
138
139
|
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.
|
data/docs/SPEC.md
CHANGED
|
@@ -141,8 +141,11 @@ check options:
|
|
|
141
141
|
--ignore IDS skip these rules
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
`check` is the default command. A first argument that is not a command name is
|
|
145
|
+
taken as a path, so `sloplint draft.md` and `sloplint -` both scan; a mistyped
|
|
146
|
+
command therefore fails as a missing file. Bare `sloplint` with piped stdin
|
|
147
|
+
also behaves as `sloplint check -`. This is the common agent path:
|
|
148
|
+
`cat draft.md | sloplint check --markdown -o json -`.
|
|
146
149
|
|
|
147
150
|
Deliberately left out of v1 (add when a real need shows up, not before):
|
|
148
151
|
`compact` output, `--min-severity`, `--max-notes`, color, `-q/--quiet`, and a
|
|
@@ -252,7 +255,7 @@ Categories (for `--select`/`--ignore` by group):
|
|
|
252
255
|
|
|
253
256
|
- `rhetorical-tic` — the cadence patterns (the user's list below)
|
|
254
257
|
- `puffery` — Wikipedia "words to watch" (boasts, vibrant, nestled, tapestry…)
|
|
255
|
-
- `structure` — rule-of-three, "not just X but Y", "the question isn't X, it's Y", "less about X more about Y", em dash, em-dash overuse
|
|
258
|
+
- `structure` — rule-of-three, "not just X but Y", "the question isn't X, it's Y", "less about X more about Y", the trailing significance participle, em dash, em-dash overuse
|
|
256
259
|
- `hedging` — vague attribution ("some critics argue", "it is widely regarded")
|
|
257
260
|
|
|
258
261
|
Severities: `warning` for strong tells, `info` for weak/contextual ones. No
|
|
@@ -318,6 +321,7 @@ Single flat rule per word-cluster, matched as whole words:
|
|
|
318
321
|
- `not-x-but-y` — the bare corrective "is not X but Y" with no escalation word; `info`, because the corrective/concession distinction is syntactic and the pattern can only approximate it.
|
|
319
322
|
- `question-isnt` — "the question isn't/is not (whether|if|how|what|why|who) X, it's/but Y"; `info`. The resolving clause is required, so a plain rhetorical question never matches; "the real question is" is excluded.
|
|
320
323
|
- `less-about-more-about` — "it's/this is/that's less about X (and) more about Y", also "… than about Y"; `info`. Both halves of the frame are required, and the subject slot is limited to the pronouns.
|
|
324
|
+
- `trailing-significance-participle` — comma plus a participle from a closed verb list (highlighting, showcasing, reinforcing, shaping, enhancing, cementing, solidifying, embodying, fostering, facilitating, signalling), the clause a model hangs off a sentence to say what a fact means. Guards drop gerund lists and "signalling to". `driving`, `representing`, `reflecting`, `marking`, `contributing`, `illustrating`, `demonstrating`, `emphasising`, `echoing` and `affirming` stay out: humans write them in the same position, usually with a person as the subject, and the pattern cannot see the subject. `underscoring` is left to `underscores-highlights`.
|
|
321
325
|
- `rule-of-three` — three parallel comma items ending a sentence (heuristic; `info` severity, off by default via `--select` since it false-positives).
|
|
322
326
|
- `em-dash` — any em dash; `info`.
|
|
323
327
|
- `em-dash-overuse` — 3+ em dashes in one paragraph; `warning`.
|
data/lib/sloplint/cli.rb
CHANGED
|
@@ -33,9 +33,9 @@ module Sloplint
|
|
|
33
33
|
when "version" then out.puts(VERSION); 0
|
|
34
34
|
when "help" then out.puts(parser.help); 0
|
|
35
35
|
else
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
# Anything else is a path or "-": `sloplint FILE`, `sloplint -`.
|
|
37
|
+
# A mistyped command lands here too, and fails as a missing file.
|
|
38
|
+
cmd_check(argv.unshift(command), opts, out:, err:, stdin:)
|
|
39
39
|
end
|
|
40
40
|
rescue OptionParser::ParseError => e
|
|
41
41
|
err.puts("sloplint: #{e.message}")
|
|
@@ -190,10 +190,11 @@ module Sloplint
|
|
|
190
190
|
# exit 0 = clean, 1 = notes found, >1 = error
|
|
191
191
|
# each note: {path,line,column,severity,rule,category,message,excerpt,context,rationale,suggestion}
|
|
192
192
|
|
|
193
|
-
usage: sloplint [-o full|json]
|
|
193
|
+
usage: sloplint [-o full|json] [command] [args]
|
|
194
194
|
|
|
195
195
|
commands:
|
|
196
196
|
check scan paths (or stdin) for AI-slop tells and report notes [default]
|
|
197
|
+
a first argument that is not a command name is taken as a path
|
|
197
198
|
rules list the rule catalog (add --json for the machine-readable form)
|
|
198
199
|
explain ID print one rule's message, rationale, and a bad/ok example
|
|
199
200
|
version print the sloplint version
|
data/lib/sloplint/rules.rb
CHANGED
|
@@ -1358,6 +1358,84 @@ module Sloplint
|
|
|
1358
1358
|
"half is chosen for the contrast, not because a reader proposed it, and " \
|
|
1359
1359
|
"the second half stands on its own."
|
|
1360
1360
|
),
|
|
1361
|
+
Rule.new(
|
|
1362
|
+
id: "trailing-significance-participle",
|
|
1363
|
+
category: "structure",
|
|
1364
|
+
severity: "warning",
|
|
1365
|
+
# The verb list is closed and short on purpose. Wikipedia's "signs of AI
|
|
1366
|
+
# writing" names eight watch words for this construction; half of them
|
|
1367
|
+
# did not survive probing. In 1.85M words of pre-2022 Hacker News and
|
|
1368
|
+
# 2.66M words of public-domain prose, "driving" appears in this position
|
|
1369
|
+
# 14 times, "representing" 16, "reflecting" 10, "marking" 5 -- all of it
|
|
1370
|
+
# ordinary English ("driving the price down", "representing a majority of
|
|
1371
|
+
# the voting power"), and all of it the same shape a model produces, so
|
|
1372
|
+
# no narrowing separates the two. Those verbs are out. The ones that ship
|
|
1373
|
+
# are used in both corpora but never here: "highlighting" appears 17
|
|
1374
|
+
# times in the HN sample and not once after a comma. "underscoring" is
|
|
1375
|
+
# left out because underscores-highlights already flags it bare.
|
|
1376
|
+
#
|
|
1377
|
+
# "emphasizing", "echoing" and "affirming" are out for the same reason,
|
|
1378
|
+
# found late: the shipped pattern flagged four sentences in the
|
|
1379
|
+
# public-domain corpus and all four had a person as the subject. A person
|
|
1380
|
+
# can emphasize or echo something; an event cannot. That is the animacy
|
|
1381
|
+
# distinction the construction really turns on, and a regex cannot see
|
|
1382
|
+
# it, so the verbs that carry a human subject in ordinary prose stay out
|
|
1383
|
+
# rather than being approximated. The narrowed list flags nothing in
|
|
1384
|
+
# either corpus.
|
|
1385
|
+
#
|
|
1386
|
+
# "ensuring" is also out, despite scoring 1 hit in each corpus: neither
|
|
1387
|
+
# corpus contains software documentation, where "the mutex is held,
|
|
1388
|
+
# ensuring no two writers collide" states a real consequence rather than
|
|
1389
|
+
# claiming significance.
|
|
1390
|
+
#
|
|
1391
|
+
# Two guards keep gerund lists out. A preceding -ing word means the match
|
|
1392
|
+
# is the second item of a list ("cutting, shaping stone"), and a
|
|
1393
|
+
# following comma, "and", or "or" means it is not the last ("cutting,
|
|
1394
|
+
# shaping and sanding"). "signaling to" is the physical gesture.
|
|
1395
|
+
pattern: /\w+(?<!ing),[ \t]+
|
|
1396
|
+
(?:further[ \t]+|thereby[ \t]+|thus[ \t]+|ultimately[ \t]+)?
|
|
1397
|
+
(?:highlighting|showcasing|reinforcing|shaping|enhancing|
|
|
1398
|
+
cementing|solidifying|embodying|fostering|facilitating|
|
|
1399
|
+
signall?ing(?![ \t]+to\b))
|
|
1400
|
+
(?![ \t]*(?:,|and\b|or\b))
|
|
1401
|
+
[ \t]+\S/ix,
|
|
1402
|
+
message: "Trailing -ing clause claiming significance -- a stock AI move.",
|
|
1403
|
+
suggestion: "Cut the clause, or state the consequence as its own sentence with a subject.",
|
|
1404
|
+
examples_bad: [
|
|
1405
|
+
"The bridge reopened in March, cementing its place in the city's skyline.",
|
|
1406
|
+
"Attendance doubled that year, highlighting the appeal of the new format.",
|
|
1407
|
+
"Its sign carries both languages, showcasing the range of visitors it draws.",
|
|
1408
|
+
"Trade routes crossed here for centuries, shaping the food people cook.",
|
|
1409
|
+
"The grant was renewed, further solidifying the lab's standing.",
|
|
1410
|
+
"The team shipped every week, reinforcing the sense that momentum mattered.",
|
|
1411
|
+
"The colour was mixed by hand, embodying the care the shop is known for.",
|
|
1412
|
+
"The lab was refitted last year, enhancing what the group can measure.",
|
|
1413
|
+
"The station sits beside the port, facilitating the movement of goods inland."
|
|
1414
|
+
],
|
|
1415
|
+
examples_ok: [
|
|
1416
|
+
# The verb in its ordinary position, with a person or document as subject.
|
|
1417
|
+
"The report highlights the two findings that changed our minds.",
|
|
1418
|
+
"She emphasises the method rather than the results.",
|
|
1419
|
+
# Gerund lists: the match is a middle item, not a trailing clause.
|
|
1420
|
+
"The work involves cutting, shaping and polishing the stone.",
|
|
1421
|
+
"They spent the morning cutting, shaping stone for the wall.",
|
|
1422
|
+
"The class covers drawing, shaping, then firing the clay.",
|
|
1423
|
+
# The physical gesture, not a claim about meaning.
|
|
1424
|
+
"He turned toward the bar, signaling to the waiter.",
|
|
1425
|
+
# War and Peace (Maude translation, public domain): a person as the
|
|
1426
|
+
# subject, which is the case the verb list cannot distinguish, so
|
|
1427
|
+
# "emphasizing", "echoing" and "affirming" are excluded outright.
|
|
1428
|
+
"recounted Bitski, emphasizing certain words and opening his eyes",
|
|
1429
|
+
"\u201cOu-rou-rou!\u201d yelled the crowd, echoing the crash of the roof",
|
|
1430
|
+
# A paragraph break is not a comma.
|
|
1431
|
+
"The kiln runs hot\n\nShaping the clay comes first."
|
|
1432
|
+
],
|
|
1433
|
+
rationale: "A participle hung off the end of a sentence, with a fact or an event as " \
|
|
1434
|
+
"its subject, asserts what something means without anyone having to say it. " \
|
|
1435
|
+
"An event cannot highlight or showcase anything; the claim belongs to a " \
|
|
1436
|
+
"narrator who never appears. Careful writers put the verb in its own clause " \
|
|
1437
|
+
"with a subject, or leave the significance to the reader."
|
|
1438
|
+
),
|
|
1361
1439
|
# ── hedging ───────────────────────────────────────────────────────────
|
|
1362
1440
|
Rule.new(
|
|
1363
1441
|
id: "vague-attribution",
|
data/lib/sloplint/version.rb
CHANGED