zero-slop 2.8.9 → 2.8.11
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.
- package/README.md +209 -192
- package/SKILL.md +27 -5
- package/package.json +1 -1
- package/references/eval.md +4 -1
- package/scripts/rescue.py +156 -0
- package/scripts/slopscore.py +15 -0
package/README.md
CHANGED
|
@@ -1,54 +1,60 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://zero-slop.ai">
|
|
3
|
+
<img src="assets/logo/logo-mark-512.png" width="112" alt="Zero Slop">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">Zero Slop</h1>
|
|
8
|
+
|
|
9
|
+
<p align="center"><strong>Find AI-sounding writing. Keep the source intact.</strong></p>
|
|
2
10
|
|
|
3
11
|
<p align="center">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<img alt="dependencies" src="https://img.shields.io/badge/runtime%20dependencies-0-227B5B">
|
|
7
|
-
<img alt="privacy" src="https://img.shields.io/badge/learning-private-227B5B">
|
|
8
|
-
<img alt="version" src="https://img.shields.io/badge/version-2.8.9-72528F">
|
|
9
|
-
<a href="https://hol.org/guard/plugins"><img alt="Listed in the HOL plugin registry" src="https://img.shields.io/badge/HOL%20registry-listed-2C6E8F"></a>
|
|
10
|
-
<a href="https://github.com/hashgraph-online/awesome-ai-plugins#tools--integrations"><img alt="Listed in awesome-ai-plugins" src="https://img.shields.io/badge/awesome--ai--plugins-listed-2C6E8F"></a>
|
|
11
|
-
<a href="https://zero-slop.ai/try/"><img alt="This README scores 11.6 out of 100 on the slop score, inside the human range" src="https://img.shields.io/badge/slop%20score-11.6%2F100-0f7d55"></a>
|
|
12
|
+
Zero Slop finds stock phrasing, mechanical rhythm, vague claims, and canned formatting.<br>
|
|
13
|
+
Your existing AI assistant edits the draft; local checks guard its names, numbers, links, quotations, code, tables, and paths.
|
|
12
14
|
</p>
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="https://zero-slop.ai/try/"><strong>Try it in your browser</strong></a>
|
|
18
|
+
·
|
|
19
|
+
<a href="#install">Install the skill</a>
|
|
20
|
+
·
|
|
21
|
+
<a href="#evidence-and-limits">See the evidence</a>
|
|
22
|
+
·
|
|
23
|
+
<a href="https://github.com/manavmishra/ZeroSlop/releases/latest">Latest release</a>
|
|
24
|
+
</p>
|
|
15
25
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
<p align="center">
|
|
27
|
+
<a href="https://github.com/manavmishra/ZeroSlop/actions/workflows/validate.yml"><img alt="Validate" src="https://github.com/manavmishra/ZeroSlop/actions/workflows/validate.yml/badge.svg"></a>
|
|
28
|
+
<img alt="Version 2.8.11" src="https://img.shields.io/badge/version-2.8.11-72528F">
|
|
29
|
+
<a href="https://www.npmjs.com/package/zero-slop"><img alt="npm version" src="https://img.shields.io/npm/v/zero-slop?color=72528F"></a>
|
|
30
|
+
<a href="https://www.npmjs.com/package/zero-slop"><img alt="npm downloads" src="https://img.shields.io/npm/dm/zero-slop?color=227B5B"></a>
|
|
31
|
+
<a href="https://github.com/manavmishra/ZeroSlop/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/manavmishra/ZeroSlop?style=flat&color=b0442a"></a>
|
|
32
|
+
<a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-202521"></a>
|
|
33
|
+
<a href="https://hol.org/guard/plugins"><img alt="Listed in the HOL plugin registry" src="https://img.shields.io/badge/HOL%20registry-listed-2C6E8F"></a>
|
|
34
|
+
</p>
|
|
20
35
|
|
|
21
36
|
```sh
|
|
22
|
-
npx
|
|
37
|
+
npx skills add manavmishra/ZeroSlop --global
|
|
23
38
|
```
|
|
24
39
|
|
|
25
|
-
|
|
40
|
+
<a href="assets/zero-slop-demo.mp4">
|
|
41
|
+
<picture>
|
|
42
|
+
<source media="(prefers-reduced-motion: reduce)" srcset="assets/zero-slop-demo-poster.png">
|
|
43
|
+
<source type="image/webp" srcset="assets/zero-slop-demo.webp">
|
|
44
|
+
<img src="assets/zero-slop-demo.gif" width="960" alt="Terminal demo: install Zero Slop, ask your AI assistant to edit a draft with /zero-slop, then review the edit and source checks.">
|
|
45
|
+
</picture>
|
|
46
|
+
</a>
|
|
47
|
+
|
|
48
|
+
<p align="center"><a href="assets/zero-slop-demo.mp4">Download the 36-second demo</a> · <sub>Reconstructed skill session; hosted outputs vary.</sub></p>
|
|
26
49
|
|
|
27
|
-
|
|
50
|
+
## Before and after
|
|
28
51
|
|
|
29
52
|
A launch post, as AI wrote it:
|
|
30
53
|
|
|
31
|
-
> We're thrilled to announce that our team has leveraged cutting-edge
|
|
54
|
+
> We're thrilled to announce that our team has leveraged cutting-edge machine learning to deliver a seamless onboarding experience, reducing setup time by 40%.
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```text
|
|
36
|
-
Writing score: 100.0/100 [major rewrite]
|
|
37
|
-
Flagged phrases : 11 across 83 words
|
|
38
|
-
Sentence variety: too even
|
|
39
|
-
Main issues : canned LinkedIn phrase, promotional language, manufactured
|
|
40
|
-
stakes, two-part contrast used as a formula, performed
|
|
41
|
-
writer's voice, buzzword used as promotion
|
|
42
|
-
|
|
43
|
-
Flagged phrases (11), strongest first:
|
|
44
|
-
"In today's fast-paced" manufactured stakes; start where the reader needs to start
|
|
45
|
-
"We're thrilled to" canned LinkedIn phrase; say what happened without the stock opening
|
|
46
|
-
"It's not just a redesign, it's"
|
|
47
|
-
two-part contrast used as a formula; state the claim once, plainly
|
|
48
|
-
"Here's the thing" performed writer's voice; say the thing plainly
|
|
49
|
-
'cutting-edge' promotional language; name what it does; cut the adjectives
|
|
50
|
-
'leveraged' buzzword used as promotion; use the plain word
|
|
51
|
-
```
|
|
56
|
+
The scorer rates that draft 99.3/100 and flags four phrases: “We're thrilled
|
|
57
|
+
to,” “leveraged,” “cutting-edge,” and “seamless.”
|
|
52
58
|
|
|
53
59
|
The rewrite, limited to the draft's stated claims:
|
|
54
60
|
|
|
@@ -59,240 +65,251 @@ Writing score: 9.5/100 [clear]
|
|
|
59
65
|
Flagged phrases : 0 across 10 words
|
|
60
66
|
```
|
|
61
67
|
|
|
62
|
-
|
|
68
|
+
The rewrite retains the draft's stated result. See four complete, reproducible pairs in [`examples/`](examples/).
|
|
63
69
|
|
|
64
|
-
|
|
65
|
-
"Here's the thing nobody tells you." Repeated wording, uniform rhythm, and
|
|
66
|
-
overworked formatting can have the same effect.
|
|
70
|
+
## What can I use it for?
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
- Tighten a launch post without losing the release details.
|
|
73
|
+
- Turn a padded product update into a useful changelog.
|
|
74
|
+
- Clean up an email while preserving names, dates, and numbers.
|
|
75
|
+
- Edit a research summary without flattening its qualifications.
|
|
76
|
+
- Gate a folder of generated copy before it ships.
|
|
71
77
|
|
|
72
|
-
|
|
78
|
+
Zero Slop is a writing tool. It does not detect authorship; its score describes the text.
|
|
73
79
|
|
|
74
|
-
|
|
80
|
+
## Install
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
Install the Zero Slop skill globally from https://github.com/manavmishra/ZeroSlop
|
|
78
|
-
```
|
|
82
|
+
To try Zero Slop first, paste a draft into [zero-slop.ai/try](https://zero-slop.ai/try/). The free editor returns the edit, the before-and-after scores, and the exact phrases that triggered the scorer.
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
The portable installer works with Claude Code, Codex, Cursor, OpenCode, Warp, Zed, and other Agent Skills-compatible tools:
|
|
81
85
|
|
|
82
86
|
```sh
|
|
83
87
|
npx skills add manavmishra/ZeroSlop --global
|
|
84
88
|
```
|
|
85
89
|
|
|
86
|
-
Or
|
|
90
|
+
Or use the package-specific installer and scoring command:
|
|
87
91
|
|
|
88
92
|
```sh
|
|
89
|
-
npx zero-slop install
|
|
90
|
-
npx zero-slop score draft.md
|
|
93
|
+
npx zero-slop install
|
|
94
|
+
npx zero-slop score draft.md
|
|
91
95
|
```
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
Claude.ai users can upload the [release ZIP](https://github.com/manavmishra/ZeroSlop/releases/latest/download/zero-slop.zip).
|
|
97
|
+
Choose a harness explicitly when needed:
|
|
95
98
|
|
|
96
|
-
|
|
99
|
+
```sh
|
|
100
|
+
npx zero-slop install --harness codex
|
|
101
|
+
# claude | codex | cursor | opencode | zed
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Environment | Fastest route |
|
|
105
|
+
|---|---|
|
|
106
|
+
| Claude Code, Codex, Cursor, OpenCode, Warp, Zed | `npx skills add manavmishra/ZeroSlop --global` |
|
|
107
|
+
| Any assistant with file uploads | Download the [single-file bundle](https://github.com/manavmishra/ZeroSlop/releases/latest/download/zero-slop-single-file.md) |
|
|
108
|
+
| Claude.ai | Upload the [latest skill ZIP](https://github.com/manavmishra/ZeroSlop/releases/latest/download/zero-slop.zip) |
|
|
109
|
+
| ChatGPT or another MCP client | Connect the optional [hosted MCP server](mcp/README.md) |
|
|
110
|
+
|
|
111
|
+
Once installed, ask your AI assistant to edit a draft:
|
|
97
112
|
|
|
98
113
|
```text
|
|
99
114
|
/zero-slop (your writing)
|
|
100
115
|
```
|
|
101
116
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
117
|
+
Inspect a draft without changing it:
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
/zero-slop inspect (your writing)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Score a file locally:
|
|
105
124
|
|
|
106
|
-
|
|
125
|
+
```sh
|
|
126
|
+
npx zero-slop score draft.md
|
|
127
|
+
```
|
|
107
128
|
|
|
108
|
-
|
|
109
|
-
Put yours up the same way:
|
|
129
|
+
From a cloned checkout, gate a folder:
|
|
110
130
|
|
|
111
|
-
```
|
|
112
|
-
|
|
131
|
+
```sh
|
|
132
|
+
python3 scripts/slopscore.py --batch drafts/ --gate 25
|
|
113
133
|
```
|
|
114
134
|
|
|
115
|
-
|
|
116
|
-
|
|
135
|
+
Installed checks run locally; editing follows your AI assistant's privacy settings. The optional hosted MCP processes drafts remotely. See its [privacy details](mcp/README.md).
|
|
136
|
+
|
|
137
|
+
### Prefer one hosted connection? Use the MCP
|
|
117
138
|
|
|
118
|
-
|
|
139
|
+
Connect the [Zero Slop MCP](https://zero-slop.ai/#mcp) once to edit drafts inside your MCP client. Its `deslop` tool returns the edit, before-and-after scores, and review status. Zero Slop requires no account or API key; server updates are managed for you.
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
https://mcp.zero-slop.ai/mcp
|
|
143
|
+
```
|
|
119
144
|
|
|
120
|
-
|
|
145
|
+
```sh
|
|
146
|
+
# Codex
|
|
147
|
+
codex mcp add zero-slop --url https://mcp.zero-slop.ai/mcp
|
|
121
148
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
4. Colon reveals: "The best part: it learns."
|
|
126
|
-
5. Dramatic fragments: "That's it. That's the whole thing."
|
|
127
|
-
6. Superficial analysis: "highlighting the team's commitment to innovation"
|
|
128
|
-
7. Importance puffery: "marks a pivotal moment," "a testament to"
|
|
129
|
-
8. Weasel attribution: "experts agree," "studies show"
|
|
130
|
-
9. Synonym cycling: the agent, the assistant, the tool, all one thing.
|
|
131
|
-
10. Marketing riders: "robust" and "leverage" score only beside a marketing trigger, so a runbook stays quiet.
|
|
149
|
+
# Claude Code
|
|
150
|
+
claude mcp add --transport http zero-slop --scope user https://mcp.zero-slop.ai/mcp
|
|
151
|
+
```
|
|
132
152
|
|
|
133
|
-
|
|
134
|
-
shuffle without loss. [`references/eval.md`](references/eval.md) has all 80 checks.
|
|
153
|
+
Follow the [MCP setup guide](https://zero-slop.ai/#mcp) for ChatGPT and other clients.
|
|
135
154
|
|
|
136
|
-
|
|
137
|
-
unedited AI drafts averaged 77 across [`bench/examples.json`](bench/examples.json).
|
|
155
|
+
## What the workflow adds
|
|
138
156
|
|
|
157
|
+
| A prompt alone | Zero Slop |
|
|
158
|
+
|---|---|
|
|
159
|
+
| “Make this sound human” leaves the target vague. | A 0–100 meter points to exact phrases and structural problems. |
|
|
160
|
+
| One rewrite can quietly alter source details. | A local fact gate checks protected strings before the edit is returned. |
|
|
161
|
+
| The model tends to overcorrect into fragments or forced casualness. | An overcorrection pass checks readability, rhythm, grammar, and voice. |
|
|
162
|
+
| Each session starts from scratch. | Optional, reason-labelled preferences can be learned privately. |
|
|
139
163
|
|
|
140
|
-
|
|
164
|
+
Zero Slop ships no model. Your AI assistant reads and edits the draft in context,
|
|
165
|
+
using Claude, GPT, or another compatible model. The repository supplies the
|
|
166
|
+
workflow and local tools for scoring and source checks.
|
|
141
167
|
|
|
142
|
-
|
|
168
|
+
## What it catches
|
|
143
169
|
|
|
144
|
-
|
|
145
|
-
installed assistant can isolate them.
|
|
146
|
-
The free web editor combines
|
|
147
|
-
the five AI responsibilities into one model response, then runs the scorer and source
|
|
148
|
-
checks locally. It makes at most one live model call and never describes that response
|
|
149
|
-
as independent review. The research supports the checks, not the number eight, which
|
|
150
|
-
is an engineering choice.
|
|
170
|
+
The current scorer combines 294 weighted patterns with a 96-term lexicon. Examples include:
|
|
151
171
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
| 5. Copy desk | Your AI assistant | Corrects grammar, spelling, usage, and consistency in the actual deliverable. |
|
|
159
|
-
| 6. Read-aloud editor | Your AI assistant | Fixes stumbles, repetition, weak transitions, and awkward flow. |
|
|
160
|
-
| 7. Verifier | Local tools and your AI assistant | Compares text with source for facts, meaning, qualifiers, voice, format, structure. In the web editor, source safety is checked locally. |
|
|
161
|
-
| 8. Fresh-eyes finalizer | Your AI assistant | Reads the finished text as a first-time reader and applies only safe polish. Any change receives one final local recheck. |
|
|
172
|
+
- binary contrast formulas: “It's not X. It's Y.”
|
|
173
|
+
- canned openers: “We're thrilled to…” and “Here's the thing…”
|
|
174
|
+
- vague attribution: “experts agree” and “studies show”
|
|
175
|
+
- significance inflation: “marks a pivotal moment” and “a testament to”
|
|
176
|
+
- promotional riders: “robust,” “seamless,” and “leverage” when used as hype
|
|
177
|
+
- repeated sentence shapes, crowded statistics, and overworked formatting
|
|
162
178
|
|
|
163
|
-
|
|
164
|
-
Slop permits one targeted repair and one local recheck, then returns the safest
|
|
165
|
-
source-preserving edit with a plain warning. On the website, a failed model call falls
|
|
166
|
-
back to a conservative local edit instead of retrying through more providers.
|
|
179
|
+
Marketing terms are scored in context, so an ordinary technical use of a word need not trigger the same penalty. [`references/eval.md`](references/eval.md) documents all 80 checks.
|
|
167
180
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
[
|
|
171
|
-
|
|
172
|
-
tools use only Python's standard library.
|
|
181
|
+
Unedited AI drafts averaged 77 in [`bench/examples.json`](bench/examples.json).
|
|
182
|
+
Human writing scored 9 to 21 in
|
|
183
|
+
[`data/corpus/must-not-flag/`](data/corpus/must-not-flag/). These are reference
|
|
184
|
+
points for the scorer, not authorship boundaries.
|
|
173
185
|
|
|
174
|
-
##
|
|
186
|
+
## How it works
|
|
175
187
|
|
|
176
|
-
|
|
177
|
-
Zero Slop does not monitor files, browsers, or publishing tools.
|
|
188
|
+

|
|
178
189
|
|
|
179
|
-
|
|
190
|
+
Eight responsibilities form one workflow. They are jobs, not separate models.
|
|
191
|
+
Research supports the checks, not the number eight, which is an engineering
|
|
192
|
+
choice.
|
|
180
193
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
194
|
+
| Stage | Job |
|
|
195
|
+
|---|---|
|
|
196
|
+
| 1. Scorer | Find exact phrases, pacing problems, readability issues, and overworked formatting. |
|
|
197
|
+
| 2. Interpreter | Read the claims, audience, structure, and voice before editing. |
|
|
198
|
+
| 3. Rewriter | Remove stock language without inventing detail. |
|
|
199
|
+
| 4. Fact gate | Check names, numbers, quotations, links, code, tables, paths, and structure locally. |
|
|
200
|
+
| 5. Copy desk | Fix grammar, usage, spelling, and consistency. |
|
|
201
|
+
| 6. Read-aloud editor | Catch stumbles, repetition, and awkward transitions. |
|
|
202
|
+
| 7. Verifier | Compare the edit with the source for meaning, qualifiers, voice, and format. |
|
|
203
|
+
| 8. Fresh-eyes finalizer | Apply only safe final polish, then run one last local check. |
|
|
184
204
|
|
|
185
|
-
|
|
205
|
+
The free web editor combines the five AI responsibilities into one response and
|
|
206
|
+
makes at most one live model call. A single response does not provide independent review.
|
|
207
|
+
Any final change receives one final local recheck.
|
|
186
208
|
|
|
187
|
-
|
|
188
|
-
80 checks. [`scripts/slopscore.py`](scripts/slopscore.py) is the meter and fact gate,
|
|
189
|
-
with [`scripts/register.py`](scripts/register.py) running the reading pass.
|
|
190
|
-
[`bench/README.md`](bench/README.md) documents every benchmark with its limits.
|
|
191
|
-
[zero-slop.ai](https://zero-slop.ai) has the same reference as browsable pages, plus the [benchmark in full](https://zero-slop.ai/benchmark/).
|
|
209
|
+
If a repair still misses the target, Zero Slop returns the safest source-preserving edit with a plain warning. It does not enter an open-ended rewrite loop.
|
|
192
210
|
|
|
193
|
-
##
|
|
211
|
+
## Evidence and limits
|
|
194
212
|
|
|
195
|
-
###
|
|
213
|
+
### Same model, same 18 drafts
|
|
196
214
|
|
|
197
|
-
|
|
198
|
-
[no-ai-slop](https://github.com/petergyang/no-ai-slop) and
|
|
199
|
-
[humanizer](https://github.com/blader/humanizer) over 18 drafts with GPT-5.4, high
|
|
200
|
-
reasoning, and pinned instructions. Zero Slop's outputs came from v2.5.9; later
|
|
201
|
-
releases only rescore those frozen outputs.
|
|
215
|
+
A saved replay ran Zero Slop and three comparable open-source instruction sets over the same drafts with GPT-5.4, high reasoning, and pinned instructions. The outputs are frozen and reproducible.
|
|
202
216
|
|
|
203
|
-
| Method | Mean writing score ↓ | Passed
|
|
217
|
+
| Method | Mean writing score ↓ | Passed local gates | Source check passed | Mean length change |
|
|
204
218
|
|---|---:|---:|---:|---:|
|
|
205
219
|
| Original drafts | 76.3 | 0/18 | — | — |
|
|
206
|
-
| Zero Slop | 12.8 | 18/18 | 18/18 | -8.9% |
|
|
220
|
+
| **Zero Slop** | **12.8** | **18/18** | **18/18** | -8.9% |
|
|
207
221
|
| avoid-ai-writing | 23.3 | 15/18 | 18/18 | -14.6% |
|
|
208
222
|
| no-ai-slop | 28.4 | 12/18 | 17/18 | -13.7% |
|
|
209
223
|
| humanizer | 35.4 | 9/18 | 17/18 | -7.2% |
|
|
210
224
|
|
|
211
|
-

|
|
225
|
+

|
|
212
226
|
|
|
227
|
+
This small LLM-reviewed regression study measures repeatable behavior; it does not establish universal writing quality. The drafts, hashes, method versions, prompts, and limitations are in [`bench/README.md`](bench/README.md).
|
|
213
228
|
|
|
229
|
+
Zero Slop's frozen outputs came from v2.5.9; newer versions only rescore those
|
|
230
|
+
saved outputs. The current scorer matched the prior 84.2% result on the fixed
|
|
231
|
+
38-item editorial panel. These fixed-sample checks are not field accuracy.
|
|
214
232
|
|
|
215
|
-
|
|
233
|
+
<details>
|
|
234
|
+
<summary>More validation</summary>
|
|
216
235
|
|
|
217
|
-
|
|
236
|
+
- A method-hidden editorial preference replay: [`bench/incumbent-blind-replay/`](bench/incumbent-blind-replay/)
|
|
237
|
+
- External-checker clean rates: [`assets/bench-external-checker.png`](assets/bench-external-checker.png)
|
|
238
|
+
- Method-hidden quality ranking: [`assets/bench-blind-quality.png`](assets/bench-blind-quality.png)
|
|
239
|
+
- Current-model corpus measurements: [`assets/bench-raid-plus.png`](assets/bench-raid-plus.png)
|
|
240
|
+
- Antithesis regression set: [`assets/bench-antithesis.png`](assets/bench-antithesis.png)
|
|
218
241
|
|
|
219
|
-
|
|
242
|
+
On the 75 labelled antithesis pairs, the current reading pass reached 91.2% recall across the full set, 100% recall on shapes in reach, and 100% precision. The labels are maintainer-authored and the pairs are constructed, so this is a regression floor rather than field accuracy.
|
|
220
243
|
|
|
221
|
-
|
|
244
|
+
Local speed measurements cover the checks, with editing time excluded. On one
|
|
245
|
+
Apple silicon Mac, the scorer processed 1,000 documents in a median of 1.9929
|
|
246
|
+
seconds (501.8 per second); the five runs ranged from 1.9614 to 2.0945 seconds.
|
|
247
|
+
It scored a 15,201-word document in a median of 0.3223 seconds. The slowest
|
|
248
|
+
stress case took 2.2932 seconds, and learning from an 8,000-word edit took
|
|
249
|
+
0.1592 seconds. The measurements and machine details are in
|
|
250
|
+
[`bench/performance-results.json`](bench/performance-results.json).
|
|
222
251
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
[`bench/incumbent-blind-replay/`](bench/incumbent-blind-replay/).
|
|
252
|
+
Across 12 interleaved runs against 2.7.7, we measured 0.54% lower median throughput,
|
|
253
|
+
which is effectively unchanged. The separate two-way replay used
|
|
254
|
+
Zero Slop v2.6.0.
|
|
227
255
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
proof of general accuracy.
|
|
256
|
+
The [RAID+ audit](bench/raid-plus-corpus/README.md) checks how the scorer responds
|
|
257
|
+
to output from different models. Its pinned sample contains 7,627 usable
|
|
258
|
+
generations:
|
|
232
259
|
|
|
233
|
-
|
|
260
|
+
| Model | Texts scored | Mean writing score ↓ | At or above 25 |
|
|
261
|
+
|---|---:|---:|---:|
|
|
262
|
+
| DeepSeek V3 | 1,995 | 14.5 | 10.1% |
|
|
263
|
+
| Gemini 3.1 Pro | 1,998 | 17.0 | 18.2% |
|
|
264
|
+
| Gemma 3 27B | 1,634 | 21.6 | 30.4% |
|
|
265
|
+
| Llama 3.3 70B | 2,000 | 25.5 | 41.7% |
|
|
234
266
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
median throughput was 0.26% lower, effectively no difference. Editing is excluded.
|
|
267
|
+
RAID+ labels record which model produced each text; they do not grade writing
|
|
268
|
+
quality. The [Beemo paired-edit audit](bench/beemo-corpus/README.md) checks how
|
|
269
|
+
scores change after human editing: raw responses averaged 30.2, expert edits
|
|
270
|
+
25.3, and human answers 20.0. Beemo also lacks writing-quality labels.
|
|
240
271
|
|
|
241
|
-
|
|
272
|
+
</details>
|
|
242
273
|
|
|
243
|
-
|
|
244
|
-
before the budget means anything. On 75 labelled pairs in
|
|
245
|
-
[`bench/antithesis/`](bench/antithesis/):
|
|
274
|
+
### Documented capability audit
|
|
246
275
|
|
|
247
|
-
|
|
248
|
-
|---|---:|---:|
|
|
249
|
-
| Recall, all shapes | 40.0% | 91.2% |
|
|
250
|
-
| Recall, shapes in reach | 44.4% | 100% |
|
|
251
|
-
| Precision | 80.0% | 100% |
|
|
252
|
-
| False positives | 3 | 0 |
|
|
276
|
+

|
|
253
277
|
|
|
254
|
-
|
|
255
|
-
|
|
278
|
+
This chart says nothing about writing quality or which tool writes better. It
|
|
279
|
+
records documented features at pinned commits; the data and reproduction notes
|
|
280
|
+
are in [`bench/README.md`](bench/README.md).
|
|
256
281
|
|
|
257
|
-
|
|
282
|
+
The design follows research on [predictable wording in machine text](https://arxiv.org/abs/2301.11305) and [overused vocabulary](https://arxiv.org/abs/2406.07016). It deliberately avoids authorship claims because detectors can [misclassify non-native English](https://arxiv.org/abs/2304.02819).
|
|
258
283
|
|
|
259
|
-
|
|
260
|
-
are identical to ordinary prose on every lexical statistic. Maintainer labels on
|
|
261
|
-
constructed pairs, so this is a regression floor, not field accuracy.
|
|
284
|
+
## Private learning
|
|
262
285
|
|
|
263
|
-
|
|
286
|
+
Learning begins only when you provide an original output and your reason-labelled edit. Zero Slop does not monitor files, browsers, or publishing tools. Private data stays under `$ZERO_SLOP_HOME`; it is not committed to this repository and does not retrain the model.
|
|
264
287
|
|
|
265
|
-
|
|
266
|
-
|
|
288
|
+
A profile selected by name can exempt existing watchlist words. It does not
|
|
289
|
+
learn cadence, tone, or a complete writing style.
|
|
267
290
|
|
|
268
|
-
|
|
269
|
-
|---|---:|---:|---:|
|
|
270
|
-
| DeepSeek V3 | 1,995 | 14.5 | 10.1% |
|
|
271
|
-
| Gemini 3.1 Pro | 1,998 | 17.0 | 18.2% |
|
|
272
|
-
| Gemma 3 27B | 1,634 | 21.6 | 30.4% |
|
|
273
|
-
| Llama 3.3 70B | 2,000 | 25.5 | 41.7% |
|
|
291
|
+
## Repository map
|
|
274
292
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
293
|
+
| Path | Purpose |
|
|
294
|
+
|---|---|
|
|
295
|
+
| [`SKILL.md`](SKILL.md) | The complete detect, rewrite, verify, and learn workflow |
|
|
296
|
+
| [`scripts/slopscore.py`](scripts/slopscore.py) | Offline meter and source-detail gate |
|
|
297
|
+
| [`scripts/register.py`](scripts/register.py) | Performed-register and reading pass |
|
|
298
|
+
| [`references/`](references/) | Genre guidance, tells, safeguards, and evaluation rules |
|
|
299
|
+
| [`examples/`](examples/) | Reproducible before-and-after edits |
|
|
300
|
+
| [`bench/`](bench/) | Frozen benchmarks, provenance, and limitations |
|
|
301
|
+
| [`mcp/`](mcp/) | Optional hosted MCP server documentation |
|
|
278
302
|
|
|
279
|
-
##
|
|
303
|
+
## Contributing and support
|
|
280
304
|
|
|
281
|
-
|
|
282
|
-
and avoid-ai-writing. It adds a writing score, source protection, separate editorial
|
|
283
|
-
passes, private learning, portfolio analysis, and release tests.
|
|
305
|
+
Bug reports, false positives, examples, and carefully tested pattern improvements are welcome. Read [`CONTRIBUTING.md`](CONTRIBUTING.md) before opening a pull request, use the structured [issue forms](https://github.com/manavmishra/ZeroSlop/issues/new/choose), or start a [Discussion](https://github.com/manavmishra/ZeroSlop/discussions).
|
|
284
306
|
|
|
285
|
-
|
|
307
|
+
For setup help and responsible disclosure, see [`SUPPORT.md`](SUPPORT.md) and [`SECURITY.md`](SECURITY.md).
|
|
286
308
|
|
|
287
|
-
|
|
309
|
+
## Credits
|
|
288
310
|
|
|
289
|
-
|
|
290
|
-
python3 tests/test_all.py
|
|
291
|
-
python3 scripts/calibrate.py --selftest
|
|
292
|
-
python3 scripts/register.py --selftest
|
|
293
|
-
python3 bench/make_charts.py --check
|
|
294
|
-
```
|
|
311
|
+
Zero Slop builds on ideas from [no-ai-slop](https://github.com/petergyang/no-ai-slop), [humanizer](https://github.com/blader/humanizer), [de-slop](https://github.com/isatimur/de-slop), [stop-slop](https://github.com/hardikpandya/stop-slop), [unslop-text](https://github.com/JCarterJohnson/vibecoded-design-tells/tree/main/unslop-ai-text), and [avoid-ai-writing](https://github.com/conorbronsdon/avoid-ai-writing).
|
|
295
312
|
|
|
296
313
|
## License
|
|
297
314
|
|
|
298
|
-
MIT
|
|
315
|
+
[MIT](LICENSE)
|
package/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: zero-slop
|
|
3
3
|
license: MIT
|
|
4
4
|
metadata:
|
|
5
|
-
version: "2.8.
|
|
5
|
+
version: "2.8.11"
|
|
6
6
|
author: manavmishra
|
|
7
7
|
description: Turn drafts into sharp, natural prose or inspect them without rewriting. Zero Slop runs inside the user's existing AI assistant; Claude, GPT, or another compatible model reads and edits in context while local tools point to exact phrases and protect the source. Use when the user asks to humanize or de-slop writing, inspect AI-sounding patterns, fix text that reads like ChatGPT, polish outward-facing prose, draft social or LinkedIn content, or apply a final quality check to prose the agent generated. The workflow preserves facts, voice, and format and learns privately from repeated, reason-labelled human edits.
|
|
8
8
|
---
|
|
@@ -80,7 +80,22 @@ not eight models or services. In an installed assistant, use role-isolated passe
|
|
|
80
80
|
the harness can do that without extra network calls. When a service has a one-request
|
|
81
81
|
budget, combine the AI responsibilities into one structured editorial response and
|
|
82
82
|
run the local checks before and after it. Name that consolidation honestly; one model
|
|
83
|
-
response is not independent review.
|
|
83
|
+
response is not independent review.
|
|
84
|
+
|
|
85
|
+
Preserve source material rather than sentence count. Delete before rewriting: keep
|
|
86
|
+
a sentence when it adds a fact, position, reason, example, instruction, or necessary
|
|
87
|
+
connection. Delete empty sentences instead of replacing their flagged words with
|
|
88
|
+
milder synonyms. Do not add a takeaway or benefit summary that repeats a nearby
|
|
89
|
+
point. For example, delete “Efficiency is paramount” instead of changing it to
|
|
90
|
+
“Efficiency is crucial.” After a measured improvement in setup time, do not append
|
|
91
|
+
that the change “makes it easier to get started.” Preserve substantive opinions,
|
|
92
|
+
emotion, and useful transitions even when they contain flagged wording. Leave clear
|
|
93
|
+
factual statements and qualifications unchanged where possible. Missing knowledge
|
|
94
|
+
stays missing: “not measured beyond the first month” does not establish that the
|
|
95
|
+
first month was measured, and a missing feature in a new product does not establish
|
|
96
|
+
that the old product had it.
|
|
97
|
+
|
|
98
|
+
Keep local and AI responsibilities distinct:
|
|
84
99
|
|
|
85
100
|
1. **Scorer — local tools.** Point to exact phrases and problems with rhythm,
|
|
86
101
|
readability, formatting, and register; explain the writing score.
|
|
@@ -643,9 +658,13 @@ restart the complete editorial sequence. If the second check still finds a probl
|
|
|
643
658
|
return the safest source-preserving edit and name the remaining issue plainly.
|
|
644
659
|
|
|
645
660
|
If an AI editorial role returns no usable text, record that it was unavailable and
|
|
646
|
-
continue from the last source-preserving text.
|
|
647
|
-
|
|
648
|
-
|
|
661
|
+
continue from the last source-preserving text. For an explicit rewrite request, if that
|
|
662
|
+
text is still the unchanged source, run `python3 scripts/rescue.py -` on the source and
|
|
663
|
+
pass its output through the same scorer and fact gate. This deterministic availability
|
|
664
|
+
editor removes only reviewed stock wrappers and never certifies itself; label its use
|
|
665
|
+
plainly. Unavailability is an abstention, not a reason to retry, switch models, or replay
|
|
666
|
+
earlier roles. A caller with a one-request budget must never make a second remote
|
|
667
|
+
request. Report any role that did not complete.
|
|
649
668
|
|
|
650
669
|
A required repair may raise the writing score from the previous draft as long as it
|
|
651
670
|
stays below the release limit. Source meaning, stated emotion, and factual accuracy
|
|
@@ -967,6 +986,9 @@ the AI model already running in the assistant or rewrite this `SKILL.md`.
|
|
|
967
986
|
requires the section A counts to be written down rather than judged silently.
|
|
968
987
|
- `references/evidence.md` — the research basis: papers, detector mechanics,
|
|
969
988
|
and why each ladder rung is ordered where it is.
|
|
989
|
+
- `scripts/rescue.py` — the conservative, no-network availability editor shared by
|
|
990
|
+
installed skills and the web demo. It returns a changed draft when a known safe edit
|
|
991
|
+
is available, then leaves approval to the scorer and fact gate.
|
|
970
992
|
|
|
971
993
|
## Worked example (LinkedIn)
|
|
972
994
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zero-slop",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.11",
|
|
4
4
|
"description": "An Agent Skill that scores AI-sounding prose locally, guides the host AI through an editorial rewrite, and checks changed source details. The local tools run offline with zero dependencies.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"zero-slop": "bin/zero-slop.mjs"
|
package/references/eval.md
CHANGED
|
@@ -155,7 +155,10 @@ the report even when they are zero.
|
|
|
155
155
|
|
|
156
156
|
## B. Substance
|
|
157
157
|
|
|
158
|
-
31. **Removal test.** Does every paragraph lose something real when deleted?
|
|
158
|
+
31. **Removal test.** Does every paragraph lose something real when deleted? Check
|
|
159
|
+
individual sentences too. Replacing “Efficiency is paramount” with “Efficiency
|
|
160
|
+
is crucial” fails when the whole sentence is empty. Cut sentences that merely
|
|
161
|
+
restate a nearby benefit; preserve substantive opinions and useful transitions.
|
|
159
162
|
32. **Relevance test.** Does every paragraph serve the brief, audience, and argument?
|
|
160
163
|
33. **Front-loading, applied selectively.** Conclusions arrive early where that helps
|
|
161
164
|
the reader, without forcing every section into the same point-then-detail shape.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Conservative, deterministic editing when an AI response is unavailable.
|
|
3
|
+
|
|
4
|
+
This is an availability path, not a substitute for the contextual editor. Every
|
|
5
|
+
rule removes a stock wrapper, contracts a phrase, or repairs paragraph staging.
|
|
6
|
+
Quoted text, code, Markdown links, URLs, names, figures, and claims are left alone.
|
|
7
|
+
|
|
8
|
+
python3 scripts/rescue.py draft.txt
|
|
9
|
+
cat draft.txt | python3 scripts/rescue.py -
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
import re
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
MAX_INPUT_BYTES = 4 * 1024 * 1024
|
|
20
|
+
PROTECTED = re.compile(
|
|
21
|
+
r"```[\s\S]*?```|`[^`\n]+`|\[[^\]\n]+\]\([^)]+\)|https?://[^\s<]+|"
|
|
22
|
+
r"“[^”\n]*”|‘[^’\n]*’|\"[^\"\n]*\""
|
|
23
|
+
)
|
|
24
|
+
TOKEN = re.compile(r"\ue000(\d+)\ue001")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _sentence_pair(match: re.Match[str], *, past: bool) -> str:
|
|
28
|
+
first, second = match.group(1), match.group(2)
|
|
29
|
+
lead = first[:1].upper() + first[1:]
|
|
30
|
+
return f"{lead} {'mattered' if past else 'matters'}. " + (
|
|
31
|
+
f"More important was {second}." if past else f"The larger gain is {second}."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def rescue_text(text: str) -> str:
|
|
36
|
+
"""Return a bounded, source-preserving edit; return clean text unchanged."""
|
|
37
|
+
original = str(text or "").strip()
|
|
38
|
+
protected: list[str] = []
|
|
39
|
+
|
|
40
|
+
def mask(match: re.Match[str]) -> str:
|
|
41
|
+
protected.append(match.group(0))
|
|
42
|
+
return f"\ue000{len(protected) - 1}\ue001"
|
|
43
|
+
|
|
44
|
+
masked = PROTECTED.sub(mask, original)
|
|
45
|
+
out = re.sub(r"[\u00a0\u202f]", " ", masked)
|
|
46
|
+
rules: list[tuple[str, str | object]] = [
|
|
47
|
+
(
|
|
48
|
+
r"\bwe are thrilled to unveil ([^,\n]+),\s+a transformative release that "
|
|
49
|
+
r"redefines what is possible in ([^.]+)\.",
|
|
50
|
+
lambda m: f"{m.group(1)} updates {m.group(2)}.",
|
|
51
|
+
),
|
|
52
|
+
(r"\bthis release represents a significant milestone in our journey to empower "
|
|
53
|
+
r"teams everywhere\.\s*", ""),
|
|
54
|
+
(r"\bwe have listened carefully to your feedback and are excited to deliver a "
|
|
55
|
+
r"suite of powerful new capabilities\.",
|
|
56
|
+
"We listened to your feedback and added new capabilities."),
|
|
57
|
+
(r"\bour cutting[-\u2010\u2011 ]edge\b", "Our"),
|
|
58
|
+
(r"\bhours of tedious manual configuration\b", "hours of manual configuration"),
|
|
59
|
+
(r"\bwe have completely reimagined\b", "We rebuilt"),
|
|
60
|
+
(r"\bwith robust error handling built in from the ground up\b",
|
|
61
|
+
"with built-in error handling"),
|
|
62
|
+
(r"\bwe believe these improvements will fundamentally transform how your team "
|
|
63
|
+
r"works,\s+and the release is available today\.", "The release is available today."),
|
|
64
|
+
(r"\bwe are incredibly excited to share(?: some news)? about\b", "We're excited about"),
|
|
65
|
+
(r"\bwe(?:['’]re| are) excited to share(?: some news)? about\b", "We're excited about"),
|
|
66
|
+
(r"\bwe are incredibly excited to share\b", "We're sharing"),
|
|
67
|
+
(r"\bwe(?:['’]re| are) excited to share\b", "We're excited about"),
|
|
68
|
+
(r"\bi(?:['’]m| am) incredibly excited to (?:share|announce)\b", "I'm sharing"),
|
|
69
|
+
(r"\bour journey\b", "our work"),
|
|
70
|
+
(r"\bour transformative journey\b", "our work"),
|
|
71
|
+
(r"\bin today'?s rapidly evolving (?:landscape|world)\b", "Today"),
|
|
72
|
+
(r"\bit is important to note that\b", ""),
|
|
73
|
+
(r"\bit is worth noting that\b", ""),
|
|
74
|
+
(r"\bwhat we did not realize was just how deeply it impacted everything downstream\.",
|
|
75
|
+
"We underestimated its effect on the work that followed."),
|
|
76
|
+
(r"\bonboarding is not a checklist\.\s*it is a promise\.",
|
|
77
|
+
"We see onboarding as a promise."),
|
|
78
|
+
(r"\bonboarding isn['’]t a checklist\s*[-—]\s*it['’]s a promise\.",
|
|
79
|
+
"We see onboarding as a promise."),
|
|
80
|
+
(r"\bthe insights were game[-\u2011]changing\.",
|
|
81
|
+
lambda m: ("Those" if m.group(0)[0].isupper() else "those")
|
|
82
|
+
+ " conversations changed our approach."),
|
|
83
|
+
(r"\bthe insights were (?:transformative|clear|significant):\s*",
|
|
84
|
+
"Those conversations showed that "),
|
|
85
|
+
(r"\ba platform that leverages intelligent automation to streamline the entire "
|
|
86
|
+
r"process end to end\b", "a platform that automates onboarding from start to finish"),
|
|
87
|
+
(r"\bthe results speak for themselves:\s*([a-z])",
|
|
88
|
+
lambda m: m.group(1).upper()),
|
|
89
|
+
(r"\bthe results speak for themselves\.\s*", ""),
|
|
90
|
+
(r"\bbut here is the thing nobody talks about\.\s*", ""),
|
|
91
|
+
(r"\bthe real win was not ([^.]+)\.\s*it was ([^.]+)\.",
|
|
92
|
+
lambda m: _sentence_pair(m, past=True)),
|
|
93
|
+
(r"\bthe real win isn['’]t just ([^.]+)\.\s*it['’]s ([^.]+)\.",
|
|
94
|
+
lambda m: _sentence_pair(m, past=False)),
|
|
95
|
+
(r"\bthat is the kind of impact that keeps us going\b", "That result keeps us going"),
|
|
96
|
+
(r"\bunlock(?:ing)? the full potential of\b", "use"),
|
|
97
|
+
(r"\bseamlessly integrates?\b", "integrates"),
|
|
98
|
+
(r"\bjust how deeply\b", "how much"),
|
|
99
|
+
(r"\bgame[-\u2011]changing\b", "useful"),
|
|
100
|
+
(r"\bcutting[-\u2010\u2011 ]edge\b", "current"),
|
|
101
|
+
(r"\bredefines what(?:['’]s| is) possible in\b", "updates"),
|
|
102
|
+
(r"\bin order to\b", "to"),
|
|
103
|
+
(r"\bat the end of the day\b", "ultimately"),
|
|
104
|
+
(r"\bwe are\b", "we're"),
|
|
105
|
+
(r"\bwe did not\b", "we didn't"),
|
|
106
|
+
(r"\bwe do not\b", "we don't"),
|
|
107
|
+
(r"\bi am\b", "I'm"),
|
|
108
|
+
(r"\bit is\b", "it's"),
|
|
109
|
+
(r"\bthey are\b", "they're"),
|
|
110
|
+
(r"\byou are\b", "you're"),
|
|
111
|
+
(r"\bthere is\b", "there's"),
|
|
112
|
+
(r"\bdoes not\b", "doesn't"),
|
|
113
|
+
(r"\bis not\b", "isn't"),
|
|
114
|
+
(r"\bare not\b", "aren't"),
|
|
115
|
+
(r"\bcannot\b", "can't"),
|
|
116
|
+
]
|
|
117
|
+
for pattern, replacement in rules:
|
|
118
|
+
out = re.sub(pattern, replacement, out, flags=re.IGNORECASE)
|
|
119
|
+
out = re.sub(r"[ \t]+\n", "\n", out)
|
|
120
|
+
out = re.sub(r" {2,}", " ", out).strip()
|
|
121
|
+
|
|
122
|
+
if out == masked:
|
|
123
|
+
paragraphs = [part.strip() for part in re.split(r"\n{2,}", out) if part.strip()]
|
|
124
|
+
if len(paragraphs) >= 4 and all(len(part.split()) < 24 for part in paragraphs):
|
|
125
|
+
out = " ".join(paragraphs)
|
|
126
|
+
|
|
127
|
+
def restore(match: re.Match[str]) -> str:
|
|
128
|
+
index = int(match.group(1))
|
|
129
|
+
return protected[index] if index < len(protected) else match.group(0)
|
|
130
|
+
|
|
131
|
+
return TOKEN.sub(restore, out).strip()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _read(path: str) -> str:
|
|
135
|
+
if path == "-":
|
|
136
|
+
raw = sys.stdin.buffer.read(MAX_INPUT_BYTES + 1)
|
|
137
|
+
else:
|
|
138
|
+
raw = Path(path).read_bytes()
|
|
139
|
+
if len(raw) > MAX_INPUT_BYTES:
|
|
140
|
+
raise SystemExit(f"input exceeds {MAX_INPUT_BYTES} bytes")
|
|
141
|
+
try:
|
|
142
|
+
return raw.decode("utf-8")
|
|
143
|
+
except UnicodeDecodeError as exc:
|
|
144
|
+
raise SystemExit(f"input is not valid UTF-8: {exc}") from exc
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def main(argv: list[str] | None = None) -> int:
|
|
148
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
149
|
+
parser.add_argument("input", nargs="?", default="-", help="UTF-8 file, or - for stdin")
|
|
150
|
+
args = parser.parse_args(argv)
|
|
151
|
+
sys.stdout.write(rescue_text(_read(args.input)) + "\n")
|
|
152
|
+
return 0
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
raise SystemExit(main())
|
package/scripts/slopscore.py
CHANGED
|
@@ -1156,6 +1156,18 @@ are artificial bookmark despite hey modern please researchers save unpopular wel
|
|
|
1156
1156
|
""".split())
|
|
1157
1157
|
NOT_NAME_WORDS = {word.lower() for word in NOT_NAMES} | COMMON_WORDS
|
|
1158
1158
|
|
|
1159
|
+
# These ordinary subjects are capitalised by sentence position. Exempt only
|
|
1160
|
+
# the generic construction, not the word everywhere: "Efficiency raised $4M"
|
|
1161
|
+
# and "Efficiency Labs" still contain protected names. A quoted construction
|
|
1162
|
+
# remains protected by the independent quotation check.
|
|
1163
|
+
_ABSTRACT_SUBJECT = re.compile(
|
|
1164
|
+
r"(?:^|(?<=[.!?])\s+|\n[ \t]*)"
|
|
1165
|
+
r"(?P<subject>Efficiency|Productivity|Innovation|Quality|Reliability|Success|Customer)"
|
|
1166
|
+
r"(?: (?:(?:experience|service|support|satisfaction)))?"
|
|
1167
|
+
r" is (?:paramount|crucial|essential|important|key|everything)\b",
|
|
1168
|
+
re.M,
|
|
1169
|
+
)
|
|
1170
|
+
|
|
1159
1171
|
|
|
1160
1172
|
def _peel_entity(run, prose, other):
|
|
1161
1173
|
"""The entity inside a title-case run, or None if the run holds no name.
|
|
@@ -1217,6 +1229,7 @@ def facts(text, _other=""):
|
|
|
1217
1229
|
prose = re.sub(r"(?m)^\s*\d+[.)]\s+", "", prose)
|
|
1218
1230
|
other = _spell_to_digits(_other)
|
|
1219
1231
|
other = re.sub(r"(?m)^\s*\d+[.)]\s+", "", other)
|
|
1232
|
+
ordinary_subject_positions = {m.start("subject") for m in _ABSTRACT_SUBJECT.finditer(prose)}
|
|
1220
1233
|
out = {}
|
|
1221
1234
|
for kind, rx in FACT_RX:
|
|
1222
1235
|
found = set()
|
|
@@ -1224,6 +1237,8 @@ def facts(text, _other=""):
|
|
|
1224
1237
|
for m in re.finditer(rx, urls if kind == "url" else prose, flags):
|
|
1225
1238
|
v = (m.group(1) if m.lastindex else m.group(0)).strip()
|
|
1226
1239
|
if kind == "name":
|
|
1240
|
+
if m.start() in ordinary_subject_positions:
|
|
1241
|
+
continue
|
|
1227
1242
|
v = _peel_entity(v, prose, other)
|
|
1228
1243
|
if not v:
|
|
1229
1244
|
continue
|