From 60cf1ac6259309b030b21551d3cbacad519dc95b Mon Sep 17 00:00:00 2001 From: rivassec Date: Wed, 23 Sep 2026 23:29:10 -0700 Subject: [PATCH] prose_checks: stop flagging "rather than" / "would rather" as weasel words "rather" hedges only as an intensifier ("rather large"). As a bare term it also matched the comparison "rather than" and the preference "would/I'd rather": 16 of 22 weasel-word hits in the 2026-09-20..23 blog-review Ralph runs were those false positives (8 posts: 22 -> 5 hits). The pattern now uses a negative lookahead for "than" and lookbehinds for would/I'd. Intensifier use is still flagged. Adds tests/test_prose_checks_weasel.py (corpus cases). Co-Authored-By: Claude Opus 5.5 (1M context) --- scripts/prose_checks.py | 5 ++- tests/test_prose_checks_weasel.py | 65 +++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/test_prose_checks_weasel.py diff --git a/scripts/prose_checks.py b/scripts/prose_checks.py index 61a73af0..b6c976b4 100755 --- a/scripts/prose_checks.py +++ b/scripts/prose_checks.py @@ -75,7 +75,10 @@ r"somewhat", r"relatively", r"fairly", - r"rather", + # "rather" is a hedge only as an intensifier ("rather large"). "rather than" + # is a comparison and "would/I'd rather" a preference: 16 of 22 weasel hits + # in the 2026-09-20..23 Ralph runs were those two false positives. + r"(? list[str]: + return [m.group(0).lower() for m in prose_checks.WEASEL_RE.finditer(text)] + + +class RatherTests(unittest.TestCase): + def test_rather_than_is_a_comparison_not_a_hedge(self): + for s in [ + "The watermark lives in token selection rather than hidden characters.", + "It provides likelihood rather than the deterministic guarantee.", + "The analogy is operational rather than cryptographic.", + "Rather than dispute that, I closed the ticket.", + "use minimal RBAC bindings rather\nthan relying on the default", + ]: + with self.subTest(s=s): + self.assertEqual(flagged(s), []) + + def test_would_rather_is_a_preference_not_a_hedge(self): + for s in [ + "the kind of artifact I would rather be evaluated on", + "I'd rather ship it today.", + "I’d rather ship it today.", + ]: + with self.subTest(s=s): + self.assertEqual(flagged(s), []) + + def test_rather_as_intensifier_is_still_flagged(self): + for s in ["The blast radius is rather large.", "Rather surprisingly, it worked."]: + with self.subTest(s=s): + self.assertEqual(flagged(s), ["rather"]) + + +class OtherTermsUnchanged(unittest.TestCase): + def test_real_hedges_from_the_corpus_are_still_flagged(self): + self.assertEqual(flagged("In some cases, it's a quiet countdown."), ["in some cases"]) + self.assertEqual(flagged("dispositions tend to fall into three buckets"), ["tend to"]) + self.assertEqual(flagged("which could be weeks or months earlier"), ["could be"]) + + +if __name__ == "__main__": + unittest.main()