Extract dashboard assembly from main.py; stop the 13-request live SPC fan-out per page load #58

Closed
opened 2026-07-18 05:31:23 +00:00 by claude-bot · 1 comment
Contributor

The dashboard route (app/main.py:138-444) contains ~300 lines of SPC
grouping/risk logic plus a "live fallback" that awaits 13 SPC fetches
(main.py:283-317) on every page load with no caching anywhere in
spc.py/nws.py for those calls — while the scheduler polls the same data every
5 minutes. Extract assembly into a service; serve live-fallback data from a
short-TTL cache shared with the poller (or drop the fallback in favor of
dashboard records). Consolidate the duplicated match-context builders
(spc_processor.py:232-273 vs spc_impacts.py:70-107 — already drifted:
guidance key, _metadata_value sanitization). Delete the dead _on_notify
handler (app/api/sse.py:42-43) while touching adjacent code.

Acceptance criteria:

  • Dashboard load performs zero direct SPC upstream requests (cache or records)
  • One shared SPC per-day risk-selection implementation
  • main.py route reduced to auth + service call + render

Filed from the 2026-07-17 codebase audit (docs/.internal/report-2026-07-17.md), finding F-19.

The dashboard route (app/main.py:138-444) contains ~300 lines of SPC grouping/risk logic plus a "live fallback" that awaits 13 SPC fetches (main.py:283-317) on every page load with no caching anywhere in spc.py/nws.py for those calls — while the scheduler polls the same data every 5 minutes. Extract assembly into a service; serve live-fallback data from a short-TTL cache shared with the poller (or drop the fallback in favor of dashboard records). Consolidate the duplicated match-context builders (spc_processor.py:232-273 vs spc_impacts.py:70-107 — already drifted: `guidance` key, `_metadata_value` sanitization). Delete the dead `_on_notify` handler (app/api/sse.py:42-43) while touching adjacent code. **Acceptance criteria:** - [ ] Dashboard load performs zero direct SPC upstream requests (cache or records) - [ ] One shared SPC per-day risk-selection implementation - [ ] main.py route reduced to auth + service call + render --- _Filed from the 2026-07-17 codebase audit (`docs/.internal/report-2026-07-17.md`), finding F-19._
Author
Contributor

Done in #110 (merged). Both parts:

Dashboard extraction + no live fan-out. New app/services/dashboard.py build_dashboard_context(request, user) owns the assembly; the / route is now auth + service call + render (~10 lines, down from ~318). The 13-request live SPC fan-out is removedpoll_spc_dashboard already upserts dashboard SPC records for all enabled+ready locations every cycle, so the dashboard reads outlooks purely from DB records and makes zero direct SPC upstream requests on load (asserted by a test that fails if any fetcher is called). _is_live was unused by any template; the dead _on_notify the audit cited was already removed by the #53 SSE broker rewrite (only the live _on_notification remains).

Match-context consolidation. The two drifted builders are now one spc_outlook_match_context in spc_impacts.py — the correct superset (_metadata_value sanitization + guidance + is_extended/spc_product_family); the notification-path builder was deleted and its caller routed through the shared one. Intended drift fixes: the impact path now also gets guidance + sanitized values, and the notification location_match.product_family is the canonical spc_convective_outlook (a context string the summary validators don't key on; payload.product_family unchanged).

All acceptance criteria met. ruff clean; bulk 670 passed; postgres tier 4 passed on the dev server.

Minor follow-up (not in scope here): the separate /spc/outlooks API endpoint still fetches SPC live per request — a candidate for the same records-based treatment if it ever matters.

Done in #110 (merged). Both parts: **Dashboard extraction + no live fan-out.** New `app/services/dashboard.py` `build_dashboard_context(request, user)` owns the assembly; the `/` route is now auth + service call + render (~10 lines, down from ~318). The 13-request live SPC fan-out is **removed** — `poll_spc_dashboard` already upserts dashboard SPC records for all enabled+ready locations every cycle, so the dashboard reads outlooks purely from DB records and makes **zero direct SPC upstream requests on load** (asserted by a test that fails if any fetcher is called). `_is_live` was unused by any template; the dead `_on_notify` the audit cited was already removed by the #53 SSE broker rewrite (only the live `_on_notification` remains). **Match-context consolidation.** The two drifted builders are now one `spc_outlook_match_context` in `spc_impacts.py` — the correct superset (`_metadata_value` sanitization + `guidance` + `is_extended`/`spc_product_family`); the notification-path builder was deleted and its caller routed through the shared one. Intended drift fixes: the impact path now also gets guidance + sanitized values, and the notification `location_match.product_family` is the canonical `spc_convective_outlook` (a context string the summary validators don't key on; `payload.product_family` unchanged). All acceptance criteria met. ruff clean; bulk 670 passed; postgres tier 4 passed on the dev server. Minor follow-up (not in scope here): the separate `/spc/outlooks` API endpoint still fetches SPC live per request — a candidate for the same records-based treatment if it ever matters.
Sign in to join this conversation.
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
rbrooks/WeatherBot#58
No description provided.