RUL-017 — No weasel words — blunt engineering vocabulary everywhere
Ruling
Never use weasel words — soft, hedging, or euphemistic vocabulary — in prose, verdict enums, schemas, docs, commit messages, or agent briefs. "A word for psychologists" is not an engineering verdict. Say what a thing IS: PASS/FAIL/BROKEN/FIXED/UNTESTED/UNKNOWN, with numbers.
This covers two distinct failure modes:
- Euphemistic verdicts —
problematic,issue,suboptimalwherefailed,bug,wrongis meant. - Epistemic hedging — a guess wearing the clothes of an answer.
likely,probably,seems to,I assume.
The second is the more expensive one. "The test is likely failing because X" ends inquiry while sounding like a finding; hours of work get built on it before anyone checks. The required alternative is a fact with its evidence attached (path:line, command output, query result) — or the word unknown, plus a statement of what it would take to find out. Saying "unknown" is honest. Hedging is not.
The term list lives in .claude/weasel-words.txt — one term per line, the single source of truth, shared by the ruling and the hook. Add a term there and it is enforced with no code change.
Evidence
- Global memory
feedback-no-weasel-words(user ruling, 2026-07-08): the user's example was a verifier verdict namedproblematic; banned→replacement table includes problematic/issue/suboptimal → failed/bug/wrong, and "feel(s) like"/"seems fine" → a measurement, a count, or a test result. - User instruction, 2026-07-27 (verbatim): "add the word likely to our list of forbidden worss and when it is said by the LLM I want a hook to fire reminding the LLM to do the actual research and not guess." This upgraded the ruling from judgment-only to hook-enforced and added the epistemic-hedging class above.
Enforcement
- hook .claude/hooks/no-guessing-stop.sh
Verification
.claude/hooks/no-guessing-stop.sh is a Stop hook: it reads the model's last turn (thinking text + output text) from the transcript, matches it word-boundary-wise and case-insensitively against .claude/weasel-words.txt, and returns {"decision":"block"} with an instruction to go resolve the question with tools — read the file, run it and read the traceback, query the graph, git show the commit — and restate the claim as a fact with evidence, or as unknown.
The earlier objection to a string-match gate (that it "would false-positive constantly on legitimate technical usage") is answered structurally rather than dismissed:
- The list is scoped to epistemic hedging, not to ambiguous technical nouns.
issueis deliberately NOT in it —GitHub issueis legitimate. - Fenced code blocks,
~~~blocks, inline code spans, and>blockquote lines are stripped before matching, because tool output legitimately contains these words.scripts/diagnose_test_failure.pyprintsLikely cause:verbatim; quoting that is presenting evidence, not hedging. - The block text tells the model that if a flagged phrase was inside evidence it was quoting, it should say so and proceed — so a genuine false positive costs one sentence, never a loop.
stop_hook_activeloop protection means it fires at most once per turn.
Verified 2026-07-27 against six cases: plain hedge in output → BLOCK; the same word only inside a fenced block → silent; evidence-bearing prose → silent; hedge in the thinking block only → BLOCK ("i assume", "probably"); multi-word terms → BLOCK ("seems to", "should be fine"); stop_hook_active=true → silent.
Registered in .claude/settings.json under hooks.Stop, alongside forbidden-doubles-stop.sh.