File size: 4,745 Bytes
d9ffd67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
---
title: Bootstrap health reports missing compact projections as EMPTY
date: 2026-07-14
category: logic-errors
module: api/health.js
problem_type: logic_error
component: service_object
severity: high
symptoms:
  - "Fresh seed metadata with a missing compact projection payload reported OK in /api/health."
  - "Dashboard panels could render blank without an actionable health signal."
root_cause: logic_error
resolution_type: code_fix
tags: [bootstrap-hydration, seed-meta, freshness-tracking, redis, health]
---

# Bootstrap health reports missing compact projections as EMPTY

## Problem

[`/api/health`](../../../api/health.js) previously allowed every `EMPTY_DATA_OK` source to report `OK` when its `seed-meta` was fresh, even if its Redis payload was absent. That contract was too broad for compact bootstrap projections: a writer or transform failure could blank a user-facing panel while health remained green. The affected issue is [#5321](https://github.com/koala73/worldmonitor/issues/5321).

`api/health.js:710-725` puts both quiet metadata-only sources and bootstrap projections in `EMPTY_DATA_OK_KEYS`. Treating both categories alike erased the distinction between an expected quiet result and a missing required projection.

## Symptoms

- Health reported `OK` for a fresh bootstrap seed even though its data key was gone.
- Panels backed by compact projections could render empty without an actionable health signal.
- Operators could not distinguish a quiet successful source cycle from a missing projection payload.

## What Didn't Work

Making every `EMPTY_DATA_OK` key fail when the payload was missing would have fixed the projection blind spot, but it would also have broken normal quiet-source behavior. `ddosAttacks`, `trafficAnomalies`, `weatherAlerts`, and `newsThreatSummary` legitimately write fresh metadata without a payload after a successful quiet cycle; they must remain healthy in that state. The test contract at `tests/health-empty-data-ok.test.mjs:16-92` covers this distinction.

Earlier bootstrap work had correctly added compact dashboard-shaped side keys, but it also showed that a side key needs its own availability signal; healthy metadata alone cannot prove that a required projection is present (session history).

## Solution

Keep the broad `EMPTY_DATA_OK_KEYS` list, then add an explicit strict subset for projections that must have a payload:

```js
const MISSING_DATA_IS_FAILURE_KEYS = new Set([
  'thermalEscalationBootstrap',
  'ucdpEventsBootstrap',
  'wildfiresBootstrap',
  'forecastsBootstrap',
  'positiveGeoEvents',
]);
```

The set is defined at `api/health.js:727-737`. In the health evaluation, a strict key with fresh seed metadata and no data key now reports `EMPTY` before the general `EMPTY_DATA_OK` path runs. All other `EMPTY_DATA_OK` keys retain the prior `OK`-when-fresh and stale-status behavior (`api/health.js:926-933`).

## Why This Works

The check is narrow and expresses the real operational invariant: the five named projections represent expected bootstrap data, whereas the quiet sources represent an optional observation that may legitimately have no payload. Giving strict missing-payload detection precedence catches projection writer and transform failures without turning expected no-event cycles into false alarms. The exact source categorization is visible in `api/health.js:710-737`, and the two resulting contracts are exercised in `tests/health-empty-data-ok.test.mjs:16-92`: strict keys are expected to be `EMPTY`, while quiet keys are expected to be `OK`.

## Prevention

When adding a source to `EMPTY_DATA_OK_KEYS`, decide explicitly which contract it needs:

- Quiet or metadata-only sources may stay in the general list, where fresh metadata plus no payload is healthy.
- Bootstrap projections or other data-required outputs must also be added to `MISSING_DATA_IS_FAILURE_KEYS` so a missing fresh payload is visible as `EMPTY`.

Extend `tests/health-empty-data-ok.test.mjs` with both the intended strict and quiet expectation for any new category. This protects the distinction at the Vercel Edge health endpoint instead of relying on an implicit interpretation of `EMPTY_DATA_OK`.

## Related Issues

- [#5321: health: EMPTY_DATA_OK bootstrap projections report OK while their key is GONE](https://github.com/koala73/worldmonitor/issues/5321)
- [Health must not grade an unconfigured optional source](health-must-not-grade-an-unconfigured-optional-source.md) — related classifier precedent for preserving an actionable source-state distinction.
- [Merged is not ran long cron seeders](../integration-issues/merged-is-not-ran-long-cron-seeders.md) — distinguishes this fresh-metadata/missing-payload condition from a producer that has not run.