Zero Slop v2.8.1
Measure the antithesis detector, then make it work
2.8.0 shipped a detector for this family with no recall measurement. It fired on
four hand-picked anchors and stayed silent on the certified-human corpus, which
is not the same thing. The number nobody had was 37.5%.
bench/antithesis/ is 58 labelled adjacent-sentence pairs — 30 antithesis, 28
ordinary — and the negatives are adversarial for this detector specifically:
negation that is not a figure, anaphora, repeated subjects, shared vocabulary,
parallel technical prose.
| 2.8.0 | now | |
|---|---|---|
| Recall, all shapes | 40.0% | 90.0% |
| Recall, shapes in reach | 44.4% | 100% |
| Precision | 80.0% | 100% |
| Specificity | 89.3% | 100% |
| False positives | 3 | 0 |
Four defects, each found by measurement
Contracted negation was invisible. "Slop isn't a vibe. It's measurable." is a
documented anchor in references/tells.md and nothing matched it. The marked
figure is now matched inside the pair as well as at its ends, gated on a frame —
a repeated opening, two shared words, or a copula on both sides — because a
negation on its own is ordinary prose.
The isocolon rule keyed on the wrong thing. It blocked a repeated opening of
two raw tokens, which killed the documented "Open weights let you adapt a model.
An open stack lets you adapt the machinery that created it." while passing
"Version one shipped in March. Version two shipped in June." The test is now
whether a content word opens both halves: a repeated subject is enumeration, a
repeated article is not.
Matches could overlap. Three short consecutive sentences produced two pairs
out of one figure, and the budget reads the rate those pairs produce.
Markdown scaffolding read as prose. A heading carries no terminal
punctuation, so the splitter returned it glued to the paragraph beneath it.
Fixing prose_of instead was the obvious move and the wrong one — measured,
dropping headings moved five documents over budget on rate alone and stripping
list markers moved eleven, because the budgets are calibrated against what it
currently produces. The family rejects the glued span itself. Across 88 corpus
and documentation files: zero verdict flips in any family, zero count moves
outside this one, identical word counts.
The recall ceiling is real
Two shapes stay out of reach and count against recall rather than being excused.
Bare subject swap is a judgment call in tells.md. The weak isocolon is worse
than hard: "A meter reports a number. A reader reports a feeling." and "The
report lists every vendor. The appendix lists every contract." are identical to
every lexical statistic — 3 and 3 content words, one shared, 0.33 overlap — and
only one is the figure. A detector that caught the first would catch the second.
Reliability, performance, scale
- 14 degenerate inputs — empty, a 60,000-word single sentence, CJK, RTL, emoji,
null bytes, combining marks, mixed line endings. No crash, no catastrophic
backtracking, worst case 0.55s. register.pyhad no timing on record at all and now has its own section in
bench/performance-results.json: 1,204 documents per second, 0.136s on a
15,201-word document, worst pathological input 0.53s against a 15s CI
threshold, linear cost out to 96,000 words.
One finding left open, recorded rather than closed
No corpus in this repository has a single document at or above the register
pass's own MIN_WORDS of 300. Every rate budget it applies is exercised only by
the repository's own documentation. The code already says these budgets are
argued rather than derived; this is what that costs, and closing it needs a
long-form certified-human corpus.
The writing score is unchanged. The register pass never moves it by design.
275 tests, register --selftest, --gate clean on README, charts and records
current.