Skip to content

fix(renewable): disclose hardcoded fallback data in Renewable Energy panel (#5497)#5521

Closed
HoneyTyagii wants to merge 1 commit into
koala73:mainfrom
HoneyTyagii:fix/renewable-energy-fallback-disclosure
Closed

fix(renewable): disclose hardcoded fallback data in Renewable Energy panel (#5497)#5521
HoneyTyagii wants to merge 1 commit into
koala73:mainfrom
HoneyTyagii:fix/renewable-energy-fallback-disclosure

Conversation

@HoneyTyagii

Copy link
Copy Markdown

Summary

Fixes #5497.

fetchRenewableEnergyData() silently substituted a hardcoded 2022 World Bank snapshot (FALLBACK_DATA) whenever the live seed and the local cache were both unavailable, and RenewableEnergyPanel rendered it with no source/stale/fallback indicator. Because World Bank renewable data genuinely lags ~2 years, the "29.6%, 2022" figure looked indistinguishable from a live read.

This applies the exact fix pattern already shipped for the sibling Human Progress panel (#3758): tag the data with its provenance and disclose the degraded state in the UI.

Changes

  • Provenance field: added source: 'hydrated' | 'bootstrap' | 'fallback' to RenewableEnergyData, set on every code path in fetchRenewableEnergyDataFresh() (hydration cache, live bootstrap fetch, static fallback).
  • No stale banner pinning: the breaker now uses shouldCache: (r) => r.source !== 'fallback' so the static fallback is never persisted to IndexedDB, matching the progress-data fix. The banner clears once the seed/network recovers.
  • UI disclosure: RenewableEnergyPanel.setData() renders a renewable-fallback-banner (role="status") when source === 'fallback', mirroring ProgressChartsPanel's banner.
  • i18n: added components.renewable.fallbackBadge and fallbackTooltip to en.json and synced all 24 locale files (npm run sync:locales).
  • Testability decoupling: the fresh-fetch path now imports createCircuitBreaker from the direct @/utils/circuit-breaker path and lazy-imports the heavy @/services/economic module inside fetchEnergyCapacity(), so the World Bank path is testable in isolation (same lean-import approach as the sibling progress-data.ts).

Acceptance criteria

  • RenewableEnergyData carries a provenance field populated on every code path.
  • RenewableEnergyPanel visibly indicates non-live data when source === 'fallback', mirroring ProgressChartsPanel.
  • Regression test covers the bootstrap and fallback paths.

Testing

  • tests/renewable-energy-fallback-disclosure.test.mts (new): 4 passing (bootstrap tag, network-failure fallback, non-OK status fallback, empty-payload fallback).
  • tests/progress-data-fallback-disclosure.test.mts (sibling): still 4 passing.
  • tsc --noEmit: clean.
  • npm run sync:locales:check: all 24 locales match en.json.
  • biome lint on changed files: clean.

…panel (koala73#5497)

fetchRenewableEnergyData() silently substituted a static 2022 World Bank snapshot when the live seed and cache were both unavailable, and RenewableEnergyPanel rendered it with no staleness indicator. This applies the same fix pattern already shipped for the sibling Human Progress panel (koala73#3758).

- Add a 'source' provenance field (hydrated | bootstrap | fallback) to RenewableEnergyData, set on every code path in fetchRenewableEnergyDataFresh().

- Skip persisting the static fallback to IndexedDB via shouldCache so the banner clears once the seed/network recovers.

- Render a fallback disclosure banner in RenewableEnergyPanel when source === 'fallback', mirroring ProgressChartsPanel.

- Add en.json fallbackBadge/fallbackTooltip keys and sync all 24 locales.

- Decouple the fresh-fetch path from the EIA client graph (direct circuit-breaker import + lazy economic import) so the service is testable in isolation.

- Add regression test covering bootstrap and fallback paths.
Copilot AI review requested due to automatic review settings July 23, 2026 16:43
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

@HoneyTyagii is attempting to deploy a commit to the World Monitor Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the trust:caution Brin: contributor trust score caution label Jul 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds provenance and a visible disclosure for hardcoded renewable-energy fallback data.

  • Tags hydrated, bootstrap, and static-fallback renewable datasets with their source.
  • Prevents newly generated static fallback results from being persisted by the circuit breaker.
  • Adds localized fallback badge and tooltip keys across the locale catalogs.
  • Lazy-loads the economic service for capacity requests and adds service-path regression tests.

Confidence Score: 3/5

The legacy cache compatibility issue should be fixed before merging because upgraded users can still receive undisclosed hardcoded fallback data.

The new predicate correctly excludes newly tagged fallback results, but source-less fallback records persisted by the previous release are accepted and rendered without the banner this change is intended to guarantee.

src/services/renewable-energy-data.ts

Important Files Changed

Filename Overview
src/services/renewable-energy-data.ts Adds provenance-aware fetching and cache policy, but legacy source-less fallback cache entries still bypass the new policy.
src/components/RenewableEnergyPanel.ts Adds a status banner for data explicitly tagged as static fallback.
tests/renewable-energy-fallback-disclosure.test.mts Covers fresh bootstrap and fallback paths but not migration behavior for pre-existing IndexedDB records.
src/locales/en.json Adds the fallback disclosure label and explanatory tooltip.

Reviews (1): Last reviewed commit: "fix(renewable): disclose hardcoded fallb..." | Re-trigger Greptile

// swallows errors and returns FALLBACK_DATA, which the breaker would
// otherwise cache to IndexedDB for the 1h TTL and keep showing the
// disclosure banner long after the seed/network recovers.
{ shouldCache: (result) => result.source !== 'fallback' },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Legacy fallbacks bypass disclosure

When a returning user has a pre-upgrade IndexedDB entry containing the hardcoded fallback without a source field, this predicate accepts it because undefined !== 'fallback'; the panel then receives the unchanged record and omits the fallback banner, causing the 2022 snapshot to remain undisclosed until the cache expires or a live refresh replaces it.

@koala73

koala73 commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Fixed properly in #5551

@koala73 koala73 closed this Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trust:caution Brin: contributor trust score caution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Renewable Energy panel serves hardcoded 2022 fallback data with zero staleness disclosure (sibling of fixed #3758)

3 participants