The three SEO content handlers (city / month / records) resolved the city by loading its full ~45-year archive up front, only then checking the derived-store cache, so even a cache HIT paid the full-history load (2-6s on prod).
Restructure so the cheap path runs first: city lookup + grid snap + the cheap content_token (indexed MAX(date), no history load) produce the cache key/ETag, and the expensive load (history, recent forecast) moves into the build() closure that _cached only calls on a miss. A store hit, or a 304, now returns without ever touching the archive. Cache keys/kinds/tokens are unchanged.
Add route tests asserting a second identical request loads history zero more times, that 304 revalidation loads nothing, plus payload/404 coverage.