| id | 2607022119 | |
|---|---|---|
| title | Word-frequency metric and over-repetition rule | |
| status | 🔲 | |
| summary | Add a MET007 word-frequency metric (the highest repeat count of any content word in a file) that ranks files by their most-repeated word, plus an opt-in rule that flags any word repeated past a threshold within a scope. A stopword `lists:` set is subtracted first so common words never trip it. | |
| model | sonnet | |
| depends-on |
|
Rank files by how often their most-repeated content word recurs. Fail when one non-stopword word repeats past a threshold in a scope. This catches accidental over-repetition that no banned-word list anticipates.
The occurrence rule (plan 2607022118) bounds a known token
you name in config. This plan handles the unknown case: the
word you did not think to list but repeated six times in one
section. Vale's
repetition check
only catches immediately adjacent duplicates ("the the"); this
is broader — frequency density across a scope.
mdsmith already ships a metrics subsystem: bytes, lines,
words, headings, token estimate, and conciseness (MET001
through MET006). All rank via mdsmith metrics rank. Word
frequency is the natural MET007: one scalar per file, the
highest repeat count of any content word.
The rule reuses the named word-list mechanism for its stopword
set (lists:, plan 2606251522 / PR #694). A project points at
a shared stopword list. It need not restate "the, a, of, and"
in every rule.
Two artifacts, one shared tokenizer.
MET007 word-frequency (metric). A new file-scope metric
under internal/metrics/. Its value is the highest repeat
count of any single content word in the file. That is one
scalar, so it fits the existing metrics.Value and ranks with
the current CLI.
It folds case, strips inline-code and code blocks, and splits
on Unicode word boundaries. It applies
min-length (default 4 runes), which already drops the
shortest function words. No stopword list ships compiled in,
matching the no-built-in-lists direction.
mdsmith metrics rank --metrics word-frequency then ranks
files by their most-repeated word (the "most repetitive file"
query a release gate wants).
over-repetition (rule, opt-in, off by default). A rule that
runs the same tokenizer per scope and fails when any surviving
word's count in that scope exceeds max (default scope: section). Settings:
scope:file|section|paragraph.max: the per-word ceiling (e.g. 4 per section).min-length: ignore words shorter than N runes (default 4), so short connectors never dominate.stopwords: theWordlistTarget()key. Alists:set unions a shared stopword list into it, subtracted before counting. With no list, onlymin-lengthfilters.mdsmith init --wordlistscan scaffold a starter stopword list.
Both share one unexported tokenizer so the metric and the rule
never disagree on what a "word" is. The rule flags; it does not
rewrite (choosing a synonym is a semantic act, not a mechanical
one). Case folding and stopword subtraction happen once per
scope with reused buffers, keeping Check within the
≤10-alloc budget.
- Add the shared tokenizer (case-fold, strip code, split on
word boundaries, apply
min-length) as an unexported helper reused by both artifacts. Stopword subtraction is the rule's job, from itslists:set; the tokenizer ships no compiled stopword list. - Add MET007 under
internal/metrics/with itsMET007-word-frequency/README and registry wiring; make it rankable throughmdsmith metrics rank. - Add package
internal/rules/overrepetition:Rule,ApplySettings(scope, max, min-length, stopwords), andCheck. Red/green per setting. Off by default. - Implement
WordlistTarget() string { return "stopwords" }and therule.WordlistConsumerassertion solists:feeds the stopword set. - Register the rule (next free ID, e.g. MDS071), add
internal/rules/MDS071-over-repetition/with README andgood//bad/fixtures including alists:-driven stopword case; confirm alloc-budget coverage. - Document both in the metrics and rules references and in
docs/guides/metrics-tradeoffs.md; regenerate catalogs withmdsmith fix.
-
mdsmith metrics rank --metrics word-frequencyranks a corpus by each file's most-repeated content word. - A section repeating one content word five times fails
over-repetition at
max: 4; the same word inside a code block does not count. - A word on the stopword
lists:set is never flagged, proven by a fixture whose list lives in.mdsmith/wordlists/. - The metric and the rule agree on token boundaries because they share one tokenizer (a test asserts it).
- The rule's
Checkstays within the alloc budget. - All tests pass:
go test ./... -
go tool -modfile=tools/go.mod golangci-lint runreports no issues.