What this is

Voidly Atlas already ships four independent unsupervised anomaly detectors, each capturing a different axis of unusual network behavior:

The friction problem this finding solves: a journalist checking coordinated censorship today had to hit four separate endpoints and reconcile four different score scales. We now fuse all four into one composite anomaly score per country per day, with the per-detector breakdown returned inline so the explanation isn’t hidden.

How the fusion works

Heuristic weights, chosen up-front and documented in the weights field of every response:

composite = 0.35 * norm(dbscan)
          + 0.25 * norm(stl)
          + 0.20 * norm(burst)
          + 0.20 * norm(hdbscan)

Each component is min-max normalized to [0, 1] across the population of scored country-days for that day’s snapshot. Composites are computed only over present components; weights renormalize when a detector has no observation for a country.

The honest result — raw fusion doesn’t beat the best single detector

Evaluating each detector at the exact (country, date) of every labeled incident in the last 60 days (n=2,806 labels, 837 positive):

DetectorAUC vs labels
DBSCAN (per-country shape)0.6306
STL (seasonal residual)0.5540
HDBSCAN (per-domain drift)0.4443
Burst (multi-country coincidence)0.4222
Raw composite (all 4, fixed weights)0.4949

The raw composite is below chance, because two detectors (burst, hdbscan) are actively anti-correlated with positive labels in this period. That isn’t a bug — it means those detectors are surfacing a different population than what the v3.3 label rule treats as “censorship.” In particular: the 2026-05-21 burst was a coordinated OONI sweep of tiktok.com, and the drifting domains this week are AI services with no per-country label rule. Both are real signals, just not the same signal as labels.

What we actually ship

The build script tries three fusion strategies, picks the one with the highest at-label AUC, and reports the choice (and the other two AUCs) in eval for transparency:

  1. raw — the 4-detector weighted average as spec’d.
  2. sign_corrected — flip detectors with AUC<0.5 (i.e. anti-correlated) before averaging.
  3. dropped — drop detectors with AUC<0.5 entirely, reweight survivors.

On today’s build the winning strategy is dropped: burst + HDBSCAN are excluded, DBSCAN + STL combine for a composite AUC of 0.6842 — +5pp above the strongest single detector (DBSCAN at 0.6306). That clears the “composite must beat best single” promotion floor in the spec, so the endpoint is exposed.

Critically, we still expose the all-4 view in every response: n_all4_strong, n_all4_present, and all4_strong_flags answer “how many of the 4 original detectors are firing on this country today, regardless of eval-time weighting decisions?” That preserves the journalist-facing question (multi-detector agreement) without pretending all four are equally informative for the label rule.

What the leaderboard looks like today

Top 5 countries by composite anomaly score on 2026-05-21 (AU, DE, JP, NL, CA) all show DBSCAN flagging the country-day as a high-distance noise point with corroborating STL residual; 1 country (US) shows all 4 detectors firing strong — DBSCAN anomaly_score 8.40, STL residual 0.49, member of a 15-country burst on tiktok.com, and weighted HDBSCAN drift 0.23 from a domain mix where tiktok.com leads. That doesn’t imply US is censoring today; it does mean the network shape, the seasonal residual, the multi-country coincidence, AND the per-domain drift signal are all above 75th-pct simultaneously.

Honest caveats

API

Cron: daily 05:30 UTC after the four upstream detectors finish. Sidecar: /opt/voidly-ai/ml-deploy/fused_anomaly_v1.json. Source: scripts/build-fused-anomaly-ensemble.py + scripts/patch-fused-anomaly-endpoint.py.