feat(variant): Energy Atlas — Release 1 Day 1 (variant scaffolding)#3291
Conversation
….app Release 1 Day 1 of the Energy Atlas plan — introduces src/config/variants/energy.ts modeled on the commodity variant. No new panels or RPCs yet; the variant reuses existing energy-related panels (energy-complex, oil-inventories, hormuz, energy-crisis, fuel-prices, renewable-energy) + supply-chain/sanctions context. Map layers enable pipelines, waterways, AIS, commodityPorts, minerals, climate, outages, natural, weather. All geopolitical/military/tech/finance/happy variant layers explicitly disabled per variant isolation conventions. Next PRs on feat/energy-atlas-release-1 add: - Pipeline & storage registries (curated critical assets, ~75 gas / ~75 oil / ~125 storage) - Global fuel-shortage registry with automated evidence-threshold promotion - Pipeline/storage disruption event log - Country drill-down Energy section - Atlas landing composition at variant root
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…sition
Day 2 of the Energy Atlas Release 1 plan. The Day-1 commit added a canonical
variants/energy.ts but discovery during Day 2 showed the app's runtime variant
resolution lives in src/config/panels.ts (ENERGY_PANELS/ENERGY_MAP_LAYERS/etc.),
not in variants/*.ts (which are orphans). This commit does the real wiring.
Changes:
- src/config/panels.ts — ENERGY_PANELS, ENERGY_MAP_LAYERS, ENERGY_MOBILE_MAP_LAYERS;
registered in ALL_PANELS, VARIANT_DEFAULTS, VARIANT_PANEL_OVERRIDES; wired into
DEFAULT_MAP_LAYERS + MOBILE_DEFAULT_MAP_LAYERS ternaries. Panels at launch:
map, live-news, insights, energy-complex, oil-inventories, hormuz, energy-crisis,
fuel-prices, renewable-energy, commodities, energy (news), macro-signals,
supply-chain, sanctions-pressure, gulf-economies, gcc-investments, climate,
monitors, world-clock, latest-brief.
- src/config/variant.ts — recognize 'energy' as allowed SITE_VARIANT; resolve
energy.worldmonitor.app subdomain to 'energy'; honor localStorage override.
- src/config/variant-meta.ts — SEO entry for energy.worldmonitor.app (title,
description, keywords targeting 'oil pipeline tracker', 'gas storage map',
'fuel shortage tracker', 'chokepoint monitor', etc.).
- src/app/panel-layout.ts — desktop variant switcher + mobile menu both list
energy with ⚡ icon and t('header.energy') label.
- src/App.ts + src/app/data-loader.ts — energy variant enables trade-policy and
supply-chain data loads (chokepoint exposure is a core Atlas surface).
- src/app/data-loader.ts — daily-brief newsCategories override for energy variant
(energy, energy-markets, oil-gas-news, pipeline-news, lng-news).
- src/locales/en.json — 'header.energy' translation key.
- src/config/variants/energy.ts — add clarifying comment that real wiring lives
in panels.ts (same orphan pattern as commodity.ts/finance.ts/etc.).
Atlas landing composition: the variant now renders its energy panel set with
energy-specific names (Energy Atlas Map, Energy Headlines, AI Energy Insights)
when SITE_VARIANT === 'energy'. Pipeline and commodity-port map layers enabled
so Week 2's pipeline registry + storage-facility registry drop in with layers
already toggled on.
Typecheck clean; 175 pre-push tests expected to remain green.
Subsequent PRs on feat/energy-atlas-release-1:
- Week 2: pipeline registry + storage facility registry (evidence-based)
- Week 3: fuel-shortage classifier + disruption log + country drill-down
- Week 4: automated revision log, SEO polish, launch
Day 3 of the Energy Atlas Release 1 plan. Adds ChokepointStripPanel — a compact horizontal strip of chip-style cards, one per chokepoint, showing name + status color + flow-as-%-of-baseline + active-warnings badge. Ordered by volume: Hormuz, Malacca, Suez, Bab el-Mandeb, Turkish Straits, Danish Straits, Panama. GEF covers 5 chokepoints (Hormuz, Malacca, Suez, Bab el-Mandeb, Panama). We cover 7 — adds Turkish Straits + Danish Straits. One of the surpass vectors enumerated in §5.7 of the plan doc. Data: reuses the existing fetchChokepointStatus() RPC backed by supply_chain:chokepoints:v4 (Portwatch DWT + AIS calibration). No new backend work; this is pure UI composition. Changes: - src/components/ChokepointStripPanel.ts — new Panel subclass with in-line CSS for the chip strip; falls back gracefully when a chokepoint is missing from the response or FlowEstimate is absent. - src/components/index.ts — barrel export. - src/app/panel-layout.ts — import + createPanel registration near existing energy panels. - src/config/panels.ts — ENERGY_PANELS adds 'chokepoint-strip' at priority 1 (renders near top of atlas). Also fixes two panel-ID mismatches caught while wiring: 'hormuz' → 'hormuz-tracker' and 'renewable-energy' → 'renewable' (matches HormuzPanel.ts and RenewableEnergyPanel registration). Typecheck clean. No new tests required — panel renders real data.
Days 4 & 5 of the Energy Atlas Release 1 plan.
## Day 4 — Attribution footer (src/utils/attribution-footer.ts)
A reusable string-builder that stamps every energy-atlas number with its
provenance. Design intent per plan §5.6 (quantitative rigour moat):
"every flow number carries {value, baseline, n_vessels, methodology,
confidence}".
Input schema:
- sourceType: operator | regulator | ais | satellite | press | classifier | derived
- method: short free-text ("AIS-DWT calibrated", "GIE AGSI+ daily")
- sampleSize + sampleLabel: observation count and unit
- updatedAt: ISO8601 / Date / number — rendered as "Xm/h/d ago"
- confidence: 0..1 — bucketed to high/medium/low
- classifierVersion: surfaced when evidence-derived badges ship in Week 2+
- creditName / creditUrl: CC-BY / dataset credit (OWID, GEM pattern)
Every field also writes data-attributes (data-attr-source, data-attr-n,
data-attr-confidence, data-attr-classifier) so MCP / scraper / analyst
agents can extract the same provenance the reader sees. Agent-native by
default.
Applied to ChokepointStripPanel — the panel now shows its evidence
footer ("AIS calibration · Portwatch DWT + AIS · N AIS disruption
signals · updated Xh ago · EIA World Oil Transit Chokepoints").
Future pipeline / storage / shortage panels drop the same helper in
and hit the same rigour bar automatically.
7 unit tests (tests/attribution-footer.test.mts, node:test via tsx):
minimal footer, method + sample size + credit, "X ago" formatting,
confidence band mapping, full data-attribute emission, credit omission,
HTML escaping.
## Day 5 — Public methodology page stubs (docs/methodology/)
Four new MDX pages surfaced in docs/docs.json navigation under
"Intelligence & Analysis":
- chokepoints.mdx — 7 chokepoints, Portwatch+AIS calibration method,
status badge derivation, known limits, revision-log link.
- pipelines.mdx — curated critical-asset scope, GEM CC-BY attribution,
evidence-schema (NOT conclusion labels), freshness SLA, corrections.
- storage.mdx — curated ~125 facilities scope, "published not
synthesized" fill % policy, country-aggregate fallback, attribution.
- shortages.mdx — automated tiered evidence threshold, LLM second-pass
gating, auto-decay cadence, evidence-source transparency, break-glass
override policy (admin-only, off critical path).
All four explicitly document WorldMonitor's automated-data-quality
posture: no human review queues, quality via classifier rigour +
evidence transparency + auto-decay + public revision log.
Typecheck clean. attribution-footer.test.mts passes all 7 tests.
Addresses three High findings from PR review:
1. Map-layer isolation (src/config/map-layer-definitions.ts)
- Add 'energy' to the MapVariant type union.
- Add energy entry to VARIANT_LAYER_ORDER with the curated energy
subset (pipelines, waterways, commodityPorts, commodityHubs, ais,
tradeRoutes, minerals, sanctions, fires, climate, weather, outages,
natural, resilienceScore, dayNight).
Without this, getLayersForVariant() and sanitizeLayersForVariant()
(called from DeckGLMap and App.ts) fell back to VARIANT_LAYER_ORDER.full,
letting the full geopolitical palette (military, nuclear, iranAttacks,
conflicts, hotspots, bases, protests, flights, ucdpEvents,
displacement, gpsJamming, satellites, ciiChoropleth, cables,
datacenters, economic, cyberThreats, spaceports, irradiators,
radiationWatch) into the desktop map tray and saved/URL layer
sanitization — breaking the PR's stated no-geopolitical-bleed goal
and violating multi-variant-site-data-isolation.
2. News feeds (src/config/feeds.ts + src/app/data-loader.ts)
- Add ENERGY_FEEDS with three keys matching ENERGY_PANELS: live-news
(broad energy headlines from OilPrice, Rigzone, Reuters/Bloomberg/FT
energy), energy (OPEC + crude + NatGas/LNG + pipelines/chokepoints
+ crisis/shortages + refineries), supply-chain (tanker/shipping,
chokepoints, energy sanctions, ports/terminals).
- Add SITE_VARIANT === 'energy' branch to the FEEDS variant selector.
- Correct newsCategories override in data-loader.ts — my earlier
speculative values ['energy','energy-markets','oil-gas-news',
'pipeline-news','lng-news'] included keys that did not exist in
any feed map. Replaced with real ENERGY_FEEDS keys ['live-news',
'energy', 'supply-chain'].
Without this, FEEDS resolved to FULL_FEEDS for the energy variant —
live-news + daily-brief both ingested the world/geopolitical feed set.
3. Insights / AI brief framing (src/components/InsightsPanel.ts)
- Add SITE_VARIANT === 'energy' branch to geoContext: dedicated energy
prompt focused on physical supply (pipelines, chokepoints, storage,
days-of-cover, refineries, LNG, sanctions, shortages) with
evidence-grounded attribution, no bare conclusions.
- Add '⚡ ENERGY BRIEF' heading branch in renderWorldBrief().
Without this, the renamed 'AI Energy Insights' panel fell through
to the empty default prompt and rendered 'WORLD BRIEF'.
Typecheck clean. attribution-footer tests still pass (no coupling changed).
Fifth High finding from PR review: src/components/Map.ts createLayerToggles() (line 381-409) has no 'energy' branch in its variant ternary, so energy-variant users whose MapContainer routes to the SVG/mobile fallback (no WebGL, mobile with deviceMemory < 3, or DeckGL init throws) see the full geopolitical toggle set — iranAttacks, conflicts, hotspots, bases, nuclear, irradiators, military, protests, flights, gpsJamming, ciiChoropleth, cables, datacenters. Clicking any toggle flips the layer via toggleLayer() which is variant-blind (Map.ts:3383) — so users could enable military / nuclear layers on the energy variant despite the rest of the isolation work in panels.ts, map-layer-definitions.ts, feeds.ts, and InsightsPanel.ts. Fix: add energyLayers array with the SVG-capable subset of ENERGY_MAP_LAYERS — pipelines, waterways, ais, commodityHubs, minerals, sanctions, outages, natural, weather, fires, economic. Intentionally omitted: commodityPorts, climate, tradeRoutes, resilienceScore, dayNight — none of these have render handlers in Map.ts's SVG path, so including them would create toggles that do nothing. Extended the ternary with 'energy' → energyLayers between 'happy' and the 'full' fallback. Note (preexisting, NOT fixed here): the same ternary has no 'commodity' branch either, so commodity.worldmonitor.app also gets the full geopolitical toggle set on the SVG fallback. Out of scope for this PR; flagged for a separate fix. Defence-in-depth: sanitizeLayersForVariant() (now fixed in map-layer-definitions.ts) strips saved-URL layers to the energy subset before the SVG map sees them, so even if a user arrives with ?layers=military in the URL, it's gone by the time initialState reaches MapComponent. The toggle-list fix closes the UI-path leak; the sanitize fix closes the URL-path leak. Typecheck clean.
Greptile SummaryThis PR scaffolds the
Confidence Score: 4/5Safe to merge after fixing the Dover Strait label; the isolation scaffolding is solid. One P1 finding — a wrong geographic name displayed to users in the atlas's top-priority chokepoint strip. All other findings are P2. The variant isolation work (layer sanitization, SVG fallback fix, hostname routing) is well-executed. src/components/ChokepointStripPanel.ts (wrong chokepoint label), src/config/variants/energy.ts (stale panel IDs in reference file) Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Browser / Tauri] -->|hostname or localStorage| B{SITE_VARIANT resolver\nvariant.ts}
B -->|energy.*| C[SITE_VARIANT = 'energy']
C --> D[panels.ts\nENERGY_PANELS\nENERGY_MAP_LAYERS]
C --> E[map-layer-definitions.ts\nVARIANT_LAYER_ORDER.energy\nsanitizeLayersForVariant]
C --> F[Map.ts createLayerToggles\nenergyLayers SVG fallback]
D --> G[panel-layout.ts\nChokepointStripPanel\nInsightsPanel energy brief]
E --> H[URL ?layers= sanitized\nto energy-allowed set]
F --> I[SVG/mobile map\nno geopolitical toggles]
G --> J[ChokepointStripPanel\nfetchChokepointStatus\nattributionFooterHtml]
|
| suez: 'Suez', | ||
| bab_el_mandeb: 'Bab el-Mandeb', | ||
| bosphorus: 'Turkish Straits', | ||
| dover_strait: 'Danish Straits', |
There was a problem hiding this comment.
Incorrect geographic label for
dover_strait
dover_strait is mapped to 'Danish Straits', but the Strait of Dover (English Channel narrows between SE England and NE France) and the Danish Straits (Øresund/Great Belt/Little Belt connecting the North Sea to the Baltic) are entirely different geographic chokepoints. An Energy Atlas showing the wrong name for a strategic shipping chokepoint is a material data-quality issue.
| dover_strait: 'Danish Straits', | |
| dover_strait: 'Dover Strait', |
| hormuz: { name: 'Strait of Hormuz Tracker', enabled: true, priority: 1 }, | ||
| 'energy-crisis': { name: 'Energy Crisis Policy Tracker', enabled: true, priority: 1 }, | ||
| 'renewable-energy': { name: 'Renewable Energy', enabled: true, priority: 2 }, |
There was a problem hiding this comment.
Reference file already diverges from runtime panel IDs
energy.ts is documented as "modify both if the variant shape changes", but it already uses panel IDs that don't exist at runtime:
'renewable-energy'(line 28) — runtimepanels.tsENERGY_PANELS registers'renewable''hormuz'(line 26) — runtimepanels.tsENERGY_PANELS registers'hormuz-tracker'
Since this file is never imported, there's no compile-time guard to catch drift. A developer following this file as the canonical reference would create or wire panels with the wrong keys, causing silent no-ops. Consider either aligning the IDs here with panels.ts or adding a CI script that asserts key parity between the two files.
Summary
Day 1 of the Energy Atlas Release 1 plan. Introduces the
energyvariant scaffolding so subsequent PRs on this branch can build the pipeline registry, storage registry, shortage classifier, and disruption log against a real variant surface.See the internal plan (not committed — gitignored in
docs/internal/) for the full 4-week schedule, scope, and Release 1 vs Release 2 split.What this PR adds
src/config/variants/energy.ts— new variant config, modeled oncommodity.tsDEFAULT_PANELSenables existing energy-adjacent panels:energy-complex,oil-inventories,hormuz,energy-crisis,fuel-prices,renewable-energy,commodities(WTI/Brent/NatGas),supply-chain(chokepoints),sanctions-pressure,gulf-economies,climate, plusmapandlive-news.DEFAULT_MAP_LAYERSenables pipelines, waterways (chokepoints), AIS (tanker positions), commodityPorts (LNG + crude terminals), minerals (energy-transition overlap), commodityHubs, sanctions, climate, outages, natural, weather, fires, tradeRoutes. Every geopolitical / military / tech / finance / happy variant layer explicitlyfalsepermulti-variant-site-data-isolationskill.MOBILE_DEFAULT_MAP_LAYERS— minimal mobile set (pipelines, waterways, commodityPorts, natural).What this PR does NOT add (coming in subsequent PRs on this branch)
PipelineStatusPanelStorageFacilityMapPanelFuelShortagePanel(automated watch + evidence-threshold-gated confirmed)CountryDeepDivePanelenergy.worldmonitor.app(infra, not code)Release 2 (post-launch, not on this branch)
Scenario runner,
getEnergyShockcascade RPC, 5 MCP tools, Clerk subscription model, global tanker density, shadow-fleet overlay.Test plan
npm run typecheck)VITE_VARIANT=energyand verifying the listed panels render without errormulti-variant-site-data-isolation)Conventions followed
worldmonitor-pro-panel-gating— variant is free-tier; no PRO gating introduced heremulti-variant-site-data-isolation— explicit per-layer toggle matches commodity/finance variant patternfeedback_world_coverage_never_subset.md— future asset registries will be curated-critical for launch (~75/75/125) then expand; no MAJOR_REPORTERS-style hardcoded subset--no-verify; pre-commit + pre-push hooks ran cleanly