Files
worldmonitor/tests
Elie Habib 0bca368a7d feat(energy-atlas): EnergyRiskOverviewPanel — executive overview tile (parity PR 2, plan U5-U6) (#3398)
* feat(energy-atlas): EnergyRiskOverviewPanel — executive overview tile (PR 2, plan U5-U6)

Lands the consolidated "first fold" surface that peer reference energy-intel
sites use as their executive overview. Six tiles in a single panel:
1. Strait of Hormuz status (closed/disrupted/restricted/open)
2. EU gas storage fill % (red <30, amber 30-49, green ≥50)
3. Brent crude price + 1-day change (importer-leaning: up=red, down=green)
4. Active disruption count (filtered to endAt === null)
5. Data freshness ("X min ago" from youngest fetchedAt)
6. Hormuz crisis day counter (default 2026-02-23 start, env-overridable)

Per docs/plans/2026-04-25-003-feat-energy-parity-pushup-plan.md PR 2.

U5 — Component (src/components/EnergyRiskOverviewPanel.ts):
- Composes 5 existing services via Promise.allSettled — never .all. One slow
  or failing source CANNOT freeze the panel; failed tiles render '—' and
  carry data-degraded="true" for QA inspection. Single most important
  behavior — guards against the recurrence of the #3386 panel-stuck bug.
- Uses the actual Hormuz status enum 'closed'|'disrupted'|'restricted'|'open'
  (NOT 'normal'/'reduced'/'critical' — that triplet was a misread in earlier
  drafts). Test suite explicitly rejects the wrong triplet via the gray
  sentinel fallback.
- Brent color inverted from a default market panel: oil price UP = red
  (bad for energy importers, the dominant Atlas reader); DOWN = green.
- Crisis-day counter sourced from VITE_HORMUZ_CRISIS_START_DATE env
  (default 2026-02-23). NaN/future-dated values handled with explicit
  '—' / 'pending' sentinels so the tile never renders 'Day NaN'.
- 60s setInterval re-renders the freshness tile only — no new RPCs fire
  on tick. setInterval cleared in destroy() so panel teardown is clean.
- Tests: 24 in tests/energy-risk-overview-panel.test.mts cover Hormuz
  color enum (including the wrong-triplet rejection), EU gas thresholds,
  Brent inversion, active-disruption color bands, freshness label
  formatting, crisis-day counter (today/5-days/NaN/future), and the
  degraded-mode contract (all-fail still renders 6 tiles with 4 marked
  data-degraded).

U6 — Wiring (5 sites per skill panel-stuck-loading-means-missing-primetask):
- src/components/index.ts: barrel export
- src/app/panel-layout.ts: import + createPanel('energy-risk-overview', ...)
- src/config/panels.ts: priority-1 entry in ENERGY_PANELS (top-of-grid),
  priority-2 entry in FULL_PANELS (CMD+K-discoverable, default disabled),
  panelKey added to PANEL_CATEGORY_MAP marketsFinance category
- src/App.ts: import type + primeTask kickoff (between energy-disruptions
  and climate-news in the existing ordering convention)
- src/config/commands.ts: panel:energy-risk-overview command with keywords
  for 'risk overview', 'executive overview', 'hormuz status', 'crisis day'

No new RPCs (preserves agent-native parity — every metric the panel shows
is already exposed via existing Connect-RPC handlers and bootstrap-cache
keys; agents can answer the same questions through the same surface).

Tests: typecheck clean; 24 unit tests pass on the panel's pure helpers.
Manual visual QA pending PR merge + deploy.

Plan section §M effort estimate: ~1.5d. Codex-approved through 8 review
rounds against origin/main @ 050073354.

* fix(energy-atlas): extract Risk Overview state-builder + real component test (PR2 review)

P2 — tests duplicated helper logic instead of testing the real panel
(energy-risk-overview-panel.test.mts:10):
- The original tests pinned color/threshold helpers but didn't import
  the panel's actual state-building logic, so the panel could ship
  with a broken Promise.allSettled wiring while the tests stayed green.

Refactor:
- Extract the state-building logic into a NEW Vite-free module:
  src/components/_energy-risk-overview-state.ts. Exports
  buildOverviewState(hormuz, euGas, brent, disruptions, now) and a
  countDegradedTiles() helper for tests.
- The panel now imports and calls buildOverviewState() directly inside
  fetchData(); no logic duplication. The Hormuz tile renderer narrows
  status with an explicit cast at use site.
- Why a new module: the panel transitively imports `import.meta.glob`
  via the i18n service, which doesn't resolve under node:test even
  with tsx loader. Extracting the testable logic into a
  Vite-dependency-free module is the cleanest way to exercise the
  production code from tests, per skill panel-stuck-loading-means-
  missing-primetask's emphasis on "test the actual production logic,
  not a copy-paste of it".

Tests added (11 real-component cases via the new module):
- All four sources fulfilled → 0 degraded.
- All four sources rejected → 4 degraded, no throw, no cascade.
- Mixed (1 fulfilled, 3 rejected) → only one tile populated.
- euGas with `unavailable: true` sentinel → degraded.
- euGas with fillPct=0 → degraded (treats as no-data, not "0% red").
- brent empty data array → degraded.
- brent first-quote price=null → degraded.
- disruptions upstreamUnavailable=true → degraded.
- disruptions ongoing filter: counts only endAt-falsy events.
- Malformed hormuz response (missing status field) → degraded sentinel.
- One rejected source MUST NOT cascade to fulfilled siblings (the
  core degraded-mode contract — pinned explicitly).

Total: 35 tests in this file (was 24; +11 real-component cases).
typecheck clean.

* fix(energy-atlas): server-side disruptions filter + once-only style + panel name parity (PR2 review)

Three Greptile P2 findings on PR #3398:

- listEnergyDisruptions called with ongoingOnly:true so the server filters
  the historical 52-event payload server-side. The state builder still
  re-filters as defense-in-depth.
- RISK_OVERVIEW_CSS injected once into <head> via injectRiskOverviewStylesOnce
  instead of being emitted into setContent on every render. The 60s freshness
  setInterval was tearing out and re-inserting the style tag every minute.
- FULL_PANELS entry renamed from "Energy Risk Overview" to
  "Global Energy Risk Overview" to match ENERGY_PANELS and the CMD+K command.
2026-04-25 17:56:02 +04:00
..