Country Instability Index (CII) Algorithm: Signals, Weighting, and Score Calculation Explained
The Country Instability Index aggregates dozens of real-time signals into four weighted components—Unrest (25%), Conflict (30%), Security (20%), and Information (25%)—then applies dynamic boosts and risk floors to generate a final 0-100 stability score.
The koala73/worldmonitor repository implements a sophisticated country instability index (CII) that transforms heterogeneous data streams—from ACLED conflict reports to GPS jamming events—into a normalized risk metric. This article breaks down the exact signals, component weightings, and algorithmic boosts defined in src/services/country-instability.ts that determine how the final score is calculated.
Core Components and Signal Sources
The CII algorithm aggregates raw signals into four capped components (0-100). Each component is computed by dedicated functions that normalize disparate data sources into comparable scores.
Unrest Component
The Unrest score captures civil disorder and information blackouts through social-unrest events and internet outages.
- Primary signals: Social-unrest events (protests) including count, fatalities, and high-severity flags; internet-outage events categorized as total, major, or partial
- Calculation:
calcUnrestScore(lines 726-759) scales protest volume by a country-specific multiplier, adds fatality and severity boosts, and incorporates a separate outage boost. The total is capped at 100. - Source file: [
src/services/country-instability.ts](https://github.com/koala73/worldmonitor/blob/main/src/services/country-instability.ts#L726-L759)
Conflict Component
The Conflict score measures kinetic violence and military engagements using armed conflict data and strike activity.
- Primary signals: ACLED conflict events (battles, explosions, civilian-targeted violence); UCDP status as a fallback; recent conflict news as a floor; high-severity strikes; OREF alerts for Israel
- Calculation:
calcConflictScore(lines 891-934) combines ACLED-derived counts with fatality boosts, applies a HAPI fallback when ACLED data is absent, enforces a news-floor when both are missing, and adds strike and OREF boosts. Capped at 100. - Source file: [
src/services/country-instability.ts](https://github.com/koala73/worldmonitor/blob/main/src/services/country-instability.ts#L891-L934)
Security Component
The Security score tracks military mobilization and infrastructure disruptions.
- Primary signals: Military flights and vessels (including foreign-military presence); aviation disruptions (closures, severe/major/moderate delays); GPS jamming (high/medium intensity)
- Calculation:
calcSecurityScore(lines 946-964) awards points for flight count (max 50) and vessel count (max 30), adds an aviation-disruption score (max 40), and a GPS-jamming score (max 35). The sum is capped at 100. - Source file: [
src/services/country-instability.ts](https://github.com/koala73/worldmonitor/blob/main/src/services/country-instability.ts#L946-L964)
Information Component
The Information score quantifies narrative velocity and alert status through news metadata.
- Primary signals: News events (count, velocity, alert flag)
- Calculation:
calcInformationScore(lines 966-989) scales raw news-event count by a country-specific multiplier, adds a velocity-based boost, and adds a flat boost if any news is flagged as an alert. Capped at 100. - Source file: [
src/services/country-instability.ts](https://github.com/koala73/worldmonitor/blob/main/src/services/country-instability.ts#L966-L989)
Component Weighting and Base Score Calculation
Inside calculateCII, the four component scores are multiplied by fixed percentages to produce the event score. This weighting reflects the algorithm's emphasis on Conflict (30%) as the primary instability driver, with Unrest and Information equally weighted (25% each), and Security comprising the remaining 20%.
const eventScore =
components.unrest * 0.25 + // 25%
components.conflict * 0.30 + // 30%
components.security * 0.20 + // 20%
components.information * 0.25; // 25%
Source: calculateCII lines 1029-1030
Dynamic Boosts and Risk Modifiers
After computing the base event score, the algorithm applies a series of dynamic boosts that reflect real-time risk factors not captured by the core components. These modifiers are summed and added to the blended score.
-
Hot-spot Activity: Proximity to intel hotspots, conflict zones, and strategic waterways adds up to 10 points (
Math.min(10, activity * 1.5)). Source:getHotspotBoostlines 885-888 -
News Urgency: High information scores trigger urgency boosts—+5 if the Information component is ≥70, or +3 if ≥50. Source:
calculateCIIlines 1032-1034 -
Focal-point Urgency: Real-time critical event detection adds +8 for critical urgency or +4 for elevated status. Source:
calculateCIIlines 1035-1038 -
Displacement: Refugee and asylum outflows add +8 for flows ≥1 million or +4 for flows ≥100,000. Source:
calculateCIIlines 1040-1042 -
Climate Stress: Direct addition of the climate-anomaly stress score (0-15). Source:
calculateCIIline 1043 -
OREF Blend: Israeli OREF alerts contribute
15 + min(25, alertCount * 5), yielding a range of 15-40 points when alerts are present. Source:getOrefBlendBoostlines 1024-1026 -
Travel Advisory: Government advisories add +15 for do-not-travel, +10 for reconsider, and +5 for caution, plus an additional +5 when three or more sources agree. Source:
getAdvisoryBoostlines 66-76 -
Supplemental Signals: AIS disruptions (≤10), satellite fires (≤8), cyber threats (≤12), and temporal anomalies (≤6) combine for up to 36 additional points. Source:
getSupplementalSignalBoostlines 86-102
The blended score formula combines the baseline risk, event score, and all dynamic boosts:
const blendedScore =
baselineRisk * 0.4 + eventScore * 0.6 +
hotspotBoost + newsUrgencyBoost + focalBoost +
displacementBoost + climateBoost +
getOrefBlendBoost(code, data) +
advisoryBoost + supplementalSignalBoost;
Source: blendedScore calculation lines 1047-1048
Risk Floors and Final Score Enforcement
After calculating the blended score, the algorithm enforces minimum risk floors based on authoritative conflict datasets and travel advisories. The final score is the maximum of the blended score or the applicable floor, capped at 100.
UCDP Conflict Floor
The Uppsala Conflict Data Program (UCDP) status provides a hard floor when active conflict is documented:
- War status: Floor of 70
- Minor conflict: Floor of 50
Implementation: getUcdpFloor lines 363-368
Travel Advisory Floor
Government travel advisories enforce additional minimums:
- Do-not-travel: Floor of 60
- Reconsider travel: Floor of 50
Implementation: getAdvisoryFloor lines 79-83
Final Calculation
const finalScore = Math.min(100, Math.max(ucdpFloor, advisoryFloor, blendedScore));
Source: Final score logic lines 1049-1051
Summary
- The country instability index aggregates signals across four components: Unrest (protests, outages), Conflict (ACLED violence, strikes), Security (military activity, GPS jamming), and Information (news velocity).
- Weighting: Conflict receives the highest weight (30%), followed by Unrest and Information (25% each), and Security (20%).
- Dynamic boosts add real-time risk factors including hotspot proximity (up to +10), displacement (+4 to +8), climate stress (+0 to +15), OREF alerts (+15 to +40), and supplemental signals (up to +36).
- Risk floors enforce minimums based on UCDP conflict status (50 or 70) and travel advisories (50 or 60), ensuring the final score reflects documented high-risk conditions.
Frequently Asked Questions
What data sources feed the Country Instability Index?
The index ingests dozens of signal streams including ACLED conflict events, UCDP conflict status, social unrest and protest data, military flight and vessel tracking, internet outage reports, GPS jamming incidents, aviation disruptions, satellite fire detection, AIS maritime disruptions, cyber threat intelligence, refugee displacement figures, climate anomaly stress scores, Israeli OREF alerts, and government travel advisories.
How does the algorithm handle missing data for a specific country?
When primary conflict data is absent, the algorithm employs fallback mechanisms. For the Conflict component, calcConflictScore uses UCDP status as a fallback (HAPI integration), and if both ACLED and UCDP are missing, it applies a news-based floor to ensure the score does not underrepresent documented violence. Similarly, the Unrest component uses country-specific multipliers to normalize protest counts when historical baselines vary.
Why does the Conflict component have a higher weight than Security?
The Conflict component receives a 30% weight compared to Security's 20% because kinetic violence (battles, explosions, civilian targeting) is the primary driver of country instability in the model's design. The algorithm prioritizes active warfare and organized violence over military mobilization signals (Security), which may indicate preparation rather than active destabilization. This weighting is hardcoded in calculateCII at lines 1029-1030.
What prevents the CII score from dropping too low during active conflicts?
The algorithm enforces risk floors that override low blended scores when authoritative sources document active conflict. The UCDP floor sets a minimum of 50 for minor conflicts and 70 for wars, while the travel advisory floor sets minimums of 50 (reconsider) or 60 (do-not-travel). The final score is calculated as Math.max(ucdpFloor, advisoryFloor, blendedScore), ensuring that documented high-risk conditions maintain elevated index values regardless of other mitigating signals.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →