Voidly's supervised v3.3 classifier sits at F1 0.729 / AUC ≈ 0.99 on labeled incidents — by far our strongest signal. But labels are themselves curated, and the unsupervised view answers a different question: which (country, day) feature vectors look weird, regardless of whether anyone wrote them up as an incident?

CenDTect (Aceto & Pescape, 2025) proposed clustering OONI measurements with DBSCAN and treating noise points (cluster label -1) as candidate censorship. We adapted that to a per-country rolling window over the full Voidly evidence table.

The build

Results

Honest caveats

Why ship it

The supervised classifier is trained against the same labels its AUC is measured against — it overfits the human-curated “what counts as an incident” definition. DBSCAN doesn't see labels at all. When the two disagree, the disagreement is itself the signal — a (country, day) the classifier shrugs at but DBSCAN flags is exactly the kind of case worth a human look.

Live at

GET /v1/anomaly/dbscan/{cc} — score a country's most-recent day (with feature vector + interpretation)
GET /v1/anomaly/dbscan/leaderboard?limit=20 — most-anomalous countries right now
GET /v1/anomaly/dbscan/info — full sidecar metrics for transparency

Example: GET /v1/anomaly/dbscan/IR currently returns anomaly_score ≈ 4.89, is_anomaly=true, with 100% block_rate across 12 critical measurements concentrated on a single ASN — a textbook shape-anomalous day.