Reads text for persuasion. Free. Runs in this tab.

No cookies. No accounts. Rules 2.0.0a5.

Method

How it works, and what is tested.

BiasClear is a set of fixed rules, not a model. This page says how the rules run, what the tests check, what the rules miss, and what nobody has measured yet.

01  The rules

One file of rules, read the same way everywhere.

Every rule lives in one file, the rule pack: rules/biasclear-rules.json, rules version 2.0.0a5. It holds 43 rules. Each rule is a set of patterns over English wording, with a name, a description, and a tier from Persistent Influence Theory: I, ideological; II, psychological; III, institutional.

Of these, 23 are general and run on every scan. Another six are for legal writing, nine for news and five for finance; they run only when a scan asks for that domain. The checker on this site runs the general rules. The Field Guide covers all of them.

The rules are deterministic. The same text gives the same result every time with the same engine and the same runtime. The Python and TypeScript engines agree on every text the tests run; they can differ only on characters that one runtime’s Unicode version assigns and the other’s does not. Nothing is learned from what you paste, and no AI model is involved.

The rules match structure. No rule lists the names of people, parties, ideologies, faiths, countries, programs, outlets, institutions or schools, and a lint fails if a rule holds a name or group word from its reference list. There is one exception, which decides only where a sentence ends: a shared list of abbreviations that do not end a sentence holds titles of every major faith (“Rev.”, “Fr.”, “Rab.”, “Ust.”, “Shri.”, “Ven.”) and both parties’ “Rep.” and “Dem.”, treated alike; the lint allows exactly these, in that list only (why). Dissent dismissed marks dismissal words that can be aimed at anyone, such as “cranks” or “shills”, and marks a group’s name only inside a frame that takes any word, such as “Only a ___ would say that”.

02  How a text is read

Patterns, then a few plain checks.

  1. Match.Each rule’s patterns run over the text. A rule marks a phrase when a pattern matches it. Five rules need two or more matches before they mark anything.
  2. Citations.Six rules check for citation shapes around the first case-insensitive occurrence of each matching phrase, within 120 characters on either side. These include a name and a year in brackets, a footnote number, a legal or page reference. A rule stays quiet only when all these windows contain a citation shape; otherwise citation suppression removes none of its matches. The rules check the shape, not whether the source exists. Repeated wording can hide an unsourced claim.
  3. Overlaps.Within one rule, overlapping matches are dropped: the earliest is kept, and of two that start together, the longer. Different rules may mark the same words; each one is listed.
  4. Tiers.Each move is counted under its tier. The count is a count, not a score.
  5. Length.The engines read up to 200,000 characters. This site’s checker reads the first 20,000.

03  What is tested

Same result in every engine. Tested with sides swapped.

693

texts with every move pinned: 521 from the first version’s tests and samples, and 172 written for the current rules. 27 more pin how non-English characters are read.

8,313

swapped pairs: the same sentence with a name or label traded for its counterpart, from 135 pairs of names and labels. Both sides must raise exactly the same rules.

1,480

