Contents
At a glance
The GGRI is a single-number daily index of global geopolitical risk, scored 0–100, delivered every weekday at 0500 EST. See a sample daily brief → for the actual format subscribers receive.
The score is the weighted sum of nine deterministic components plus a small bounded chaos term:
where:
- Cᵢ is component score i (each on 0–100)
- Wᵢ is its weight (Σ = 1.00, asserted at module load)
- Z ∈ ℤ ∩ [−5, +5] is a chaos draw from a CSPRNG (
secrets.SystemRandom().randint(-5,5)in the local engine;RANDOM.orgtrue-RNG path on the production Mac)
Tier mapping
| Tier | Range | Operational meaning |
|---|---|---|
| LOW | 0–20 | Baseline. Background of routine geopolitics. |
| MODERATE | 21–40 | Elevated friction; specific theaters bear watching. |
| ELEVATED | 41–60 | Multiple active theaters; markets noticing. |
| HIGH | 61–80 | Active kinetic + sanctions cycles + market stress. |
| EXTREME | 81–100 | Multi-theater conflict, energy/finance dislocation, cyber escalation. |
What changed in v1.1
v1.0 ran six components. v1.1 adds three and rebalances. Rationale:
- C7 Sanctions & Regulatory was being absorbed into C2 Geopolitical Tensions, where regulatory-cycle signal got averaged into vague sentiment. OFAC / EU / BIS actions are leading indicators that deserve their own weight.
- C8 Energy & Chokepoints was being averaged into C3 Markets, which is dominated by VIX. The May 5 run is the case study: VIX 18.29 (composed) while WTI is $107 and the Strait of Hormuz is contested. Splitting energy out lets the model react to chokepoint stress independent of equity vol.
- C9 Civil Stability captures things that aren't inter-state tension but matter operationally — protests, election windows, coups, constitutional crises. Lower weight than the others because some signal already flows into C1 and C4.
Component table — v1.1 weights
| Component | Weight | What it measures | |
|---|---|---|---|
| C1 | Conflict | 0.22 | Active kinetic engagement; combat tempo; civilian casualties; refugee flows |
| C2 | Geopolitical Tensions | 0.16 | Diplomatic posture; alliance stress; expert-rated state-vs-state risk |
| C3 | Markets | 0.10 | VIX, sovereign CDS, currency stress, equity drawdowns (excludes energy) |
| C4 | News Tone | 0.13 | VADER-scored sentiment across major outlets; press-freedom signal |
| C5 | Social Attention | 0.09 | Reddit r/worldnews ranking; Telegram channel velocity; Wikipedia spikes |
| C6 | Cyber | 0.09 | CISA KEV adds; ransomware disclosures; nation-state campaigns |
| C7 | Sanctions & Regulatory (new) | 0.07 | OFAC/EU/UK actions; export controls; treaty withdrawals |
| C8 | Energy & Chokepoints (new) | 0.07 | WTI/Brent/LNG; Hormuz/Suez/Bab-al-Mandeb status; AIS-derived shipping disruptions |
| C9 | Civil Stability (new) | 0.04 | Protest counts (ACLED); election-window risk; coup probability; cabinet collapses |
| Sum | 1.00 | (assert at module load) | |
| Chaos term | ±5 | bounded integer, CSPRNG-drawn | |
Why the weight shifts
- C1 (0.25 → 0.22): still the largest, still the dominant signal, but no longer carries the regulatory or energy load.
- C3 (0.15 → 0.10): with energy lifted into C8, what remains in C3 is plain equity vol + currency / sovereign-credit stress. That deserves less weight on a geopolitical index where markets are usually downstream.
- C2 (0.20 → 0.16): loses the sanctions-cycle load to C7 (where it belongs).
- C4 (0.15 → 0.13), C5 (0.10 → 0.09), C6 (0.10 → 0.09): small reductions to balance the three new additions.
Component scoring rubrics
Each component returns a 0–100 score from a small number of normalized sub-signals.
C1 — Conflict
Sub-signals: active conflict-day tally (theaters with kinetic combat in last 24h), ACLED event count delta vs. 30-day rolling average, civilian casualty reports (CrisisWatch, ISW), refugee-movement reports (UNHCR ETT).
Mapping: 0 = no active conflict; 50 = one major theater + low-intensity others; 80 = multiple major theaters + acceleration; 100 = WMD use or peer-state direct combat.
C2 — Geopolitical Tensions
Sub-signals: expert surveys (CSIS ChinaPower, AEI tracker, Just Security); diplomatic moves (treaty withdrawals, embassy closures, ambassador recalls — minus the sanctions/regulatory component, which is now C7); alliance stress (NATO/QUAD/SCO friction signals); high-stakes summits (positive signal: scheduled; negative signal: cancelled).
C3 — Markets (narrowed in v1.1)
Sub-signals: VIX level + 5-day rate of change; sovereign CDS spreads (top-20 economies, weighted); currency stress (DXY, EM-FX volatility); equity drawdowns vs. 30-day high.
C4 — News Tone
Sub-signals: VADER compound sentiment across the day's headlines per source, then per-tier weighted average; press-freedom signal (RSF index events); headline-volume concentration (high concentration on geopolitical themes = elevated).
C5 — Social Attention
Sub-signals: Reddit r/worldnews top-10 attention concentration; Wikipedia view spikes on country/conflict articles; Telegram channel velocity in war-zone-relevant channels (where reachable).
Caveat: sandbox runs from Lambda are blocked from Reddit and Telegram; on those days C5 is qualitatively assessed and flagged in the brief. The local production engine is unrestricted and produces the canonical value.
C6 — Cyber
Sub-signals: CISA KEV adds in last 24h (count + severity); ransomware disclosures with sectoral materiality (banking/critical infrastructure weighted higher); nation-state campaign reports (CYFIRMA, Mandiant); major CVE active-exploitation flags.
C7 — Sanctions & Regulatory (new)
Sub-signals: OFAC designations (last 24h, weighted by target severity); EU/UK sanctions packages; BIS export-control list adds; Federal Register executive orders with international scope; treaty withdrawals / suspensions; embargo escalations.
Mapping: 0 = quiet day; 50 = routine designations only; 80 = major package (e.g., Russia 14th-package class); 100 = sweeping multilateral action (oil cap, secondary sanctions, etc.).
C8 — Energy & Chokepoints (new)
Sub-signals: WTI / Brent / LNG (TTF, JKM) day-over-day moves; Strait-of-Hormuz transit status (incidents, escort posture); Suez / Bab-al-Mandeb / Malacca traffic flags; maritime AIS-derived disruptions (vessel redirections, port closures); pipeline status (Druzhba, BTC, Nord Stream class events); strategic commodity stress (rare earths, lithium, grain export controls).
Mapping: 0 = quiet markets, no chokepoint stress; 50 = elevated oil + minor maritime incident; 80 = chokepoint contested + structural energy shock; 100 = sustained chokepoint closure or strategic embargo.
C9 — Civil Stability (new)
Sub-signals: ACLED protest event counts (delta vs. 30-day rolling average); election-window risk (countries entering 60-day pre-election window); coup / regime-change indicators (sudden cabinet collapses, military redeployments to capitals); constitutional crises (referenda, judicial-executive standoffs).
Mapping: 0 = quiet domestic politics globally; 50 = scattered protests + 2–3 election windows; 80 = simultaneous protests in 5+ countries or a coup in progress; 100 = coordinated regional unrest or multiple state-failure events.
Source pool — 41 feeds across 4 tiers
Sources are grouped into four tiers, with a downstream weight applied to each tier when computing tone, attention, and event-count signals.
Tier 0 — Primary government (no editorial layer) — weight 1.00
OFAC Recent Actions, Federal Register, CISA KEV catalog, CISA Alerts, EU Official Journal (sanctions section).
Tier 1 — Wire / authoritative — weight 0.90
AP News (apf-topnews), AFP (when reachable), CrisisGroup CrisisWatch, ISW (Institute for the Study of War), ACLED, Bellingcat.
Tier 2 — Established media / think tanks — weight 0.70
BBC World, BBC US & Canada, BBC Africa, BBC Middle East, BBC Asia, BBC Latin America; Guardian World, Guardian US, Guardian UK; NPR World, NPR Politics, NPR National; VOA World; Yahoo News World, Yahoo News US; CBS News World; ABC News World; Al Jazeera; CSIS, AEI (China-Taiwan tracker), Just Security; Kyiv Independent, The Moscow Times, Times of Israel, South China Morning Post; CYFIRMA Weekly Intelligence.
Tier 3 — State-affiliated (always flagged) — weight 0.40
RT (Russia), TASS (Russia), Xinhua (China), PressTV (Iran).
State-affiliated sources are never excluded — Moscow's framing of Hormuz is operationally relevant — but they are always flagged in the response payload (source_class: "state_affiliated", with the affiliated state) so consumers can choose to discount.
Sources we'd like but can't include yet
- Reuters — retired most public RSS in 2023; available only via paid API at ~$800+/mo enterprise tier. Defer until paying-subscriber base supports it.
- Bloomberg, NYT, WSJ — paywalled; same call.
- GDELT — Lambda IPs blocked; would need a paid proxy or self-hosted ingest.
- Reddit r/worldnews — Lambda IPs blocked; same.
- CNN — limited public RSS; testing reachability for inclusion next iteration.
Country attribution
For per-country scoring (the AtlasRisks dashboard), each headline is attributed to one or more countries via:
- Keyword match — ~250 country/keyword mappings covering capitals, leader names, key institutions, and common synonyms (USA: also catches Trump, White House, Pentagon, Federal Reserve, Wall Street, Silicon Valley, etc.).
- Region fallback — when a feed is region-specific (e.g., BBC US & Canada, Guardian UK), unmatched articles default to the feed's primary country.
global_recentfallback — a per-day rolling list of the 25 most-recent global headlines is exposed so countries with no specific coverage today still show real fresh news with a "no country-specific coverage" flag.
The chaos term
A bounded integer drawn from CSPRNG (secrets.SystemRandom().randint(-5,5)) added to the deterministic score. Two purposes:
- Prevent pseudo-precision. A daily 0–100 index that always returns 73.5 implies a precision the underlying signal doesn't support. The chaos term keeps the index honest about its noise floor.
- Make the model robust to over-interpretation. A consumer who treats the score's last-decimal as meaningful is misreading the index; the chaos term is a small but real reminder that this is a direction-of-risk indicator, not a measurement.
The local production engine uses the RANDOM.org true-RNG path when reachable (atmospheric-noise true random) and falls back to OS CSPRNG otherwise. The cloud sandbox cannot reach RANDOM.org and uses CSPRNG only; the chaos_provenance field in the output JSON records which path was used.
Output schema
The daily JSON brief returns:
{
"date": "2026-05-05",
"version": "1.1",
"ggri": 63.4,
"deterministic": 62.4,
"chaos": 1,
"chaos_provenance": "csprng_local", // or "random_org_atmospheric"
"tier": "HIGH",
"components": {
"C1": { "score": 78, "weight": 0.22, "contribution": 17.16, "evidence": [...] },
"C2": { "score": 70, "weight": 0.16, "contribution": 11.20, "evidence": [...] },
"C3": { "score": 52, "weight": 0.10, "contribution": 5.20, "evidence": [...] },
"C4": { "score": 62, "weight": 0.13, "contribution": 8.06, "evidence": [...] },
"C5": { "score": 60, "weight": 0.09, "contribution": 5.40, "evidence": [...] },
"C6": { "score": 58, "weight": 0.09, "contribution": 5.22, "evidence": [...] },
"C7": { "score": 72, "weight": 0.07, "contribution": 5.04, "evidence": [...] },
"C8": { "score": 80, "weight": 0.07, "contribution": 5.60, "evidence": [...] },
"C9": { "score": 35, "weight": 0.04, "contribution": 1.40, "evidence": [...] }
},
"top_drivers": ["C8", "C1", "C2"],
"anomalies": [...],
"by_country": { "IRN": { "score": 88, ... }, "USA": { ... }, ... },
"global_recent": [...],
"sources_used": [
{ "id": "ofac_recent", "tier": 0, "weight": 1.0, "items": 3 },
{ "id": "rt", "tier": 3, "weight": 0.4, "state_affiliated": "Russia", "items": 7 },
...
]
}
Changelog
v1.1 — 2026-05-05
- Added C7 (Sanctions & Regulatory), C8 (Energy & Chokepoints), C9 (Civil Stability)
- Reweighted C1 0.25→0.22, C2 0.20→0.16, C3 0.15→0.10, C4 0.15→0.13, C5 0.10→0.09, C6 0.10→0.09
- Expanded source pool from 22 to 41 feeds, organized in 4 tiers
- Added tier-weighting (T0=1.0, T1=0.9, T2=0.7, T3=0.4) on tone/attention/event-count rollups
- Added explicit
state_affiliatedflag on T3 source items in output - Added
versionandchaos_provenancefields in output JSON - Preserved weight-sum assert at module load (
assert sum(W.values()) == 1.0)
v1.0 — 2026-04-24
- Initial six-component model: C1 (0.25), C2 (0.20), C3 (0.15), C4 (0.15), C5 (0.10), C6 (0.10)
- 22-feed OSINT pool
- Chaos term ±5
- launchd-scheduled daily run at 0500 EST on the production Mac
How to read the GGRI
The GGRI is a direction-of-risk indicator, not a measurement. A 63.4 today and a 62.1 tomorrow does not mean risk fell by 1.3; the noise floor is wider than that. Read tier transitions, week-over-week trajectory, and the top-three drivers — not last-decimal moves.
Use the per-component scores and the linked evidence in evidence: [...] to investigate why the day's score is what it is. The score is a starting point for analysis, not a substitute for it.
— AtlasRisks · GGRI v1.1 · 2026-05-05