Methods
Everything the essay claims came out of the simulator on this site. This page states the model precisely enough to argue with, lists the parameters the published figures were produced at, and links to the source — which this site serves directly, so nothing here needs taking on trust.
The model
Every agent occupies one of four states. Unaware has not heard the claim. Believer heard it, holds it, and is still repeating it. Doubter heard it and rejects it, and may carry the correction. Fatigued still holds it but has stopped raising it — a silent carrier, and the reason a wave can return.
Agents also carry a conviction in [0,1], raised by every reinforcing contact. Conviction has three effects: it increases how often an agent brings the claim up, it reduces the probability a correction moves them, and it slows the rate at which they lose interest.
Uptake
For a believer contacting an unaware agent j, adoption
probability is
p = virality · (1 − skeptic[j]) · (1 + socialProof · 2 · proof[j]) · (1 + repetition · exposures[j])
capped at 0.95, and multiplied by 0.45 if j has already met the
correction. proof[j] is the fraction of j's own
contacts currently repeating the claim — this is the complex-contagion term,
and it is why four friends are not four times one friend.
skeptic[j] is drawn per agent from a normal distribution around
the population skepticism, so there are always credulous and
stubborn tails.
Loss of interest
After a believer's contacts for a tick, they fall silent with probability
quit = stifling · (1 + 1.5 · staleFraction) · (1 − 0.6 · conviction)
where staleFraction is the share of that tick's contacts who
already knew. This is the Daley–Kendall stifling rule, and it is what gives the
model a finite infectious period and therefore a genuine epidemic threshold. An
earlier revision omitted it; every parameter setting then saturated at about
98% reach and virality changed nothing but timing.
Correction
A correction converts believers with probability
correctionStrength · (1 − resistance), where resistance rises with
conviction and with local social proof. A correction that fails to land is not
neutral: it raises conviction by 0.14 · backfire, and against a
fatigued agent it may return them to actively spreading. Corrections also reach
unaware agents, who become doubters — this inoculation is the mechanism behind
the timing result, since its value is proportional to how many people the claim
has not yet reached.
Networks
Generated fresh per run: Watts–Strogatz small world, Barabási–Albert scale-free, a stochastic block model for communities, and Erdős–Rényi as a null case. A node's audience per telling scales with the square root of its degree. Without that term, degree affects only who you hear from, hubs stop behaving like hubs, and scale-free networks wrongly resist spread more than clustered ones do.
Parameters
Published figures use these values unless the text says otherwise. They are
the same defaults the simulator loads, in
src/sim/model.js.
| Parameter | Value | What it sets |
|---|---|---|
| n | 520 | agents |
| avgDegree | 7 | mean contacts |
| rewire | 0.09 | small-world shortcuts |
| seeds | 3 | agents who start believing |
| virality | 0.11 | base chance one telling lands |
| socialProof | 0.55 | weight on the complex-contagion term |
| repetition | 0.12 | illusory-truth gain per exposure |
| skepticism | 0.35 | population mean resistance |
| chattiness | 3 | tellings per believer per tick |
| amplification | 0.25 | popularity bias and out-of-network delivery |
| stifling | 0.18 | rate of losing interest |
| correctionStrength | 0.30 | persuasiveness of a fact-check |
| backfire | 0.35 | hardening from a failed correction |
Reproducing the figures
Every number in the essay is a mean over 30 independent runs, each on a freshly generated network with a fresh seed. Runs are seeded, so a given seed reproduces a run exactly.
The quickest check is the page itself: set the controls to the values above,
press Run 40 trials, and compare. For the table showing that timing beats
strength, vary only factCheckTick and
correctionStrength.
To run it outside the browser, the modules are plain ES modules with no
dependencies and no build step. Fetch
model.js,
generators.js,
rng.js and
sweep.js, then:
import { runSweep } from './src/sim/sweep.js';
import { DEFAULTS } from './src/sim/model.js';
const early = await runSweep({ ...DEFAULTS, virality: 0.13, factCheckTick: 8,
factCheckReach: 0.08, correctionStrength: 0.2 }, 30);
const late = await runSweep({ ...DEFAULTS, virality: 0.13, factCheckTick: 55,
factCheckReach: 0.08, correctionStrength: 0.8 }, 30);
console.log(early.mean, late.mean); // ≈ 0.25, ≈ 0.97
The source
This site serves its own source. Nothing is minified and there is no build step, so these are the files the simulator above is actually running:
src/sim/model.js— states, transition rules, summary statisticssrc/graph/generators.js— the four network generatorssrc/sim/sweep.js— Monte Carlo trialssrc/sim/rng.js— seeded generatorsrc/ui/presets.js— the scenarios, with their exact parameters
MIT licensed. If you find an error in the model, it is an error in the findings too, and I would like to know.