v1.4.0 Phase 3: extract dashboard assembly, drop live SPC fan-out, consolidate match-context (#58) #110

Merged
claude-bot merged 2 commits from feat/v1.4.0-phase3-dashboard into main 2026-07-19 04:28:46 +00:00
Contributor

Final v1.4.0 phase — resolves F-19.

Dashboard extraction + no more live fan-out

The / route was ~318 lines and awaited a 13-request live SPC fan-out on every page load. That work is redundant: poll_spc_dashboard already upserts dashboard SPC records for all enabled+ready locations every cycle (independent of subscriptions — its docstring says so).

  • New app/services/dashboard.pybuild_dashboard_context(request, user) does all assembly and returns the template context. The / route is now auth + service call + render (~10 lines).
  • Live SPC fan-out dropped: the dashboard reads outlooks purely from DB records. A dashboard load now makes zero direct SPC upstream requests — asserted by a new test that patches the fetchers to fail if called.
  • _is_live is unused by any template (no template change needed). The dead _on_notify the audit cited was already removed by the #53 SSE broker rewrite — only the live _on_notification remains, left intact.

Acceptance criteria met: zero upstream requests on load ✓, one shared per-day risk selection (choose_highest_risk_for_point, owned by poll_spc_dashboard) ✓, route reduced to auth + service + render ✓.

Match-context consolidation

_spc_outlook_location_match_context (notification path) and spc_outlook_match_context (impact path) had drifted (guidance key + _metadata_value sanitization on one side; is_extended/spc_product_family on the other). Now one spc_outlook_match_context in spc_impacts.py — the superset (sanitization + guidance + extended support); _metadata_value moved there (existing one-way import direction, no cycle). The old builder is deleted and its caller routed through the shared one.

Behavior notes: the impact path now also gets guidance + sanitized values (the intended drift fix); the notification location_match.product_family is now the canonical spc_convective_outlook (a context string the summary validators don't key on — payload.product_family is unchanged). A location with no dashboard record shows an SPC card only after the next poll_spc_dashboard cycle (steady-state coverage unchanged).

Testing (dev server)

ruff clean; bulk 670 passed; Postgres tier 4 passed.

Closes #58

🤖 Generated with Claude Code

Final v1.4.0 phase — resolves F-19. ## Dashboard extraction + no more live fan-out The `/` route was ~318 lines and awaited a **13-request live SPC fan-out on every page load**. That work is redundant: `poll_spc_dashboard` already upserts dashboard SPC records for all enabled+ready locations every cycle (independent of subscriptions — its docstring says so). - New `app/services/dashboard.py` → `build_dashboard_context(request, user)` does all assembly and returns the template context. The `/` route is now **auth + service call + render (~10 lines)**. - **Live SPC fan-out dropped**: the dashboard reads outlooks purely from DB records. A dashboard load now makes **zero direct SPC upstream requests** — asserted by a new test that patches the fetchers to fail if called. - `_is_live` is unused by any template (no template change needed). The dead `_on_notify` the audit cited was already removed by the #53 SSE broker rewrite — only the live `_on_notification` remains, left intact. Acceptance criteria met: zero upstream requests on load ✓, one shared per-day risk selection (`choose_highest_risk_for_point`, owned by `poll_spc_dashboard`) ✓, route reduced to auth + service + render ✓. ## Match-context consolidation `_spc_outlook_location_match_context` (notification path) and `spc_outlook_match_context` (impact path) had drifted (`guidance` key + `_metadata_value` sanitization on one side; `is_extended`/`spc_product_family` on the other). Now **one** `spc_outlook_match_context` in `spc_impacts.py` — the superset (sanitization + guidance + extended support); `_metadata_value` moved there (existing one-way import direction, no cycle). The old builder is deleted and its caller routed through the shared one. **Behavior notes:** the impact path now also gets `guidance` + sanitized values (the intended drift fix); the notification `location_match.product_family` is now the canonical `spc_convective_outlook` (a context string the summary validators don't key on — `payload.product_family` is unchanged). A location with no dashboard record shows an SPC card only after the next `poll_spc_dashboard` cycle (steady-state coverage unchanged). ## Testing (dev server) ruff clean; bulk **670 passed**; Postgres tier **4 passed**. Closes #58 🤖 Generated with [Claude Code](https://claude.com/claude-code)
F-19: the dashboard "/" route was ~318 lines and, on every page load, awaited a
13-request live SPC fan-out (convective + fire + extended geometry + 10 outlook
texts) — duplicating work the scheduler already does.

- New app/services/dashboard.py: build_dashboard_context(request, user) does all
  the assembly (visible locations, active-alert lifecycle grouping, SPC records +
  impact-page ids, per-location severity, highest-risk-per-day grouping, freshness
  banner) and returns the template context. The "/" route is now auth + service
  call + render (~10 lines).
- Dropped the live SPC fan-out entirely: poll_spc_dashboard already upserts
  dashboard SPC records for all enabled+ready locations every cycle (independent
  of subscriptions), so the dashboard reads outlooks purely from DB records. A
  dashboard load now makes ZERO direct SPC upstream requests (new test asserts the
  fetchers are never called).
- _is_live is unused by any template, so no template change was needed; the dead
  _on_notify handler the audit cited was already removed by the #53 SSE broker
  rewrite (only the live _on_notification remains).

Behavior: a location with no dashboard SPC record shows an SPC card only after the
next poll_spc_dashboard cycle (steady-state coverage unchanged, since that job
already covers all enabled+ready locations).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Consolidate the two drifted SPC match-context builders into one (#58)
All checks were successful
CI / test (pull_request) Successful in 4m10s
0a146d4ad2
F-19: _spc_outlook_location_match_context (spc_processor.py, notification path)
and spc_outlook_match_context (spc_impacts.py, impact-page path) had drifted —
the former had a guidance key + _metadata_value sanitization but no extended
support; the latter supported is_extended via spc_product_family but lacked
guidance/sanitization.

- One shared spc_outlook_match_context(location, outlook, *, is_fire, is_extended)
  in spc_impacts.py, the correct superset: _metadata_value sanitization + the
  guidance key + spc_product_family/is_extended. _metadata_value moved to
  spc_impacts.py (the existing one-way import direction; no circular import).
- Deleted _spc_outlook_location_match_context; its notification caller now uses
  the shared builder (is_extended=False).

Drift resolution (intended): the impact path now also gets guidance + sanitized
values, and the notification location_match product_family is now the canonical
spc_convective_outlook (a context-metadata string the summary validators don't
key on; payload.product_family is unchanged).

Full suite green on the dev server: 670 passed, postgres tier 4 passed.

Closes #58

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
claude-bot deleted branch feat/v1.4.0-phase3-dashboard 2026-07-19 04:28:47 +00:00
Sign in to join this conversation.
No reviewers
No milestone
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!110
No description provided.