Skip to content

feat(core): flag "tenant" misused for "tenet" - #3822

Open
ozpool wants to merge 2 commits into
Automattic:masterfrom
ozpool:feat/tenant-tenet
Open

feat(core): flag "tenant" misused for "tenet"#3822
ozpool wants to merge 2 commits into
Automattic:masterfrom
ozpool:feat/tenant-tenet

Conversation

@ozpool

@ozpool ozpool commented Jul 14, 2026

Copy link
Copy Markdown

Issues

Closes #1070.

Description

tenant (a renter) is commonly written where tenet (a principle) is meant — "a core tenant of good design", "the main tenants of many religions". Harper did not catch this.

This adds a TenantTenet rule that flags tenant / tenants when it follows a principle-sense adjective (core, central, fundamental, basic, guiding, cardinal, underlying, foundational, defining) and suggests tenet / tenets:

  • a core tenant of good designa core tenet of good design
  • the central tenants of the movementthe central tenets of the movement

To keep false positives low, it deliberately only fires after that adjective set, where the renter reading is implausible. Real-estate senses are left untouched — the main tenant, a key tenant, three tenants, commercial tenants. Broader frames (e.g. bare tenants of X) are intentionally out of scope for now, since tenant is a valid word and over-flagging would be worse than the occasional miss.

The rule is a grouped Weir rule (singular + plural children under TenantTenet/) because the two forms need different replacements.

No related PRs.

Demo

$ harper-cli lint "These are the core tenants of our design."
1 │ These are the core tenants of our design.
  │                   ╰──────── [Malapropism::TenantTenet]: Did you mean `tenets`?

$ harper-cli lint "The main tenant of the building left."   # no lint (renter)

How Has This Been Tested?

Embedded Weir tests (16 correction cases + 8 negative cases across the two children):

$ harper-cli test harper-core/src/linting/weir_rules/TenantTenet/Singular.weir
All tests pass!
$ harper-cli test harper-core/src/linting/weir_rules/TenantTenet/Plural.weir
All tests pass!

Rust suite (rule registration + curated-config drift check):

$ cargo test -p harper-core --lib curated_default_config_lists_every_registered_rule
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5803 filtered out

$ cargo test -p harper-core --lib run_tests_for_weir_rules
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5803 filtered out

Also checked by hand that renter-sense phrases (the main tenant, a key tenant, three tenants) stay clean.

AI Disclosure

  • I am a human and didn't use any AI.
  • I used LLM features of my editor, but not an agent.
  • I used an AI agent interactively.
  • I am an agent or I got an agent to do the work autonomously.

If Your PR Implements or Enhances a Linter

  • I made up the sentences in the unit tests.
  • The sentences in the unit tests were generated by an AI.
  • I'm using examples from the bug report / feature request.
  • I collected real-world sentences for the unit tests.

Checklist

  • I have performed a self-review of my own code
  • I have added tests to cover my changes
  • I have considered splitting this into smaller pull requests.

"tenant" (a renter) is often written where "tenet" (a principle) is
meant. Adds the TenantTenet rule, which flags "tenant"/"tenants" after a
principle-sense adjective (core, central, fundamental, guiding, ...) and
suggests "tenet"/"tenets" ("a core tenant of good design" -> "a core
tenet of good design").

Real-estate senses ("the main tenant", "three tenants") are left alone.

Closes Automattic#1070
@ozpool
ozpool force-pushed the feat/tenant-tenet branch from 46acc68 to 13ed6d4 Compare July 17, 2026 07:55

@hippietrail hippietrail left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I wrote this message hours ago while on the road, but it seems as though I failed to submit it?)

I would like to see this run over a large corpus of real-world text somehow. Mainly because when I was researching this with tons of manual Google searches I found "tenant" used legitimately in tech contexts far more than I was expecting. So much so that it proved very difficult to find examples of the mistake.

By the way, I've never heard or read anybody using "tenet" when they intend the meaning of "tenant" so we don't need to handle that case.

Now I've tried quite a lot to get an AI agent to harvest real-world examples for Harper testing and so far I've not found anything that works. In particular I can't get them to automate my way, which is Google searches with search operators to include all inflections and sometimes wildcards. But I've only used free AI tools. Maybe somebody with access to paid tools who is interested in tackling this can do it.

"tenant" is used legitimately as a noun modifier in multi-tenancy
writing ("core tenant isolation", "fundamental tenant model"), where the
adjective binds to the whole compound rather than to "tenant" itself.
Require the following token to be a non-noun so those cases are left
alone, and cover them with tests.

The trade-off is that a sentence-final "a core tenant." is no longer
flagged, since there is no following token to inspect. Avoiding the
false positives is worth more than catching that form.
@ozpool

ozpool commented Jul 23, 2026

Copy link
Copy Markdown
Author

Good call — you were right, and it did fire on the tech usage you mentioned. Going looking for it, I hit exactly that:

  • "The core tenant isolation logic lives here."
  • "Our fundamental tenant model uses row-level security."
  • "The basic tenant configuration is in config.yaml."

The problem is that in multi-tenancy writing tenant is a noun modifier, so the adjective binds to the whole compound — core [tenant isolation], not [core tenant]. The adjective gate on its own couldn't tell those apart.

Pushed a fix: the rule now requires the token after tenant / tenants to be a non-noun, which leaves the compound cases alone while still catching the mistake.

text before after
core tenant isolation logic flagged clean
fundamental tenant model flagged clean
basic tenant configuration flagged clean
core tenants list is stored per region flagged clean
multi-tenant architecture, tenant ID clean clean
the tenant paid rent, commercial tenants clean clean
a core tenant of good design flagged flagged
one of my central tenants is honesty flagged flagged
Core Tenants of Highly Effective Teams flagged flagged

One trade-off worth flagging: a sentence-final a core tenant. is no longer caught, since there is no following token to inspect. Avoiding the false positives seemed worth more than catching that form.

Agreed on the direction, too — the rule only goes tenanttenet, never the reverse.

On the corpus point: I don't have a good automated harvesting setup either. What I have done instead is keep the trigger deliberately narrow — only the nine principle-sense adjectives, plus the noun-modifier exclusion — so it stays conservative and misses real instances (key tenants, main tenants) rather than risk firing on legitimate text. Happy to widen it if a corpus ever shows that is safe.

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.

Flag using "tenant" instead of "tenet".

2 participants