snifftest 0.1.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.
- package/LICENSE +21 -0
- package/README.md +372 -0
- package/SECURITY.md +165 -0
- package/bench/panel-direct.yaml +97 -0
- package/bench/panel.yaml +136 -0
- package/bench/prices/anthropic-2026-09-17.yaml +33 -0
- package/bench/prices/openai-2026-09-17.yaml +27 -0
- package/dist/snifftest.js +12217 -0
- package/examples/CORPUS.md +54 -0
- package/examples/corpus/cold-email.md +5 -0
- package/examples/corpus/editing-by-ear.md +5 -0
- package/examples/corpus/field-notes-app.md +5 -0
- package/examples/corpus/franklin-the-printer.md +3 -0
- package/examples/corpus/franklin-the-socratic-method.md +3 -0
- package/examples/corpus/franklin-the-spectator.md +1 -0
- package/examples/corpus/on-checklists.md +5 -0
- package/examples/corpus/release-note.md +5 -0
- package/examples/corpus/station-routes.md +5 -0
- package/examples/corpus/strunk-introduction.md +1 -0
- package/examples/replays/bench-2026-09-17.json +104 -0
- package/examples/replays/drafts/clean.md +1 -0
- package/examples/replays/drafts/faulty.md +1 -0
- package/examples/replays/example.json +79 -0
- package/examples/seeds/bank.json +196 -0
- package/package.json +46 -0
- package/rules/default.yaml +458 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# Sniff Test, the default ruleset.
|
|
2
|
+
#
|
|
3
|
+
# Fifteen rules, ten of which apply to most prose and five of which are
|
|
4
|
+
# conventions of copy meant to sell or persuade. Five rules are countable and
|
|
5
|
+
# run as regular expressions on your machine, with nothing sent anywhere. Ten
|
|
6
|
+
# are judgment calls and are answered by the judgment model, one probability
|
|
7
|
+
# per rule per paragraph. A flag names its rule and its probability.
|
|
8
|
+
#
|
|
9
|
+
# The rules tagged `marketing` encode a convention of marketing copy, and they
|
|
10
|
+
# sit out an ordinary run because `off_by_default` names that tag below. Ask
|
|
11
|
+
# for them on a landing page with `--only marketing`, or run everything else
|
|
12
|
+
# and add them with a project file that extends this one and writes
|
|
13
|
+
# `off_by_default: []`. Every rule here is one view of good writing. Disagree
|
|
14
|
+
# with any of them by editing your own copy of the file; that is the feature.
|
|
15
|
+
#
|
|
16
|
+
# A countable rule may name the kinds of block it applies to with `chunks`.
|
|
17
|
+
# The kinds are front_matter, heading, table, link_definition, html_comment,
|
|
18
|
+
# list, block_quote and prose. A rule that names none applies to prose, block
|
|
19
|
+
# quotes, lists and headings, which is everything a person would call writing.
|
|
20
|
+
# The judgment rules are asked about prose, block quotes and lists long enough
|
|
21
|
+
# to hold a sentence, and never about the rest: a heading is not a paragraph,
|
|
22
|
+
# and a request about one costs what a request about a paragraph costs.
|
|
23
|
+
#
|
|
24
|
+
# A `.snifftest.yaml` in your project extends or replaces this file. Copy a
|
|
25
|
+
# rule, change its words, keep its id unique. The `seed` on each rule is how
|
|
26
|
+
# `snifftest eval` manufactures one defect of that kind inside your own clean
|
|
27
|
+
# text, so that recall and false alarms can be measured on your prose rather
|
|
28
|
+
# than ours. A transform seed is mechanical; a splice seed inserts one of the
|
|
29
|
+
# listed sentences, at the start, at the end, or anywhere, per `position`.
|
|
30
|
+
#
|
|
31
|
+
# Each judgment rule carries four parts. `what` describes the defect.
|
|
32
|
+
# `not_for` lists the near misses that must not be flagged. `examples` are
|
|
33
|
+
# sentences that do trip the rule. `criteria` are the two statements the
|
|
34
|
+
# model decides between. The contrast is what makes the judgment reliable;
|
|
35
|
+
# a rule with a `what` and no `not_for` will flag things you did not mean.
|
|
36
|
+
|
|
37
|
+
version: 1
|
|
38
|
+
threshold: 0.7
|
|
39
|
+
|
|
40
|
+
# Tags whose rules sit out a run unless they are asked for by name.
|
|
41
|
+
off_by_default: [marketing]
|
|
42
|
+
|
|
43
|
+
rules:
|
|
44
|
+
# --- countable rules: regular expressions, no network -------------------
|
|
45
|
+
|
|
46
|
+
- id: dash_present
|
|
47
|
+
kind: regex
|
|
48
|
+
# The built-in matches two characters: an en dash (U+2013) and an em dash
|
|
49
|
+
# (U+2014). A plain hyphen in a compound word does not count, and neither
|
|
50
|
+
# does an en dash between numerals, because "pages 10-20" written with the
|
|
51
|
+
# typographer's dash is a range and this rule is about a writer reaching
|
|
52
|
+
# for a dash instead of a full stop.
|
|
53
|
+
#
|
|
54
|
+
# A block quote is somebody else's text, so its dashes are theirs and the
|
|
55
|
+
# rule stays out of it. A quotation running inline inside a sentence cannot
|
|
56
|
+
# be told from the writer's own words without parsing quotation marks that
|
|
57
|
+
# mean five other things as well, so an inline quotation is still flagged.
|
|
58
|
+
builtin: dash_present
|
|
59
|
+
chunks: [prose, list, heading]
|
|
60
|
+
message: "A long dash. Give the sentence a full stop instead."
|
|
61
|
+
seed: { transform: insert_em_dash, count: 1 }
|
|
62
|
+
|
|
63
|
+
- id: colon_heavy
|
|
64
|
+
kind: regex
|
|
65
|
+
# The built-in counts the colon character (U+003A) in the paragraph and
|
|
66
|
+
# trips at `min` or more. A semicolon is not a colon. The colon in a URL,
|
|
67
|
+
# the one in a clock time and the ones inside an HTML comment are not
|
|
68
|
+
# punctuation a reader sees, so they are not counted.
|
|
69
|
+
#
|
|
70
|
+
# A list is not one paragraph: four bullets with a colon apiece are four
|
|
71
|
+
# sentences, and counting them together told a design note to pick one
|
|
72
|
+
# colon out of four.
|
|
73
|
+
builtin: colon_count
|
|
74
|
+
min: 3
|
|
75
|
+
chunks: [prose, block_quote]
|
|
76
|
+
message: "Three colons in one paragraph. Pick one."
|
|
77
|
+
seed: { transform: add_colons, count: 3 }
|
|
78
|
+
|
|
79
|
+
- id: sentence_rhythm
|
|
80
|
+
kind: regex
|
|
81
|
+
# The built-in splits on (?<=[.!?])\s+, counts words per sentence, and
|
|
82
|
+
# trips when the coefficient of variation (standard deviation over mean)
|
|
83
|
+
# is below `floor`. Paragraphs with fewer than `min_sentences` sentences
|
|
84
|
+
# or fewer than `min_words` words are skipped: four six-word sentences are
|
|
85
|
+
# a status note, and telling its author that every sentence runs to the
|
|
86
|
+
# same length is telling them their note is a note.
|
|
87
|
+
builtin: sentence_rhythm
|
|
88
|
+
floor: 0.25
|
|
89
|
+
min_sentences: 4
|
|
90
|
+
min_words: 60
|
|
91
|
+
chunks: [prose, block_quote]
|
|
92
|
+
message: "Every sentence runs to the same length. The reader nods off by the third."
|
|
93
|
+
seed: { transform: equalize_sentences }
|
|
94
|
+
|
|
95
|
+
- id: slop_vocab
|
|
96
|
+
kind: regex
|
|
97
|
+
# The built-in matches any listed word and its ordinary inflections: the
|
|
98
|
+
# stem as written plus s, es, ed, ing, ly, ment(s) and ion(s), with a final
|
|
99
|
+
# silent e dropped where English drops it, so "delve" catches "delves" and
|
|
100
|
+
# "delving", and "seamless" catches "seamlessly". Matching is
|
|
101
|
+
# case-insensitive and stops at a word boundary, so "landscape" does not
|
|
102
|
+
# catch "landscaped lawn" through some longer word. A derivation further
|
|
103
|
+
# from the stem than those suffixes, such as "intricacies", is a separate
|
|
104
|
+
# word: add it to the list if you want it.
|
|
105
|
+
#
|
|
106
|
+
# `except` lists phrases in which a listed word is doing its literal job.
|
|
107
|
+
# These are matched case-insensitively and take the word out of the count.
|
|
108
|
+
# Edit both lists freely; a word on this list is a tell in some registers
|
|
109
|
+
# and the plain choice in others.
|
|
110
|
+
builtin: slop_vocab
|
|
111
|
+
words:
|
|
112
|
+
- delve
|
|
113
|
+
- tapestry
|
|
114
|
+
- landscape
|
|
115
|
+
- unlock
|
|
116
|
+
- testament
|
|
117
|
+
- navigate
|
|
118
|
+
- realm
|
|
119
|
+
- myriad
|
|
120
|
+
- intricate
|
|
121
|
+
- pivotal
|
|
122
|
+
- seamless
|
|
123
|
+
- showcase
|
|
124
|
+
except:
|
|
125
|
+
- landscape architect
|
|
126
|
+
- landscape architecture
|
|
127
|
+
- landscape gardener
|
|
128
|
+
- landscape orientation
|
|
129
|
+
- landscape mode
|
|
130
|
+
- navigate to
|
|
131
|
+
- navigate by
|
|
132
|
+
- navigate the menu
|
|
133
|
+
- navigation bar
|
|
134
|
+
- navigation pane
|
|
135
|
+
- unlock the door
|
|
136
|
+
- unlock the screen
|
|
137
|
+
- unlock your phone
|
|
138
|
+
message: "A word that turns up far more often in generated text than in prose a person wrote. Try the plain one."
|
|
139
|
+
seed: { transform: insert_slop_word, count: 1 }
|
|
140
|
+
|
|
141
|
+
- id: banned_words
|
|
142
|
+
kind: regex
|
|
143
|
+
# Same matcher as slop_vocab, over your own list. Empty by default, so it
|
|
144
|
+
# flags nothing until you add a word. Put the words your house never uses.
|
|
145
|
+
builtin: banned_words
|
|
146
|
+
words: []
|
|
147
|
+
message: "A word from your own banned list."
|
|
148
|
+
seed: { transform: insert_banned_word, count: 1 }
|
|
149
|
+
|
|
150
|
+
# --- judgment rules: answered by the model, one probability each ---------
|
|
151
|
+
|
|
152
|
+
- id: not_x_but_y
|
|
153
|
+
kind: judgment
|
|
154
|
+
what: |
|
|
155
|
+
A sentence, or a pair of sentences, whose whole job is to swap one
|
|
156
|
+
label for another. The writer denies one description of a thing and
|
|
157
|
+
puts a replacement in its place, and the swap is the point. The shape
|
|
158
|
+
is "it is not X, it is Y", or "this was never X. It was Y.", or "not a
|
|
159
|
+
X but a Y", or the same swap in reverse, "it is Y, not X". Both halves
|
|
160
|
+
describe the same subject, and the sentence carries nothing else.
|
|
161
|
+
not_for: |
|
|
162
|
+
A plain negation with no replacement offered ("This is not a
|
|
163
|
+
guarantee.").
|
|
164
|
+
A denial followed by a separate fact rather than a relabelling ("It is
|
|
165
|
+
not finished, and two tests still fail.").
|
|
166
|
+
A comparison with "rather than" or "instead of" inside a sentence that
|
|
167
|
+
carries other information ("We ship on Tuesdays rather than Fridays so
|
|
168
|
+
the weekend stays quiet.").
|
|
169
|
+
A factual correction of a claim someone else made, with the evidence
|
|
170
|
+
for it.
|
|
171
|
+
Two sentences that each carry their own information, where the second
|
|
172
|
+
does not exist only to replace the first.
|
|
173
|
+
examples:
|
|
174
|
+
- "It is not a shortcut, it is the whole method."
|
|
175
|
+
- "The problem was never the tooling. It was the calendar."
|
|
176
|
+
- "That is a habit, not a strategy."
|
|
177
|
+
criteria:
|
|
178
|
+
true: "At least one sentence, or sentence pair, denies one description of a thing and substitutes another for effect, in either order, with the swap as its point."
|
|
179
|
+
false: "Every negation either stands alone, is followed by new information rather than a relabelling, or corrects a claim with evidence."
|
|
180
|
+
message: "Not X, it's Y. The reframe is doing the arguing for you."
|
|
181
|
+
seed:
|
|
182
|
+
splice:
|
|
183
|
+
- "Calling Tuesday an outage would be generous. Somebody chose to turn it off."
|
|
184
|
+
- "Whatever the Friday meeting has become, a review is no longer the word for it. A rehearsal is."
|
|
185
|
+
- "Nobody has a scheduling problem here. What everyone has is a saying-no problem."
|
|
186
|
+
position: any
|
|
187
|
+
|
|
188
|
+
- id: tricolon
|
|
189
|
+
kind: judgment
|
|
190
|
+
what: |
|
|
191
|
+
Judge sentence by sentence. One sentence is enough to trip this rule,
|
|
192
|
+
wherever it sits in the paragraph and however informative the rest of
|
|
193
|
+
the paragraph is.
|
|
194
|
+
A decorative rule of three. Three short parallel words or phrases in a
|
|
195
|
+
row whose job is the beat rather than the information, such as three
|
|
196
|
+
adjectives, three verbs, or a three-word fragment used as a flourish.
|
|
197
|
+
not_for: |
|
|
198
|
+
A list of three distinct things the reader needs, such as three named
|
|
199
|
+
steps, three options, or three findings, each adding something the
|
|
200
|
+
others do not.
|
|
201
|
+
A list of two, or of four or more.
|
|
202
|
+
Three items quoted from somewhere else and discussed.
|
|
203
|
+
examples:
|
|
204
|
+
- "The fix is cleaner, faster, and truer."
|
|
205
|
+
- "Plan, build, repeat."
|
|
206
|
+
- "It was slow, it was loud, it was late."
|
|
207
|
+
criteria:
|
|
208
|
+
true: "At least one sentence, anywhere in the paragraph, carries a three-item run whose purpose is rhythm rather than information. One such sentence is enough, and the informative lists around it do not excuse it."
|
|
209
|
+
false: "Every three-item run in the paragraph is an informative list, or there are none."
|
|
210
|
+
message: "Three items for the cadence. Keep the one that carries the weight."
|
|
211
|
+
seed:
|
|
212
|
+
splice:
|
|
213
|
+
- "The result was quieter, lighter, and kinder."
|
|
214
|
+
- "Read, mark, move on."
|
|
215
|
+
- "Small budget, small room, small hopes."
|
|
216
|
+
position: any
|
|
217
|
+
|
|
218
|
+
- id: stacked_hedging
|
|
219
|
+
kind: judgment
|
|
220
|
+
what: |
|
|
221
|
+
One claim carrying two or more softeners at once, so that the sentence
|
|
222
|
+
never commits. "Might perhaps", "arguably, in some sense, probably",
|
|
223
|
+
"it seems to me that it could possibly".
|
|
224
|
+
not_for: |
|
|
225
|
+
A single hedge used once and on purpose, such as one "I think" or one
|
|
226
|
+
"roughly".
|
|
227
|
+
Honest uncertainty stated plainly ("The cause is unknown.").
|
|
228
|
+
A precise qualifier on a number ("about 40 percent", "at least three").
|
|
229
|
+
A passage that quotes or discusses hedging as its subject.
|
|
230
|
+
examples:
|
|
231
|
+
- "It might perhaps, in some sense, arguably be the main reason."
|
|
232
|
+
- "It seems to me that this could possibly tend to help a little."
|
|
233
|
+
criteria:
|
|
234
|
+
true: "At least one claim carries two or more piled-up softeners in the same sentence."
|
|
235
|
+
false: "Hedges are absent, or each claim carries at most one, used deliberately."
|
|
236
|
+
message: "Three hedges on one claim. Either say it or leave it out."
|
|
237
|
+
seed:
|
|
238
|
+
splice:
|
|
239
|
+
- "That could perhaps, in a way, maybe explain part of the gap."
|
|
240
|
+
- "I would think it might arguably, more or less, be worth a try."
|
|
241
|
+
position: any
|
|
242
|
+
|
|
243
|
+
- id: rhetorical_opener
|
|
244
|
+
kind: judgment
|
|
245
|
+
what: |
|
|
246
|
+
The paragraph's first sentence is a question asked for effect, to set
|
|
247
|
+
up what the writer is about to say, rather than to get an answer from
|
|
248
|
+
anyone.
|
|
249
|
+
not_for: |
|
|
250
|
+
A question that appears later in the paragraph.
|
|
251
|
+
A first sentence that is a statement, even a curious-sounding one.
|
|
252
|
+
An opening question addressed to a named person, or one the paragraph
|
|
253
|
+
reports someone else asking.
|
|
254
|
+
examples:
|
|
255
|
+
- "What if the checker itself is the thing that is wrong?"
|
|
256
|
+
- "But what happens when nobody reads the draft twice?"
|
|
257
|
+
criteria:
|
|
258
|
+
true: "The first sentence is a question asked for rhetorical effect."
|
|
259
|
+
false: "The first sentence is a statement, or the only questions come later, or the opening question is one someone actually asked."
|
|
260
|
+
# About the paragraph's opening, so it is not asked of the later pieces of a
|
|
261
|
+
# paragraph that was too long to send in one request.
|
|
262
|
+
sentence: first
|
|
263
|
+
message: "Opens on a question nobody asked. Start with the answer."
|
|
264
|
+
seed:
|
|
265
|
+
splice:
|
|
266
|
+
- "Who decided that a draft has to be finished before anyone reads it?"
|
|
267
|
+
- "And what is a rule worth if nobody remembers it on a Friday?"
|
|
268
|
+
position: start
|
|
269
|
+
|
|
270
|
+
- id: restating_closer
|
|
271
|
+
kind: judgment
|
|
272
|
+
what: |
|
|
273
|
+
The paragraph's final sentence only says again what the paragraph has
|
|
274
|
+
already said. It often opens with "in short", "in other words", "to sum
|
|
275
|
+
up", or "put simply", or refers back to "everything above".
|
|
276
|
+
not_for: |
|
|
277
|
+
A closing sentence that lands something new: a consequence, a named
|
|
278
|
+
mechanism, a number, a source, a condition, or a turn the paragraph had
|
|
279
|
+
not yet made, even when it is short or emphatic.
|
|
280
|
+
A paragraph of a single sentence.
|
|
281
|
+
examples:
|
|
282
|
+
- "In short, everything above is what we said."
|
|
283
|
+
- "To sum up, that is how the process works, as this paragraph has described."
|
|
284
|
+
criteria:
|
|
285
|
+
true: "The last sentence is a summary of the paragraph and adds nothing."
|
|
286
|
+
false: "The last sentence advances the argument or adds information, or the paragraph is a single sentence."
|
|
287
|
+
# About the paragraph's ending, so it is not asked of the earlier pieces of
|
|
288
|
+
# a paragraph that was too long to send in one request.
|
|
289
|
+
sentence: last
|
|
290
|
+
message: "The last sentence says the paragraph again. End one sentence earlier."
|
|
291
|
+
seed:
|
|
292
|
+
splice:
|
|
293
|
+
- "In other words, this paragraph has just made the point it set out to make."
|
|
294
|
+
- "Put simply, that is the whole of what was said above."
|
|
295
|
+
position: end
|
|
296
|
+
|
|
297
|
+
- id: self_undercutting
|
|
298
|
+
kind: judgment
|
|
299
|
+
tags: [marketing]
|
|
300
|
+
# A page meant to sell has to make its offer. A page meant to document
|
|
301
|
+
# has to state its limits, which is why this rule sits out by default.
|
|
302
|
+
what: |
|
|
303
|
+
Judge sentence by sentence. One sentence is enough to trip this rule,
|
|
304
|
+
however confident and specific the rest of the paragraph is.
|
|
305
|
+
A line that talks the reader out of the thing being offered. It says
|
|
306
|
+
the thing may not work, that the writer does not claim it works, that
|
|
307
|
+
there is no guarantee, or that it may not be for them. On a page meant
|
|
308
|
+
to sell, describe, or recommend, this weakens the offer and tells the
|
|
309
|
+
reader nothing they can use.
|
|
310
|
+
not_for: |
|
|
311
|
+
A precise statement of scope or a known limit ("It checks Markdown and
|
|
312
|
+
plain text, not PDFs.").
|
|
313
|
+
A measured result with its range ("Recall was 0.85 to 0.94 across three
|
|
314
|
+
runs.").
|
|
315
|
+
A specific past failure that the paragraph then explains.
|
|
316
|
+
An honest statement of what a piece of work does and does not cover
|
|
317
|
+
("We do not claim this catches every case."), which is a scope note and
|
|
318
|
+
belongs in good documentation.
|
|
319
|
+
Disputing a claim someone else made.
|
|
320
|
+
examples:
|
|
321
|
+
- "This may not work for you, and we are not saying it will."
|
|
322
|
+
- "There is no guarantee any of this helps."
|
|
323
|
+
criteria:
|
|
324
|
+
true: "At least one sentence, anywhere in the paragraph, tells the reader not to count on the thing working, with no specific limit named. One such sentence is enough."
|
|
325
|
+
false: "Limits are named precisely, or no self-undercutting line appears."
|
|
326
|
+
message: "The copy is talking the reader out of it. Name the limit and drop the shrug."
|
|
327
|
+
seed:
|
|
328
|
+
splice:
|
|
329
|
+
- "It might do nothing at all for your team, and that is fine."
|
|
330
|
+
- "Plenty of people try this once and shrug, so keep your expectations low."
|
|
331
|
+
- "Results vary and we make no promises about yours."
|
|
332
|
+
position: any
|
|
333
|
+
|
|
334
|
+
- id: first_x_that
|
|
335
|
+
kind: judgment
|
|
336
|
+
tags: [marketing]
|
|
337
|
+
# A first claim is a marketing habit; a technical note may need the word
|
|
338
|
+
# for a sequence, which `not_for` covers.
|
|
339
|
+
what: |
|
|
340
|
+
Judge sentence by sentence. One sentence is enough to trip this rule,
|
|
341
|
+
wherever it sits in the paragraph.
|
|
342
|
+
A claim that the writer, or their team, product, or company, is the
|
|
343
|
+
first to do something. "The first tool that", "the first team to", "we
|
|
344
|
+
were the first to".
|
|
345
|
+
not_for: |
|
|
346
|
+
A first-ever claim about someone else, with a source.
|
|
347
|
+
"First" as a position in a sequence, such as the first step, the first
|
|
348
|
+
draft, or the first of two things.
|
|
349
|
+
A claim of being different, deeper, or better that does not use
|
|
350
|
+
"first".
|
|
351
|
+
A dated historical fact with a source ("The first edition appeared in
|
|
352
|
+
1918.").
|
|
353
|
+
examples:
|
|
354
|
+
- "This is the first tool that reads a draft the way an editor does."
|
|
355
|
+
- "We are the first team to run this check on every save."
|
|
356
|
+
criteria:
|
|
357
|
+
true: "At least one sentence, anywhere in the paragraph, claims the writer, or their product, team, or company, was first to do something. One such sentence is enough."
|
|
358
|
+
false: "No first claim is made about the writer or their own work."
|
|
359
|
+
message: '"The first X that." Someone will check.'
|
|
360
|
+
seed:
|
|
361
|
+
splice:
|
|
362
|
+
- "Nobody had put a probability beside every flag until our team did."
|
|
363
|
+
- "Ours is the earliest field notebook a crew could carry down a mine with no signal."
|
|
364
|
+
position: any
|
|
365
|
+
|
|
366
|
+
- id: naked_cost_figure
|
|
367
|
+
kind: judgment
|
|
368
|
+
tags: [marketing]
|
|
369
|
+
# This is a house rule about marketing surfaces, not about writing.
|
|
370
|
+
what: |
|
|
371
|
+
The paragraph states what something cost to make or run, in model
|
|
372
|
+
spend, compute, hours, or "it cost us", without naming the price a
|
|
373
|
+
customer pays and the alternative beside it.
|
|
374
|
+
not_for: |
|
|
375
|
+
A cost quoted together with the customer price and a comparison ("It
|
|
376
|
+
costs us about a dollar to run, you pay $49, and an agency charges
|
|
377
|
+
$2,000.").
|
|
378
|
+
A cost in a technical appendix or a bench table that names what it
|
|
379
|
+
measures.
|
|
380
|
+
A customer price quoted as a price.
|
|
381
|
+
A revenue figure, a valuation, or a figure about someone else's
|
|
382
|
+
business.
|
|
383
|
+
examples:
|
|
384
|
+
- "This report cost us $1.30 in API calls."
|
|
385
|
+
- "Each run costs us about nine cents in model spend."
|
|
386
|
+
criteria:
|
|
387
|
+
true: "A production or running cost appears with no customer price and no alternative next to it."
|
|
388
|
+
false: "Every cost figure is accompanied by the price and an alternative, or no cost figure appears."
|
|
389
|
+
message: "A cost with no price next to it. Sniffs like a discount nobody asked for."
|
|
390
|
+
seed:
|
|
391
|
+
splice:
|
|
392
|
+
- "It cost us about four dollars of compute to make this."
|
|
393
|
+
- "Rendering the page costs us a little under two cents each time."
|
|
394
|
+
position: any
|
|
395
|
+
|
|
396
|
+
- id: jobs_claim
|
|
397
|
+
kind: judgment
|
|
398
|
+
tags: [marketing]
|
|
399
|
+
# A positioning rule for pages that sell. A report about employment
|
|
400
|
+
# says what it measures and is not covered by this.
|
|
401
|
+
what: |
|
|
402
|
+
Judge sentence by sentence. One sentence is enough to trip this rule,
|
|
403
|
+
wherever it sits in the paragraph and however carefully the rest of the
|
|
404
|
+
paragraph describes the division of work.
|
|
405
|
+
A claim about employment. That the thing creates jobs, that it
|
|
406
|
+
replaces the people who used to do the work, or that it would never
|
|
407
|
+
replace a person.
|
|
408
|
+
not_for: |
|
|
409
|
+
Describing what the tool does and what a person still decides, with no
|
|
410
|
+
claim about employment.
|
|
411
|
+
Naming who reviews or signs off.
|
|
412
|
+
Replacing a thing rather than a person ("It replaces the spreadsheet.").
|
|
413
|
+
A sourced statistic about employment, in a report whose subject is
|
|
414
|
+
employment.
|
|
415
|
+
examples:
|
|
416
|
+
- "We would never replace a person."
|
|
417
|
+
- "This replaces the people who used to do the checking by hand."
|
|
418
|
+
- "Four seats means we create jobs rather than removing them."
|
|
419
|
+
criteria:
|
|
420
|
+
true: "At least one sentence, anywhere in the paragraph, makes an employment claim of one of those kinds. One such sentence is enough, whatever the surrounding sentences say about what people still do."
|
|
421
|
+
false: "No sentence makes an employment claim; the paragraph describes the division of work and stops there."
|
|
422
|
+
message: "A claim about jobs. Say what the tool does and what people keep, then stop."
|
|
423
|
+
seed:
|
|
424
|
+
splice:
|
|
425
|
+
- "Nobody loses their job to this, and if anything it adds a few."
|
|
426
|
+
- "The tool now does the work that three people used to do."
|
|
427
|
+
- "We have promised the team that no role will ever be automated away."
|
|
428
|
+
position: any
|
|
429
|
+
|
|
430
|
+
- id: pullquote_fragment
|
|
431
|
+
kind: judgment
|
|
432
|
+
tags: [marketing]
|
|
433
|
+
# A typographic convention of published copy, not of ordinary prose.
|
|
434
|
+
what: |
|
|
435
|
+
Judge line by line. One display line is enough to trip this rule,
|
|
436
|
+
wherever it sits in the paragraph and however complete the other lines
|
|
437
|
+
around it are.
|
|
438
|
+
A pull quote, meaning a short line set apart in quotation marks or
|
|
439
|
+
italics as a display line, whose text is a fragment with no subject and
|
|
440
|
+
verb of its own.
|
|
441
|
+
not_for: |
|
|
442
|
+
A quotation from a named source running inline as part of a sentence,
|
|
443
|
+
however short.
|
|
444
|
+
A complete sentence used as a pull quote.
|
|
445
|
+
A heading or a title.
|
|
446
|
+
A paragraph with no pull quote at all.
|
|
447
|
+
examples:
|
|
448
|
+
- "*\"Built to be argued with.\"*"
|
|
449
|
+
- "*\"The part nobody reads twice.\"*"
|
|
450
|
+
criteria:
|
|
451
|
+
true: "At least one display line, anywhere in the paragraph, is set apart as a pull quote and is a fragment rather than a complete sentence. One such line is enough, and the complete ones beside it do not excuse it."
|
|
452
|
+
false: "There is no pull quote, or every pull quote in the paragraph is a complete sentence."
|
|
453
|
+
message: "A pull quote with no verb. Quote a whole sentence."
|
|
454
|
+
seed:
|
|
455
|
+
splice:
|
|
456
|
+
- "*\"Cheaper by the paragraph.\"*"
|
|
457
|
+
- "*\"A pen on a string.\"*"
|
|
458
|
+
position: any
|