Litmus returns twenty signal groups in the same response body as the markdown, and hedge_language is the one most likely to be read as a verdict, because it looks like one. It has a label. The label is low, medium, or high. A label invites a conclusion.
Underneath the label are two integers and a division. Once those are visible, a 26-page sample produces two rows that look like bugs and are not: a page carrying 60 hedge markers scores low, and a page carrying one hedge marker scores medium. Both are correct. Both were measured on 2026-11-01 against the live endpoint, and both are reproducible from the committed payloads.
The field as served
Two real objects, copied out of response bodies:
{"density": "low", "markers_found": 60, "per_500_words": 1.7}
{"density": "medium", "markers_found": 1, "per_500_words": 2}
The first is en.wikipedia.org/wiki/Conspiracy_theory, 17,240 words. The second is cancer.gov/about-cancer/treatment, 247 words. The shorter page has one sixtieth of the markers and a higher band.
The five patterns
hedge_language is a count of phrases. The whole vocabulary, quoted from computeHedgeDensity() in the deployed source:
const HEDGE_MARKERS: RegExp[] = [
new RegExp("\\b(?:may\\s+be|might\\s+be|could\\s+be|appears\\s+to|seems\\s+to|likely|possibly|probably|potentially)\\b", "i"),
new RegExp("\\b(?:suggests?|indicates?|implies?|reportedly|allegedly|purportedly)\\b", "i"),
new RegExp("\\b(?:according\\s+to|sources?\\s+say|it\\s+is\\s+believed|it\\s+is\\s+thought)\\b", "i"),
new RegExp("\\b(?:not\\s+fully\\s+understood|remains\\s+unclear|more\\s+research\\s+is\\s+needed)\\b", "i"),
new RegExp("\\b(?:speculative|unconfirmed|unverified|preliminary|tentative)\\b", "i"),
];
Every occurrence counts, not every pattern that matched. That distinction was a bug until 2026-10-05: the patterns are non-global, so String.match returned at most one match per pattern and markers_found could not exceed 5 on any page. The fix clones each pattern with the g flag. The comment that records it is in the source:
// 2026-10-05 audit: the marker regexes are non-global, so String.match
// returned at most ONE match per pattern and capped markersFound at 5.
// Count every occurrence via a global clone of the pattern.
The denominator
The ratio needs a word count, and the word count is not the one a reader would guess:
const bodyText = markdown.replace(/^#+\s+.+$/gm, "");
const wordCount = bodyText.split(/\s+/).filter(w => w.length > 0).length;
Two consequences. Heading lines are removed completely, so a title like "Alleged fraud in the 2026 election" contributes no words and no markers. And markdown syntax counts as words: on a link list, every ](#cite_note-CSICOP-58) is a token.
That second effect is measurable. On the measured snapshot, the Hacker News front page returned 969 words on the endpoint's denominator, of which 659 were real prose — 32% of its "words" were link targets and footnote syntax. The front page rotates, so its word count moves between runs; the share of link syntax does not. Across the 26 completed pages, stripping link targets, footnote tokens and punctuation runs changed the band on zero of them, so the dilution is real but rarely decisive. Worth knowing before arguing that a link-heavy reference page was scored against a padded denominator.
The thresholds
Two comparisons, quoted from the same function:
if (per500 > 5) return { density: "high", ... };
if (per500 > 2) return { density: "medium", ... };
return { density: "low", ... };
Converted to markers: high needs more than one marker per 100 words. medium needs more than one per 250 words. For a 4,000-word page that is 41 markers for high, 17 for medium. For the 17,240-word conspiracy-theory page, high would need 173 markers. It carried 60.
That is the whole mechanism. No model, no scoring weights, two integers.
What 35 submissions returned
Twenty-six pages completed and nine were refused before any charge: 5 blocked, 3 not_found, 1 content_insufficient. Refusals are named and cost nothing. The completed set, sorted by absolute marker count:
page words marks /500 band
-------------------------------------------- ------ ----- ----- ------
en.wikipedia.org/wiki/Conspiracy_theory 17240 60 1.7 low
en.wikipedia.org/wiki/Speculation 3332 17 2.6 medium
nhs.uk/conditions/asthma/ 1699 8 2.4 medium
nhs.uk/conditions/asthma/symptoms/ 1699 8 2.4 medium
en.wikipedia.org/wiki/Hearsay 2406 7 1.5 low
en.wikipedia.org/wiki/Web_scraping 4095 6 0.7 low
en.wikipedia.org/wiki/Rumour 1938 5 1.3 low
mayoclinic.org/diseases-conditions/asthma/sy 2055 5 1.2 low
who.int/news-room/fact-sheets/detail/asthma 1200 5 2.1 medium
bbc.com/news/world 1054 4 1.9 low
law.cornell.edu/wex/defamation 1687 4 1.2 low
bbc.com/news 1290 3 1.2 low
bbc.com/news/technology 1263 3 1.2 low
en.wikipedia.org/wiki/Allegation 371 2 2.7 medium
kubernetes.io/docs/concepts/overview/ 1469 2 0.7 low
law.cornell.edu/wex/hearsay 527 2 1.9 low
developer.mozilla.org/en-US/docs/Web/API/Fet 459 1 1.1 low
cancer.gov/about-cancer/treatment 247 1 2.0 medium
usa.gov/ 539 1 0.9 low
arxiv.org/abs/2610.29823 645 0 0.0 low
docs.python.org/3/library/json.html 3791 0 0.0 low
en.wikipedia.org/wiki/List_of_common_misconc 395 0 0.0 low
example.com 132 0 0.0 low
news.ycombinator.com 969 0 0.0 low
stripe.com 1339 0 0.0 low
vercel.com 99 0 0.0 low
The words column is the denominator the endpoint divides by — the markdown with heading lines removed, then whitespace-split. It is smaller than the token count in the body, because headings contribute nothing.
Band distribution: 20 low, 6 medium, 0 high. Total markers across the 26 pages: 144.
The counts are not taken on trust. Recomputing all five patterns over each served markdown, with the same heading strip and the same whitespace split, reproduced markers_found, per_500_words and the band on 26 of 26 pages.
The two ends of the sample
The conspiracy-theory article is 17,240 words and carries 60 markers: may be, likely, speculative, unverified, allegedly, spread across a very long document. Its ratio is 1.7, so it reads low even though it holds the largest marker count in the sample — 60 of the sample's 144, with the next page at 17.
The cancer.gov page is 247 words and carries one marker, and the sentence that fired it is a navigation caption:
Find cancer clinical trials—and learn how to locate other research studies—that may be right for you or a loved one.
One marker in 247 words is 2.024 per 500. That prints as 2.0, and it still clears the medium cut, because the comparison uses the unrounded ratio rather than the printed one. The trust score picks it up: the page's trust_factors include "Moderate hedge-language density — some claims are qualified."
The highest ratio in the sample belongs to en.wikipedia.org/wiki/Allegation at 2.7, and both of its markers come from one sentence about pleading procedure:
Such a pleading may be considered disjunctive and may be permissible.
That is a statement about what a court allows, not a statement of doubt. The field counted it as hedging, twice, on a 371-word page.
What the markers fire on
The phrase histogram across all 144 markers:
44 may be
26 likely
12 suggests
12 speculative
8 could be
8 according to
6 suggest
5 allegedly
4 potentially
4 probably
3 unverified
3 purportedly
2 seems to
2 indicate
2 might be
2 not fully understood
1 implies
may be alone is 31% of the count, and the NHS asthma page shows what it is usually doing there: "you may be offered asthma medicines to see if they help your symptoms". That is a care pathway, not uncertainty.
according to is 8 markers, and on the Wikipedia pages all eight are attribution to a named author — "According to Barkun, the appeal of conspiracism is threefold", "According to Rothbard, a "shallow" theorist observes an event and asks". Attribution is the opposite of hedging: it is a page saying where the claim came from. The pattern cannot tell the two apart, and it is not trying to.
So the honest description of the signal is narrower than its name: it counts modal and attribution grammar. Modal grammar overlaps with uncertainty, which is why the signal is useful. It is not the same thing, which is why the label should not be read alone.
The band that did not fire
No page in the sample reached high. Part of that is the sample itself — a docs site, a storefront and a link list have nothing to hedge. Part of it is arithmetic: one marker per 100 words is roughly a qualified clause in every paragraph.
The band matters more than it looks, because structural_trust_score debits it:
if (hedgeDensity === "high") {
score += 2;
trust_factors.push("High hedge-language density — claims are heavily qualified");
} else if (hedgeDensity === "medium") {
score += 1;
trust_factors.push("Moderate hedge-language density — some claims are qualified");
}
Two points separate high from low, the same weight the score gives a user-generated source, and double what it gives a stale page. So the band on a 247-word navigation page and the band on a 17,240-word article are not cosmetic details of a report. They move a number.
Before the 2026-10-05 fix the ceiling made high nearly unreachable: with at most five markers countable, clearing the high cut required a document under 500 words that matched all five patterns. The fix removed the cap. The band is still rare in practice, and the sample above is the evidence: zero of 26.
How to read it
markers_foundis absolute,per_500_wordsis length-normalized. Compare the ratio only between pages of similar length; across lengths, read the absolute count and then read the sentences.lowis not confidence.vercel.comreturned 113 words with zero markers and scoredlow: a thin page, not a careful one.- On a short page one marker sets the band. If
markers_foundis 1, the ratio is a fact about the page length, not about the prose. - Treat
mediumandhighas "go read the sentences", not "the page is unreliable". The cancer.gov and Wikipedia rows above are both examples of the field being right about the words and wrong about the meaning. - Pair it with
citationsandoutbound_authority, which measure where a claim points rather than how it is phrased. A page with strong outbound authority and amediumhedge band is a well-sourced page that qualifies its claims, which is what good writing does.
Reproduce it
Every number here comes from a stored response body. The field is three keys:
jq '.litmus.hedge_language' response.json
# {"density": "medium", "markers_found": 8, "per_500_words": 2.4}
Recompute it from the markdown in the same body, in Python, with no access to the worker:
import re
PATTERNS = [
r"\b(?:may\s+be|might\s+be|could\s+be|appears\s+to|seems\s+to|likely|possibly|probably|potentially)\b",
r"\b(?:suggests?|indicates?|implies?|reportedly|allegedly|purportedly)\b",
r"\b(?:according\s+to|sources?\s+say|it\s+is\s+believed|it\s+is\s+thought)\b",
r"\b(?:not\s+fully\s+understood|remains\s+unclear|more\s+research\s+is\s+needed)\b",
r"\b(?:speculative|unconfirmed|unverified|preliminary|tentative)\b",
]
body = re.sub(r"(?m)^#+\s+.+$", "", markdown)
words = len(body.split())
markers = sum(len(re.findall(p, body, re.I)) for p in PATTERNS)
per500 = markers / words * 500 if words else 0
band = "high" if per500 > 5 else "medium" if per500 > 2 else "low"
print(markers, round(per500, 1), band)
On the 26 pages above this prints the same three values the endpoint returned, every time. That property is the useful part of a deterministic signal: a reader can audit it without a model, a key, or a second opinion.
The field is served by https://nanoparse.app/fetch at $0.005 per successful parse, and to MCP clients at https://nanoparse.app/mcp in the same envelope. If the label matters to a decision, the numbers behind it are in the body — the band is a summary, and the two integers are the claim.
Related: Nothing Fired reads the trust ledger the same way, and What boilerplate_ratio Counts takes the same approach to a different ratio.