Every country in Voidly Atlas carries a risk tier, an integer 1–5 stored in country_geography.risk_tier (tier 1 = highest censorship risk, tier 5 = lowest). That tier is not a measurement. It was hand-set — an analyst typed a number. And it is not inert: the v3.3 censorship classifier consumes it as an input feature, the 7-day shutdown forecast consumes it, and several downstream surfaces lean on it. If the hand-set tier is stale or simply wrong, that error is silently baked into every model that reads it.

This finding ships a data-driven alternative: a risk tier derived from objective signals over the trailing 365 days, computed so a human can see exactly where the hand-set tier and the data disagree. It is a proposal surface only. It does not touch the country_geography table. The hand-set tier stays authoritative until a human reviews the diff.

The six features

For each country, over the last 365 days:

FeatureWhat it measures
confirmed_censorship_incident_countIncidents typed censorship or mixed. Pure disruption rows excluded — same rule the forecast labeler uses.
mean_block_rateEmpirical-Bayes-shrunk fraction of non-IODA evidence at signal_level=critical.
n_distinct_domains_blockedDistinct domains observed blocked at critical level.
n_blocking_methods_observedDistinct blocking mechanisms (DNS poison, TCP reset, blockpage…).
forecast_mean_riskMean 7-day shutdown risk from the live forecast model.
dbscan_anomaly_frequencyFraction of evidence days a CenDTect-style per-country DBSCAN flags as shape-anomalous.

Each feature is rank-transformed to [0,1] then z-scored, and the composite is the equal-weight mean of the six z-scores. Countries are then clustered with KMeans(k=5) on the composite — clusters relabeled so the highest-mean cluster is tier 1. K-means is the headline binning; an equal-frequency quantile split is reported alongside as a cross-check.

Three data-quality fixes that mattered

The first cut produced nonsense — the United States scored “60% blocked,” Sweden “100% blocked.” Three corrections, each one a real bias:

Result: 107 of 148 countries disagree

Of the 148 countries with a hand-set tier, 107 land in a different data-derived tier and only 41 agree. The data says higher risk than the hand-set tier for 41 countries and lower risk for 66. Fifty disagreements are large (≥2 tiers).

TierHand-set countData-derived (k-means) count
1 (highest risk)611
21726
38729
41643
5 (lowest risk)22108

The hand-set column parks 87 countries in a tier-3 catch-all. The data does not: most of those countries have little observed censorship and the data pushes them down to tier 4–5.

The five biggest disagreements

CountryHand-setData-derivedΔ
ER Eritrea15+4
KP North Korea15+4
TM Turkmenistan14+3
GB United Kingdom52−3
CA Canada53−2

These five are exactly the cases that prove why this stays a proposal, not an auto-apply.

Eritrea, North Korea, Turkmenistan are hand-set tier 1 — the most repressive information environments on earth. The data drops them to tier 4–5. That is not the data being right. It is the data being blind: there are almost no OONI probes inside those countries, so the trailing 365-day window shows near-zero blocked domains, near-zero incidents, a flat block rate. Total censorship and zero measurement look identical to a feature pipeline. The hand-set tier encodes political reality the data cannot see — this is the headline reason the hand-set tier stays authoritative.

The UK and Canada move the other way: hand-set tier 5, data-derived tier 2–3. They are heavily probed, so they accumulate a non-trivial DBSCAN anomaly frequency and a handful of genuine but minor blocking events. The data is not claiming the UK is China; it is saying that, on recent measured signal alone, a well-instrumented democracy with any blocking at all out-ranks an unmeasured country. Whether that is a tier-2 country or a tier-5 country with measurement noise is precisely the call a human should make.

Honest caveats

Live at

GET /v1/atlas/risk-tiers — full comparison table
GET /v1/atlas/risk-tiers?disagreeing_only=1&min_magnitude=2 — just the big disagreements
GET /v1/atlas/risk-tiers/CN — per-country detail with features + z-scores

Built by scripts/build-data-driven-risk-tiers.py. Sidecar at /opt/voidly-ai/ml-deploy/data_driven_risk_tiers_v1.json. This is a transparency artifact: it makes a hand-set number auditable, and it gives a human a ranked list of exactly which 148 country tiers to re-examine first.