The /api/journal/weather route was filtering out cache rows older than 24
hours via parse_weather_card_data, while journal_prep.py read the same
rows raw without freshness checking. Result: the daily prep referenced
"home" and "work" temperatures while the right-rail UI showed nothing —
two surfaces, same backing data, inconsistent visibility.
Two changes:
1. parse_weather_card_data no longer returns None for stale data.
WeatherCard already exposes fetched_at and gracefully hides
today_high / forecast fields when they're absent, so old data renders
with whatever fields the cached forecast still covers.
2. The /weather route opportunistically schedules a background refresh
for any cache row older than 4 hours. If the user's journal_config
has lat/lon for that location_key, the refresh runs and the next
page load gets fresh data; if no usable config, the refresh is a
silent no-op and the stale cache is still served.
This makes prep and UI consistent. It also self-heals over time — once
locations are configured, stale caches get refreshed on the next page
load instead of waiting indefinitely.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>