fix(telemetry): eliminate synthetic fallbacks in SSR fire summary and weather service #93

Closed
opened 2026-10-14 23:58:24 +00:00 by yuris · 0 comments
Owner

This was generated by AI during triage.

Problem Statement

During the comprehensive architectural audit against docs/ARCHITECTURE.md, two silent synthetic fallback mechanisms were uncovered in the production application:

  1. src/app/page.tsx:49-74 (getSummaryData):
    When the upstream SiPongi API fails during Next.js server-side rendering (SSR), the catch block returns hardcoded fake telemetry (totalHotspots: 10334, criticalClustersCount: 48, Kalimantan Tengah: 2410, Riau: 1980). This misleads users and search engine crawlers with fabricated fire counts across Indonesia during network or API disruptions.

  2. src/lib/services/weather.ts:98-111 (fetchWeatherObservation):
    When Open-Meteo GFS API fails and no cache exists, the service silently catches the error and returns synthetic dry-season weather (temperatureC: 31.0, relativeHumidity: 65, windSpeedKmh: 16.0, windDirectionDeg: 120). These unmeasured synthetic wind vectors are then piped directly into smoke-cone.ts and the composite danger scoring engine, presenting calculated smoke dispersion cones as real observations.

Both mechanisms violate the non-negotiable completeness contract and silent-failure discipline:

  • NEVER deliver fake fallbacks, placeholders, or synthetic mocks in production.
  • Fail loudly or explicitly mark telemetry as unmeasured/offline.

Proposed Remediation

  1. src/app/page.tsx:

    • In getSummaryData(), if fetchSiPongiHotspots() fails and no cached telemetry exists, return a clean empty summary (totalHotspots: 0, criticalClustersCount: 0, provincialSummaries: []).
    • The crawlable SEO component renders an empty/neutral state rather than fabricated fire numbers.
  2. src/lib/services/weather.ts:

    • In fetchWeatherObservation(), if Open-Meteo API fails and no stale cache exists, throw a descriptive error instead of inventing synthetic wind speed and directions.
    • Ensure src/app/api/weather/route.ts returns HTTP 502 with structured error details when upstream is unreachable.
  3. Regression Tests:

    • Add unit tests asserting that upstream failures do not return synthetic mock numbers.
    • Verify that weather failures propagate cleanly as errors when no cache is available.

Acceptance Criteria

  • src/app/page.tsx returns 0 hotspots and empty provincial list upon SiPongi failure; no hardcoded 10,334 numbers remain anywhere in source.
  • src/lib/services/weather.ts throws when Open-Meteo fails without cache; no hardcoded 31°C / 16 km/h synthetic weather.
  • pnpm exec vp check passes with 0 warnings.
  • pnpm test passes all tests.
  • pnpm build completes cleanly.
> *This was generated by AI during triage.* ## Problem Statement During the comprehensive architectural audit against `docs/ARCHITECTURE.md`, two silent synthetic fallback mechanisms were uncovered in the production application: 1. **`src/app/page.tsx:49-74` (`getSummaryData`)**: When the upstream SiPongi API fails during Next.js server-side rendering (SSR), the `catch` block returns hardcoded fake telemetry (`totalHotspots: 10334`, `criticalClustersCount: 48`, `Kalimantan Tengah: 2410`, `Riau: 1980`). This misleads users and search engine crawlers with fabricated fire counts across Indonesia during network or API disruptions. 2. **`src/lib/services/weather.ts:98-111` (`fetchWeatherObservation`)**: When Open-Meteo GFS API fails and no cache exists, the service silently catches the error and returns synthetic dry-season weather (`temperatureC: 31.0`, `relativeHumidity: 65`, `windSpeedKmh: 16.0`, `windDirectionDeg: 120`). These unmeasured synthetic wind vectors are then piped directly into `smoke-cone.ts` and the composite danger scoring engine, presenting calculated smoke dispersion cones as real observations. Both mechanisms violate the non-negotiable completeness contract and silent-failure discipline: - NEVER deliver fake fallbacks, placeholders, or synthetic mocks in production. - Fail loudly or explicitly mark telemetry as unmeasured/offline. ## Proposed Remediation 1. **`src/app/page.tsx`**: - In `getSummaryData()`, if `fetchSiPongiHotspots()` fails and no cached telemetry exists, return a clean empty summary (`totalHotspots: 0`, `criticalClustersCount: 0`, `provincialSummaries: []`). - The crawlable SEO component renders an empty/neutral state rather than fabricated fire numbers. 2. **`src/lib/services/weather.ts`**: - In `fetchWeatherObservation()`, if Open-Meteo API fails and no stale cache exists, throw a descriptive error instead of inventing synthetic wind speed and directions. - Ensure `src/app/api/weather/route.ts` returns HTTP 502 with structured error details when upstream is unreachable. 3. **Regression Tests**: - Add unit tests asserting that upstream failures do not return synthetic mock numbers. - Verify that weather failures propagate cleanly as errors when no cache is available. ## Acceptance Criteria - [x] `src/app/page.tsx` returns 0 hotspots and empty provincial list upon SiPongi failure; no hardcoded 10,334 numbers remain anywhere in source. - [x] `src/lib/services/weather.ts` throws when Open-Meteo fails without cache; no hardcoded 31°C / 16 km/h synthetic weather. - [x] `pnpm exec vp check` passes with 0 warnings. - [x] `pnpm test` passes all tests. - [x] `pnpm build` completes cleanly.
yuris closed this issue 2026-10-15 00:04:45 +00:00
Sign in to join this conversation.
No labels
backend
frontend
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/titik-gambut-next#93
No description provided.