Projects / Featured
QGI
Quantitative Geopolitical Intelligence: a solo-built platform that reads six decades of national indicators to find countries tracing the trajectories that preceded past crises.
An applied-machine-learning platform that reads six decades of national indicators to find countries tracing the same trajectories that preceded past crises, and surfaces the real historical precedents behind every signal.
Status: research prototype; models and recipes under academic review. QGI reports how strongly a country resembles historical precedents, ranked, evidenced, with the uncertainty stated, rather than issuing probabilistic forecasts.
QGI is a solo-built, seven-repository system running on a multi-account AWS backbone, live at qgintelligence.com. Its current methodology is the Trajectory Engine: a fleet of per-event-type models, each learning which indicators matter, over what horizon, and how closely a country today resembles the historical cases behind that event type. A separate statistical scoring layer, older than the fleet and unrelated to the retired recipes, still contributes country scores alongside it. The platform's original engine, the Classic Cascade, a pure-statistics correlation pipeline that mined cross-country indicator correlations into event recipes, is retired: it no longer feeds the live pipeline, and is described below for its own engineering history rather than as part of the current system.
Methodology
Two generations, one platform
QGI has been built twice. Pick a generation to see how it was engineered; only the Trajectory Engine is live.
Trajectory Engine: the ML layer
Each recipe becomes its own model, architecture chosen by how much positive-class data it has: a regularised logistic regression when positives are thin, XGBoost once there are enough. A univariate pre-filter narrows the indicator catalogue to the handful that carry signal for that event type, then a greedy search selects the final set and the horizon over which the pattern plays out, cross-validated throughout, leave-one-country-out, with bias-corrected bootstrap confidence intervals, so a model is never scored on a country it trained on. Across the fleet, that validation discipline is the point, not a single number: median out-of-fold AUC is 0.633 (range 0.535–0.741), a modest but real early-warning signal. Surviving models rank today's countries by resemblance to the historical precedents, never a probability.
The current modelling generation: a fleet of per-event-type models on the current indicator catalogue. A separate statistical scoring layer, older than the fleet, still contributes country scores alongside it.
-
1 · Ingest
- Amazon S3
- Parquet
- 250 indicators · 8 providers
- World Bank · V-Dem · UCDP · FAOSTAT
- UNHCR · ILOSTAT · OWID · UNDP
- over 10,000 verified events
- 71 categories · 1903–2026
-
2 · Feature store
- Amazon S3
- AWS Glue
- Athena
- Columnar feature store
- Glue-catalogued, queried in SQL
- Curated event labels
-
3 · Orchestration
- Step Functions
- AWS Batch
- DynamoDB
- Map state, one run per recipe
- Graviton Spot · c7g / m7g
- Python 3.13 · arm64
- Coordination counters
-
4 · Model fleet
- AWS Batch
- Amazon S3
- XGBoost
- scikit-learn
- 42 models, one per event type
- logistic regression or XGBoost
- per-recipe models written to S3
Gates
- coverage gate
- chance gate
- 7-confound battery
-
5 · Publish
- Amazon S3
- Vercel
- Next.js
- baked static JSON
- qgintelligence.com
Also scoring
- a separate statistical layer
- older than the fleet, still contributes country scores
Multi-account AWS org · eu-central-1 · Terraform per-environment state · GitHub Actions OIDC, no long-lived credentials
- Recipe + Labels
-
1
Feature Substrate
-
Feature Substrate
250 macro indicators across 8 providers (World Bank, V-Dem, UCDP, FAOSTAT, UNHCR, ILOSTAT, OWID, UNDP) as a shared columnar feature store, plus curated and verified event labels (positives).
-
- indicators + labels
-
2
Per-Recipe Walk F-ML-1
-
Univariate Pre-filter
Ranks 250 indicators by leave-one-country-out signal and keeps the top 40, capping the expensive search so the indicator pool can grow without exploding compute.
-
Indicator Selection + Window Search
Greedy forward selection over indicators, jointly searching the canonical horizon {3 … 25 years}; a candidate joins the recipe only if it lifts held-out AUC.
-
Train + Leave-One-Country-Out AUC
XGBoost per recipe (logistic fallback for sparse classes), scored by leave-one-country-out cross-validation so no country is ever evaluated on itself.
-
Clears the LOCO-AUC floor?
clears floor below floor
-
- canonical shape + indicator weights
-
3
Similarity-as-Risk Scoring
-
Similarity-as-Risk Scoring
Each country's recent trajectory is compared with the recipe's precedent pattern and reported as a 0–100 resemblance score with a confidence band.
-
- 0–100 resemblance + precedents
-
4
Recipe-Fleet · AWS Batch
-
Parallel Fleet Fan-Out
A canary-gated Step Functions Map fans every runnable recipe across right-sized 2-vCPU Graviton Spot instances (c7g / m7g), writing per-recipe models back to S3, a full fleet run costs a few dollars.
-
- Trend Tracker · live
Resemblance ranks, not probabilities · leak-guarded (leave-one-country-out) · research prototype & under academic review
Classic Cascade: the original statistical core
QGI's first generation, and a pure-statistics pipeline: for every pair of countries and every indicator it computed time-shifted Pearson correlations (SCDIs), aggregated them into multi-indicator Patterns, and bound those to real historical events to form Recipes, reusable fingerprints of what tended to precede a given kind of crisis, on the order of billions of correlations per run. It is retired: the live product no longer runs on it, and its recipes do not feed the current Trajectory Engine, which was built as a separate, per-event-type model fleet on top of the platform's much larger current indicator catalogue.
History. QGI's original statistical core, retired: it no longer feeds the live pipeline.
-
1 · Ingest
- AWS Lambda
- Amazon S3
- Janitor · Indicator Fetcher
- World Bank · V-Dem · FAOSTAT
- the 109-indicator vintage
- Parquet on S3
-
2 · Orchestration
- Step Functions
- Amazon SQS
- AWS Lambda
- Dispatcher fan-out
- Asynchronous polling, no idle compute
- Dead-letter queue scanner
-
3 · SCDI compute
- AWS Batch
- Amazon S3
- Graviton Spot workers
- time-shifted Pearson correlations
- 14.3 billion SCDI rows
-
4 · Catalogue
- AWS Glue
- Athena
- Crawler over the lake
- Partition repair, then SQL
- 2.01 billion pattern rows
-
5 · Synthesis
- AWS Batch
- AWS Lambda
- Patterns
- Recipes
- Ops report
Its recipes do not feed the model fleet · the data lake it produced is still real
- Indicator series
-
1
Hygiene
-
Janitor
Removes stale intermediate data before each run.
-
- clean slate
-
2
Ingest
-
Indicator Fetcher
Pulls macro indicators (World Bank, V-Dem, FAOSTAT) into Parquet on S3.
-
Dispatcher A
Fans out one Fargate Spot task per indicator, then Step Functions waits on the fleet asynchronously rather than holding compute open.
-
Reporter
Tallies which indicators were updated and emits the set the rest of the run works from.
-
- updated indicators
-
3
SCDI Compute · AWS Batch
-
Batch Orchestrator
Submits Pearson cross-correlation jobs across all country pairs to Graviton Spot instances, on the order of billions of correlations per run.
-
Batch Checker
Polls the job queue asynchronously, so no compute sits idle while the fleet works.
-
- SCDI rows on S3
-
4
Discovery · Glue Crawler
-
Partition Finder
Crawls the lake to auto-discover the new Parquet partitions the compute phase wrote, then reports back when the catalogue is ready.
-
- catalogued partitions
-
5
Synthesis · Patterns & Recipes
-
Dispatcher C
Fans out workers via SQS to aggregate SCDIs into multi-indicator Patterns, then binds them to historical events as Recipes.
-
Repair Table
Registers the new Parquet partitions so the Patterns table is queryable in SQL.
-
- patterns + recipes
-
6
Ops Report
-
DLQ Scanner
Surfaces failed messages and unprocessed items and produces the final health report. Also the landing point when the ingest phase finds no updates.
-
- Ops report
Serverless throughout · Step Functions polls asynchronously, so nothing holds compute open between phases
Validation & Integrity
Every model in the fleet is tested the same way: leave-one-country-out cross-validation, so a model is never scored on a country it trained on, with bias-corrected bootstrap confidence intervals, time-matched negative sampling, and three-cohort stratification. Before a recipe is even attempted it has to clear a coverage gate (enough positives, enough negatives, enough surviving positives across enough countries) and a chance gate (its bootstrap confidence interval has to clear 0.50), then it is stress-tested against a battery of seven confounds designed to catch the platform's own false positives. Pre-registered falsification criteria and a forbidden-actions list were written before any model was trained.
An early result reported an AUC of 0.9147, computed on 10 of 174 positive cases. It was wrong: recomputed on the full set, it corrected to about 0.4967, no better than random guessing. The claim was retracted publicly, and the one recipe that had briefly graduated was reset. A fleet-wide audit then re-measured all 42 models under the same protocol; median out-of-fold AUC is 0.633, described above.