Skip to content

A list of data is not a tricolon - #101

Merged
peopleworks merged 1 commit into
mainfrom
rule-of-three-skips-data-lists
Sep 16, 2026
Merged

peopleworks merged 1 commit into
mainfrom
rule-of-three-skips-data-lists

Conversation

@peopleworks

Copy link
Copy Markdown
Owner

Closes #100.

rhet.rule-of-three matched any three word-characters, so it could not tell a rhetorical tricolon — "fast, simple, and powerful" — from an author listing three values. #100 found it on "2324, 2425 and 2526" in a support-ticket reply, and measured it: 18 of the rule's 236 corpus matches are lists like that (gene names, doses, year codes), and six texts had no other hit. Reproduced exactly before changing anything.

The narrowing

In the pack, not in C#, so the rule stays editable by anyone. A list is skipped when none of its three items contains a lowercase letter:

\b(?!(?-i:[\p{Lu}\d]+), (?-i:[\p{Lu}\d]+),? and (?-i:[\p{Lu}\d]+)[.,;])(\w+), (\w+),? and (\w+)[.,;]

Two traps shaped it, and both are pinned by tests:

  • PatternAnalyzer compiles every pack pattern with IgnoreCase, so an uppercase class would match prose too and silently switch the rule off. The token class is wrapped in (?-i:…). If that ever stops working, "fast, simple, and powerful" stops firing and the test says so.
  • \p{Lu}, not [A-Z] — an ASCII class misses ÁREA, ÉPOCA y ÍNDICE. Same lesson as the Turkish dotless ı in The character scanner reads Turkish dotless i as an artifact #62.

Mixed lists still fire (CD31, CD45, and cells): requiring all three to be data is the conservative reading #100 argued for.

The Spanish twin rhet.regla-de-tres gets the same narrowing. The Spanish corpus cannot judge it — 14 matches, none of them data — but the reasoning is language-independent, and leaving the packs asymmetric is how a sibling goes stale.

Published numbers: unchanged in every field

The calibration run was compared field by field before and after the regex change. A baseline run first confirmed the tool reproduces the committed file exactly except engine and measuredOn; the run with the new regex differs from that baseline in zero fields. So published-calibration.json is not regenerated here, and no committee is needed.

humanRatePer1000 stays at 1.09 on purpose. It was measured on a superset of these matches, so it is now slightly generous — and refitting one rule's rate in isolation is the trap #75 describes. It will be refreshed with the next full thresholds run.

A sibling

SKILL.md told agents to "vary the count" on tricolons. In edit mode that rewrites someone's data. It now says a list of data is not a tricolon.

Verification

  • Mutation: with the original regexes, all 12 data-list tests fail; with the new ones, all 18 pass.
  • 393 + 72 + 7, plus the desktop job's 31.

Thanks to whichever terminal filed #100 — it arrived measured, with a proposal and the open questions named, which is what made this a half-day fix.

🤖 Generated with Claude Code

https://claude.ai/code/session_015PEbbiYSNPw7jE3LrPNhyF

Closes #100.

rhet.rule-of-three matched any three word-characters, so it could not tell a
rhetorical tricolon ("fast, simple, and powerful") from an author listing three
values. #100 found it on "2324, 2425 and 2526" in a support-ticket reply and
measured it: 18 of the rule's 236 corpus matches are lists like that -- gene
names, dose numbers, year codes -- and six texts had no other hit.

The narrowing is in the pack, not in C#, so the rule stays editable by anyone:
a list is skipped when none of its three items contains a lowercase letter.
Two traps shaped the regex:

- PatternAnalyzer compiles every pack pattern with IgnoreCase, so an uppercase
  class would match prose too. The token class is wrapped in (?-i:...).
- \p{Lu}, not [A-Z]: an ASCII class misses an accented acronym, which is what
  the Turkish dotless i taught this project a week ago.

Mixed lists still fire ("CD31, CD45, and cells"): requiring all three items to
be data is the conservative reading #100 argued for.

The Spanish twin, rhet.regla-de-tres, gets the same narrowing. The Spanish
corpus cannot judge it -- 14 matches, none of them data -- but the reasoning is
language-independent, and leaving the two packs asymmetric is how a sibling
goes stale.

Published numbers: unchanged in every field. The calibration run was compared
before and after the regex change, and the only fields that differ from the
committed file are engine and measuredOn -- which is why that file is not
regenerated here. humanRatePer1000 is deliberately left at 1.09: it was
measured on a superset of these matches, so it is now slightly generous, and
refitting one rule's rate in isolation is the trap #75 describes.

SKILL.md told agents to "vary the count" on tricolons, which in edit mode
would rewrite someone's data. It now says a list of data is not one.

Verified by mutation: with the original regexes, all 12 data-list tests fail.
393 + 72 + 7, plus the desktop job's 31.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015PEbbiYSNPw7jE3LrPNhyF
peopleworks added a commit that referenced this pull request Sep 16, 2026
Bumped here rather than in a later release PR, on purpose. Pages deploys on
merge, and the download page builds the installer's URL from
DesktopRelease.Version: merging the page change at 0.8.0 would point the
primary button at desktop-v0.8.0, which has no Setup.exe. The version and the
page have to land together.

All seven declarations, held together by ReleaseVersionTests.

Merge #101 first, so v0.8.1 carries the rule-of-three fix. Then cut
desktop-v0.8.1 before v0.8.1: until that tag exists, the button 404s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015PEbbiYSNPw7jE3LrPNhyF
@peopleworks
peopleworks merged commit 39c0f3c into main Sep 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rule-of-three fires on enumerations of codes and numbers, which are not tricolons

1 participant