more pairs from red-team reviews (separate AI review sessions run for this project) that tried to make the rules treat one side differently, and from the fixes that followed. All must pass.

  1. Two engines, one result.A Python engine and a TypeScript engine read the same rule pack. A script runs both on every pinned text and every swapped pair, in every domain, and fails on any difference. It runs on Python 3.10 to 3.14 on every change.packages/engine/scripts/parity.mjs
  2. This site runs that engine.The script this site loads is the engine package’s own browser build, byte for byte, and the site’s test checks that it gives the same results as the package.site/test/site.test.mjs
  3. Swapped sides.The swapped pairs trade names between parties and movements, government bodies and think tanks, colleges, news outlets, religions, nationalities, professions, and the two sides of contested questions, in both directions. The people, parties, organizations and outlets in them are made up, each with the shape of a real name; generic government bodies (such as a census bureau), faiths and nationalities are named as they are. 20 pairs that still differ are known limits: the same kind of wording is marked when it is aimed at one side and not when it is aimed at the other. Each has a written reason and runs as a test that is expected to fail, so a fix shows up at once. 48 more red-team pairs are retired: they set a word no rule may hold (a group’s own name, a movement’s name, a faith’s word) against a common word, or changed the kind of word rather than the side (“experts” against “historians”), so they are not mirrors. Each is listed with its reason, and where one has a true mirror, the mirror runs; none is run or counted as a limit. The pairs are also run inside the frames and slots where rules hold word shapes and short lists: “Typical ___!”, “Ignore the ___.”, “Those ___ are at it again”, the group after “leading”, and the object of “destroying”.tests/test_symmetry.py
  4. No names, no group words.A lint rejects any rule whose patterns list two or more proper nouns or acronyms from its reference list, and any rule that holds, even once, a word from its reference list of party, movement, ideology, faith, country and program names and the words built from them, such as “anti-” forms and slur blends. It cannot know every name, so the swapped pairs check the rules too.tests/test_neutrality_lint.py
  5. No side effects.The Python engine is checked to write no files, open no network connections and start no processes. The browser engine is built without access to the network or the page, and its bundle is run in an empty sandbox.tests/test_no_side_effects.py, packages/engine/test/bundle.test.ts

The counts on this page are read from the repository each time the site is built, by scripts/build-site.mjs and scripts/site_facts.py. The window sizes and the Python versions below are checked against the rules and the CI workflow by tests/test_doc_counts.py.

04  What it misses

What the rules cannot see.

  • Repeated wording and citations.Citation checks use the first occurrence of a matching phrase, even for a later copy. A cited “Studies show” near the start can silence an unsourced “Studies show” much later. Lowercasing can also shift these windows for characters such as “İ”. These are inherited engine limits.
  • Other wording.The rules know the usual wording of a move. The same move in other words goes unmarked. Each Field Guide entry shows examples.
  • Tone, insinuation, pictures and layout.A suggestion made without a claim, or a story told by what is placed first, leaves no wording to match.
  • Truth.It checks shape, not facts. A marked sentence can be true, and an unmarked one can be false.
  • Who is speaking.A quoted dismissal is marked the same as one the writer makes.
  • Whether a citation is real.Something shaped like a citation can quiet a rule, even if it points nowhere.
  • A group’s name used as a label.Dissent dismissed holds no group’s name. It marks one only inside a frame that takes any word (“Ignore the ___.”, “Typical ___!”), so “They’re just” followed by a group’s name goes unmarked. A dismissal word it does not know goes unmarked too.
  • Plain sentences with the same shape.A frame cannot tell a jibe from a plain remark, so some ordinary sentences are marked: “The fire destroyed our home.” and “The frost destroyed the petals.” read like a claim that one cause ruined everything, and “The kids loved these puppets.” like a label. They are marked the same way whoever the words are about.
  • Long names.A name slot or a gap between two parts of a rule holds at most 16 words (32 for “either … or”; a few short phrase slots hold fewer). A longer name can stop a match, for any side.
  • Capitalized words.A trigger word such as “History” or “Research” counts only at the start of a sentence, where a one-word name spelled the same way cannot be told apart from it.
  • Other languages.The rules read English.

rules/RULE_CHANGES.md lists the 20 known limits and the 48 retired pairs, each with its reason.

05  Accuracy

Accuracy on new text: not measured yet.

Nobody has yet measured how often these rules are right or wrong on text that someone else labeled. Until a script in this repository does that, this site quotes no accuracy figure. Read each mark as a prompt to look closer, not as a finding.

The first version of BiasClear published scores. They were measured on the same samples its rules were tuned on, so they said nothing about new text, and they are withdrawn.

The plan is to measure each rule on independently labeled data, starting with SemEval-2020 Task 11, with a script that fetches the data and never republishes it. The results, and the script that made them, will appear here and in the repository.