Open-Meteo's daily high/low for the current day aggregates only the hours
elapsed so far, so grading it reads a still-unfolding day as complete and
produces spurious extremes — a cool morning served as a 1st-percentile
record-low high. The MET Norway primary already guards this with its
diurnal-coverage gate; the Open-Meteo fallback had no equivalent, so a
fleet-wide failover onto it exposed the bug.
Use the utc_offset_seconds Open-Meteo reports for a timezone=auto request to
identify the cell's local today and exclude it from the bundle. Past days are
complete and future days are whole-day forecasts, so only today is dropped;
the day lands in the record once it is over. When no offset is reported the
guard is skipped rather than guessing a date.
Content pages keyed cache validity on the full-history hist_end, invalidating ~1-2x/day and paying a 45yr load even to compute the token. Add content_token(cell_id) = PAYLOAD_VER:CONTENT_VER:max_date, backed by an indexed MAX(date) (climate_store.history_max_date / climate.history_max_date), so it survives intra-day top-ups and needs no full-history load.
Steady-state usage of the Open-Meteo API is removed; it remains only as a dormant fallback. Geocoding -> local GeoNames + Nominatim; wind gusts -> Meteostat; history -> NASA POWER (curated cells seeded with keyless ERA5); recent+forecast -> NASA range + MET Norway. Plus a drift-check tool comparing NASA vs Open-Meteo. All keyless, no new infra. Backend suite green in-image (gate).