- The famous “grow now, clean up later” curve (the Environmental Kuznets Curve) is not in the data — it's an illusion created by comparing rich countries to poor ones.
- Growth still buys carbon: every 1% of GDP growth brings ~0.5–0.7% more CO₂ — a tighter link than in the 1990s.
- What changed is everything around growth: at zero growth, emissions now fall ~1%/yr globally and ~2.7%/yr in rich countries. Technology and energy mix are doing the cleanup — not income.
Five stages, one honest answer
Everything below is reproducible: each stage is a runnable script that reads only the previous stage's outputs. Together they go from “nothing but an API” to a defended finding.
build_panel.pyeda.pytopic_models.pyekc_pipeline/stakeholder_stress_tests.pyThe central question is an old and famous one in economics: the Environmental Kuznets Curve (EKC) says that as countries get richer, pollution first rises, then peaks, then falls on its own — an upside-down U. If true, growth eventually cleans up after itself. This project tests whether that promise actually exists in 30 years of data for every country on Earth — and finds something more interesting instead.
Building a world in a table
The foundation is a country-year panel: one row per country per year, one column per indicator — 38 indicators × 217 economies × 1995–2024. Everything comes from the World Bank API (the only source with genuinely global coverage), grouped into seven families: economy, governance, trade & investment, inequality, human capital, tech/AI proxies, and energy & pollution.
Why a panel and not a snapshot? A single year can only compare rich countries to poor ones. A panel lets you watch the same country change over time — and that distinction turns out to be the entire story of this project (see section 06).
The fetcher caches every API response and throttles between calls (firing ~35 requests back-to-back turned out to trip spurious errors from the API). Three indicator codes had silently died upstream and had to be hunted down: the governance codes were retired and re-published under a new prefix, the total-CO2 series was archived, and the clean-cooking code had changed. Data engineering is mostly this: the glamorous work of noticing what quietly broke.
Engineered features
On top of the raw indicators, the pipeline builds what models actually consume: log transforms (income and population are wildly skewed — Luxembourg vs. Burundi is a factor of 125), per-country growth rates and one-year lags (so “past” can predict “future” without cheating), a carbon-intensity ratio (CO₂ per $1,000 of GDP), and a time trend. One built-in integrity check: the growth rate computed from the data correlates 0.96 with the World Bank's own published growth series — the panel is internally consistent.
Trust, but verify
Before modeling anything, the data got interrogated — a dedicated quality pass that treats every suspicious number as guilty until proven innocent. Three kinds of problems surfaced — each with a fix that later analyses depend on:
🚫 Impossible values
Lithuania's fossil-fuel share reading −61%? Central African Republic's life expectancy dropping to 14.7 years for exactly one year, flanked by ~48 on both sides? Those are upstream artifacts, not history — 9 observations dropped, with a check first that other negative values (São Tomé's savings rate, Sierra Leone's 1997 investment) were real economics and must be kept.
🏝️ Micro-states
57 of 217 entities have under a million people. Micronesia reports 0.002 tonnes of CO₂ per person — implausible bookkeeping, not virtue. They stay in the dataset but carry a flag, and every model excludes them.
⚖️ The selection trap
Requiring complete data on all 38 indicators leaves just 75 countries — 40 high-income and exactly 1 low-income. Model that and you've built a rich-country model wearing a “world” costume. The honest modeling core: 120 countries, 2000–2022.
Why the selection trap matters: imagine polling “the world” but only counting people who answer on the first ring. You'd learn a lot about people who sit near their phones — and nothing about the world. Requiring perfect data does the same thing: it silently selects rich countries, because they're the ones with complete statistics.
What 30 years of world data actually says
Before choosing a model, you earn the right to model — by checking the data against things you already know are true.
The reality checks passed. Poorer countries grew faster than rich ones on average (the classic “convergence” pattern, slope −0.0047). Countries with better governance are richer (correlation 0.83 with government effectiveness — a textbook institutions result). And the biggest movers are exactly who history says they should be: Guyana +897% (offshore oil), China +749%, and Syria −40% (civil war).
Just as important, the EDA mapped what the data cannot support: the governance indicators are structurally missing in 1997/1999/2001 (the survey was biennial back then — interpolating across that gap would fabricate data), and inequality (Gini) never covers more than half the world in any single year. Every later model respects these boundaries.
The original chart code picked its “snapshot year” by checking only 3 hardcoded indicators — and silently produced blank panels for 6 others whose data lags a year or two. The fix requires 90% of all indicators to have coverage before a year qualifies. Lesson: charts fail silently; coverage checks shouldn't.
Four candidates, one winner
Rather than guess, all four candidates were run as real fixed-effects panel regressions first — then judged on both rigor and story:
Tech diffusion → growth
Does internet adoption (the best global AI-proxy that exists) predict growth? Answer: not significantly (p=0.46) once you control for the obvious. An honest null.
HONEST NULLPollution & the EKC
A quick grounding check found the famous inverted-U looks upside down in raw data — dominated by petrostates like Qatar (46 t CO₂/person). A textbook result that's fragile? That's a story.
CHOSEN ★Conditional convergence
Poor countries grow faster even after controls (−0.051, p<0.001). Solid, but it's a well-told textbook tale.
SOLIDThe digital divide
Internet access dispersion across countries widened until 2013, then began narrowing. Nice descriptive arc, limited depth.
DESCRIPTIVEThe first decoupling regression included both year fixed effects and a linear time trend — but year effects absorb anything that's the same for all countries in a year, which a time trend is. The leftover collinearity produced coefficients claiming emissions intensity was rising, flatly contradicting the raw data (0.30 → 0.16 t/$1000 over the sample). One line of thought — “does this number even match the data I can see?” — caught it.
Killing a textbook curve, carefully
The one idea you need: there are two ways to ask “does getting richer eventually cut pollution?” You can compare different countries (Qatar vs. Ethiopia — rich ones just emit more), or you can watch the same country over 30 years as it grows. The first is called a cross-section; the second is what “fixed effects” unlock. The textbook EKC comes from the first kind of comparison. The truth requires the second.
The specification ladder
Five models, each one step stricter. Watch the curvature coefficient — the number that decides whether the inverted-U exists (a negative value means inverted-U; positive means the opposite):
| Model (stricter ⭣) | Comparison type | Curvature | Verdict |
|---|---|---|---|
| 1 · Pooled quadratic (“textbook”) | Across countries | +1.324 *** | U-shape — wrong direction! |
| 2 · + country fixed effects | Within countries | −0.122 n.s. | Curve vanishes |
| 3 · + year fixed effects | Within, minus global shocks | −0.034 n.s. | Still nothing |
| 4 · + controls (energy mix, trade, urbanization…) | Within, adjusted | +0.478 *** | Significantly convex |
| 5 · + governance interaction | Within, adjusted | +0.503 *** | Same |
No specification produces the inverted-U. The famous curve appears only when you compare rich countries to poor ones — it is a statement about who emits, not about what happens when a country grows.
Is there a turning point at all?
The EKC's promise hinges on a peak — an income level where emissions start falling. To test whether one exists, the analysis was re-run 500 times on random re-samples of countries (a “block bootstrap”). If the peak were real, it should show up again and again.
Inference uses Driscoll-Kraay standard errors because the residual diagnostics demanded them: serial correlation (ρ = 0.76) and cross-sectional dependence (Pesaran CD = 4.78, p<0.001 — emission shocks like oil prices and recessions hit many countries at once, and error bars that ignore this are overconfident). Clustered SEs are reported side-by-side; every conclusion survives both. Robustness battery: petrostate exclusion, two alternative dependent variables, split time periods, alternative governance measure — the no-inverted-U result survives all of them.
The day a “great” model lost to doing nothing
The pipeline validated its models on held-out years: train on 1996–2018, predict 2019–2024. First results looked spectacular — the structural model explained 97% of out-of-sample variation in emission levels, edging out a tuned gradient-boosting model. Time to celebrate?
The weather-forecast test: predicting tomorrow's weather with “same as today” sounds dumb — and beats most forecasting systems. Emissions are like that: a country's CO₂ this year is almost exactly last year's (correlation 0.996). So the review added the dumbest possible baseline: carry each country's last known value forward, unchanged.
| Task 1 — predict emission levels | RMSE | R² |
|---|---|---|
| 🪨 Naive “no change” baseline | 0.901 | 0.977 WINNER |
| Structural econometric model | 1.008 | 0.971 |
| Tuned gradient boosting (ML) | 1.097 | 0.966 |
The rock beat both models. That impressive 97% was persistence, not skill — and a validation section bragging about it would have been (unintentionally) lying. So the task was reframed around what is actually hard: predicting the change in emissions, where “no change” scores zero by construction.
| Task 2 — predict emission changes | RMSE | R² |
|---|---|---|
| Naive “zero change” baseline | 0.645 | −0.005 |
| Structural differenced model | 0.581 | 0.184 WINNER |
| Gradient boosting (same features, tuned fairly) | 0.606 | 0.115 |
On the hard task, the simple, theory-shaped model beat the flexible black box — with GDP change as the dominant driver. In a small, noisy dataset, structure is information.
Mid-review, the structural model briefly scored R² = −31 (catastrophically worse than guessing). Cause: a one-line data-alignment bug — reindexing the test matrix before adding the intercept column filled the intercept with zeros, silently deleting the model's baseline. Germany was being predicted at 0.25 tonnes instead of ~8. Fixed, the same model scored 0.971. Two lessons: investigate absurd numbers in both directions, and never trust a pipeline you haven't tried to break.
The review also made the comparison fair before declaring a winner: the gradient-boosting model gets raw features (trees find curvature themselves — hand-feeding it the squared term had inflated its importance scores), hyperparameters tuned on an inner temporal fold (no peeking at test years), and importances measured by held-out permutation rather than the biased impurity method. Structure won anyway.
Attack your own work before the audience does
Every claim got stress-tested with the toughest objection first. Click each one — the answers are quantified, not hand-waved:
Q1 “Your prediction win is just COVID, isn't it?”
Largely yes — and that's the finding. In calm years, annual emission changes are close to noise (R² ≈ 0.015). In 2020–21, when GDP moved violently, the model scored 0.267 while the naive baseline collapsed to −0.45. The model earns its keep exactly when growth moves — which is out-of-sample proof that the growth–emissions link is real and live. The per-year breakdown is published in the brief, including the thin post-2021 rows (n≤7), flagged before anyone else could.
Q2 “Same-year predictors aren't a real forecast.”
Correct — conceded with numbers. Using only lagged information, test R² drops to 0.01: next year's emission change is essentially unforecastable. The model is attribution (“given the growth that happened, how much did emissions move?”), and its GDP coefficient — the marginal coupling — is the quantity the final finding is built on. No crystal-ball claims anywhere.
Q3 “Petrostates create your U-shape.”
They amplify it; they don't create it. Dropping all 8 major oil-and-gas outliers (Qatar, Kuwait, UAE…), the pooled curvature stays positive and significant (+0.65, p<0.001). Still no inverted-U, with or without them.
Q4 “Intensity decoupling is a ratio trick — absolute emissions are what the atmosphere sees.”
Agreed, so absolute per-person emissions were tested directly: falling in high-income countries (−0.070 t/yr, p<0.001 — real absolute decline), but still rising in upper-middle-income countries (+0.038 t/yr, p<0.01). Absolute decoupling exists — so far as a rich-country phenomenon.
Q5 “Maybe you just lack power to detect the EKC within countries.”
Partly fair — only 3.2% of CO₂ variance is within-country, and that's flagged. But the within-country estimate isn't a shrug: with controls it's significantly convex (+0.48, p<0.001), the opposite shape — and the elasticity analysis extracts precise estimates from that same within-country variation. The data can speak; what it says is “no inverted-U.”
Q6 “Driscoll-Kraay standard errors with only ~29 years?”
Both standard-error families are published side by side. Point estimates are identical; every conclusion survives under country-clustered SEs too. The fixed-effects choice rests on the Mundlak test (p=0.001), not on the classic Hausman — which degenerates on this panel and is reported as degenerate rather than quietly swapped.
Q7 “A rising elasticity contradicts your own decoupling claim.”
No — they're the two different margins of one regression. The slope (how emissions respond to growth swings) rose; the intercept (the baseline drift when growth is zero) fell. Both moved, in opposite directions, both p<0.001. That tension isn't a contradiction; it's the headline.
Q8 “None of this is causal.”
Stated on every output. These are conditional associations with fixed effects and robust inference; no valid instrument exists here. The policy-relevant claim — that observed declines come from the drift, not from an income turning point — is about where the variation lives, and stands at the descriptive level at which it's made.
Two-speed decarbonization
The red team didn't just defend the work — it surfaced the best result of the project. Split every country's annual emission change into two parts: the part that moves with the economy, and the part that happens regardless of it.
Think of emissions as a car on a hill. The engine — economic growth — pushes emissions up as hard as it ever did (harder, actually). What changed is the hill: renewables, efficiency, and the shifting energy mix now slope the road downward, so the car drifts backwards ~1% a year whenever the engine idles — and in rich countries, ~2.7% a year. The Kuznets curve promised the engine itself would eventually go green. It hasn't. The road did.
Worked examples — what these numbers mean
| Period | Coupling (CO₂ % per 1% GDP growth) | Drift at zero growth (%/yr) |
|---|---|---|
| 1996–2005 | 0.32 *** | +0.84 |
| 2006–2015 | 0.64 *** | −0.18 |
| 2016–2024 | 0.72 *** (0.53 ex-COVID) | −0.95 (−0.72 ex-COVID) |
The thesis, in one paragraph
The Environmental Kuznets Curve — the promise that growth eventually cleans up after itself — is not in this data. Its inverted-U is a cross-sectional artifact that flips sign under within-country fixed effects and never yields an identifiable turning point. What is in the data is two-speed decarbonization: every 1% of GDP growth still brings ~0.5–0.7% more CO₂ — tighter coupling than in the 1990s — while the zero-growth baseline swung from +0.8%/yr to −1%/yr globally, and −2.7%/yr in rich countries. Decarbonization is happening around growth — through the energy mix — not through it. Waiting for an income turning point is not a climate strategy. The drift — technology and energy policy — is where the leverage is.
Observational associations throughout — no instrument, no causal claims. Turning-point estimates are functional-form sensitive. Governance data has a structural 1997–2001 gap; post-2021 test coverage is thin. Falling carbon intensity is not sufficiency: absolute emissions still rise wherever growth outruns the drift (as it does in upper-middle-income countries). Results describe the ~150 larger economies; micro-states excluded.
100% AI-built — the human only prompted
Every artifact in this project — the data pipeline, the audit, four topic models, the EKC pipeline, the red team, the reports, and this page — was written by Claude. The human contribution was direction, not code: a handful of plain-English prompts, no manual editing of the analysis. What made the result trustworthy wasn't any single clever instruction — it was steering the AI through rotating adversarial roles, where each new role attacked the previous one's blind spots.
Three of the actual prompts, exactly as typed — one per act:
The full prompt playbook — how the data-quality pass was framed, how the four topics were scoped and one selected, how the model build and the defense were sequenced — is deliberately not published. The method above (builder → auditor → reviewer → red team) is free to steal; the exact recipe stays in the kitchen. Adversarial process, not any single clever prompt, is what made the final answer trustworthy.
Run the whole thing
All source code ships in this folder. Five scripts, in order — the first one rebuilds the raw panel (~17MB, not shipped) straight from the World Bank's public API, caching responses so re-runs are fast and polite to their servers:
pip install -r requirements.txt cd notebooks python build_panel.py # 1. fetch + clean + engineer → output/panel_*.csv python eda.py # 2. explore → output/eda/ python topic_models.py # 3. four topic regressions → output/models/ python run_ekc_pipeline.py # 4. the EKC pipeline → output/ekc/ python stakeholder_stress_tests.py # 5. red team + star result → output/ekc/stress/
Key documents in this folder: FINAL_SUMMARY.md (the
full technical narrative), EKC_REPORT.md
(the model report), and
STAKEHOLDER_BRIEF.md (the
8-question defense). Every number on this page traces to one of the 60+ published artifacts.