The Positive Test That's Probably Wrong

A test is 99% accurate. It just told you that you have a disease that 1 in 100 people carry. How worried should you be? The honest answer is a coin flip. This is the trap Bayes' theorem unsprings, and you can watch it spring below.

If your test comes back positive, the chance you are actually sick is

50.0%

Out of everyone who tests positive, half are perfectly healthy people the test flagged by mistake.

Turn the three dials

How many people in the population actually have it, before any test.

Of people who are sick, the share the test correctly flags positive.

Of people who are healthy, the share the test correctly clears. The rest are false alarms.

sick & caught 99 sick, missed 1 healthy, false alarm 99 healthy & cleared 9801

In this rounded grid of 10,000 people, 100 are sick; the test catches 99 of them. The other 9,900 are healthy, but the test still flags 99 of them by mistake. So 198 people test positive, and only 99 are truly sick. Grid share: 99 in 198 (about 50.0%). The model probability is 50.0%.

The same thing, in modern notation

P(sick | positive) = P · Se / ( P · Se + (1−P) · (1−Sp) ) ≈ 50.0%

That is all Bayes' theorem is: the positive results split into the truly sick (P · Se) and the false alarms ((1−P) · (1−Sp)), and you ask what fraction of the pile is real. When the disease is rare, the false-alarm pile is drawn from the enormous healthy majority — so even a tiny false-positive rate can swamp the few true cases. The accuracy of the test never appears alone; it is always weighed against how rare the thing you're testing for is. Ignore the base rate and you get the wrong answer — usually by reporting the test's accuracy as if it were your odds.

This isn't a hypothetical failure. In 1978 Casscells and colleagues posed exactly the 1-in-1000 / 5%-false-alarm question to staff and students at Harvard Medical School. The most common answer was 95%. The correct answer is under 2% — and only about 18% of them got it right.1 Set the dials to the Casscells preset above and watch why.

Show the check

Selected count calculations and sampled probability-versus-odds comparisons are checked in research/bayes-theorem/verify.mjs (run it from a fresh checkout). It checks:

Machine-checked — the kernel pins the thesis

The check above computes the answer once, in JavaScript, and samples its universal claims over random draws. A sample is evidence, not a proof. So the same counts are now handed to a proof assistant's kernel in research/bayes-theorem/lean/Bayes.lean (Lean 4, zero imports — no library, only the kernel is trusted). Over an equiprobable population a plain count is a probability: the kernel builds all 1,000 people of a clinic and counts them, and — where the sampling could only check a finite window — it proves the base-rate law for every population at once.

-- The clinic, enumerated: 1,000 people; 1% sick; test catches 90%, false-alarms 10%.
def clinic : List Person := cohorts 9 1 99 891

-- Of the 108 who test positive, only 9 are truly sick: 9/108 = 1/12 ≈ 8.3%.
theorem clinic_posterior_one_twelfth :
    countB truePos clinic * 12 = countB positive clinic * 1 := by decide

-- The headline: a "99% accurate" test on a 1-in-100 disease → 99/198 = 1/2, a coin flip.
theorem flagship_is_a_coin_flip : 99 * 2 = (99 + 99) * 1 := by decide

-- Rarity beats accuracy — proved for EVERY population, not sampled:
-- however sensitive the test (tp ≤ sick), if false-alarms outnumber the sick
-- population (sick < fp), a positive is more likely a false alarm (tp < fp).
theorem rarity_beats_accuracy (sick tp fp : Nat)
    (hacc : tp ≤ sick) (hrare : sick < fp) : tp < fp ∧ 2 * tp < tp + fp := by
  refine ⟨?_, ?_⟩ <;> omega

#print axioms the_base_rate_decides       -- enumerated counts: NO axioms at all
#print axioms rarity_beats_accuracy       -- universal (omega): [propext, Quot.sound]

Lean 4.30 · the_base_rate_decides — does not depend on any axioms · rarity_beats_accuracy — [propext, Quot.sound]

No sorry, no Classical.choice, no native_decide. The enumerated counts reduce in the kernel and depend on no axioms whatsoever; the universal theorems lean only on the two propositional axioms every Lean proof may use. Re-run it yourself: bash research/bayes-theorem/lean/verify.sh (Lean not installed? bash research/bayes-theorem/lean/install-lean-nix.sh). verify.mjs §6 recomputes the integer counts in JavaScript and, when lean is on your PATH, runs the proof live and confirms the axiom verdict — all pass.

The claims record 112 claims re-read against their sources, 14 October 2026

Written 2026-06-22. Claims re-read against their sources on 2026-10-14: 112 checked, 89 confirmed, 22 wrong, 0 unverifiable, 1 true when written and overtaken since (dated, not corrected). By the assay line (research/assay-line/queue-1014c/), Codex fixer directed by claude-assaying-boyle-1014; source record by Codex, checked by Codex.

This was the directed queue-1014c repair pass for bayes-theorem, read at dd89bb6ab4. The fixer independently re-read the evidence for all 24 triage items, reproduced the original numerical failures, and repaired 21 items within this layer. X10 was rejected with primary-source evidence. X19 remains MINOR and is listed under the shared placard hold; X20 remains STALE pending the shared landing regeneration, with this record supplying the new pass date. The 88 CONFIRMED claims from the Codex checker are carried forward as explicitly attributed baseline re-reads, not recast as fresh observations. The wrong count includes 11 WRONG and 11 MINOR lines. Eight correction lines cover the 11 repaired WRONG copies; MINOR repairs have no page correction line.

This record is long (112 claim lines and 23 findings), so it is not part of the page until you open it. It loads here now if your browser runs scripts; otherwise, or to keep it, read the whole record as plain text.

The assay office: what a record is, and every layer re-read so far.