Skip to content

Comments

feat: alert lifecycle intelligence — new/updated/cancelled summaries (#321)#330

Merged
Orinks merged 6 commits intodevfrom
feat/alert-lifecycle-intelligence
Feb 24, 2026
Merged

feat: alert lifecycle intelligence — new/updated/cancelled summaries (#321)#330
Orinks merged 6 commits intodevfrom
feat/alert-lifecycle-intelligence

Conversation

@Orinks
Copy link
Owner

@Orinks Orinks commented Feb 20, 2026

feat: alert lifecycle intelligence — new/updated/cancelled summaries (#321)

Implements issue #321: surface meaningful alert lifecycle diffs (new, updated, cancelled) so the UI and screen reader output can describe what changed, not just list current alerts.

Changes

US-001: AlertLifecycleDiff model + diff_alerts() function (alert_lifecycle.py)

  • AlertChangeKind enum: NEW, UPDATED, CANCELLED
  • AlertChange dataclass with is_severity_upgrade property
  • AlertLifecycleDiff dataclass: new_alerts, updated_alerts, cancelled_alerts, summary, has_changes
  • diff_alerts(previous, current) pure function — compares two WeatherAlerts snapshots

US-002: Surface diff in AlertsPresentation + build_alerts()

  • AlertsPresentation gets change_summary: str | None = None field
  • build_alerts() accepts lifecycle_diff kwarg; when changes exist, prepends "Alert changes: {summary}\n" to fallback_text

US-003: Cache previous alerts per-location in WeatherClient; wire diff into presenter

  • WeatherData gets alert_lifecycle_diff: AlertLifecycleDiff | None = None field
  • WeatherClient.__init__ now maintains _previous_alerts: dict[str, WeatherAlerts]
  • _location_key(location) static method: "{lat:.4f},{lon:.4f}"
  • _fetch_smart_auto_source() (auto/multi-source path): computes diff against previous, stores current
  • _do_fetch_weather_data() NWS and VC single-source paths: same lifecycle diff computation
  • WeatherPresenter._build_alerts() now accepts lifecycle_diff kwarg and forwards it to build_alerts()
  • WeatherPresenter.present() passes weather_data.alert_lifecycle_diff into _build_alerts()

Tests

  • tests/test_alert_lifecycle.py — 27 tests for model and diff_alerts() function
  • tests/test_alert_lifecycle_presentation.py — 16 tests for AlertsPresentation integration
  • tests/test_alert_lifecycle_pipeline.py — 10 new tests for WeatherClient pipeline:
    • _location_key() correctness
    • First fetch: all alerts marked as NEW
    • Second fetch with same alerts: has_changes == False
    • Second fetch with one alert removed: cancelled_alerts non-empty
    • Per-location cache independence
    • WeatherData.alert_lifecycle_diff field defaults and assignment

All 2166 tests pass. Ruff clean.

Closes

Fixes #321

@Orinks Orinks force-pushed the feat/alert-lifecycle-intelligence branch from 29f2bf4 to 7ae5ef4 Compare February 24, 2026 00:01
- Add notify_lifecycle_changes() to AlertNotificationSystem
- Updated alerts fire UPDATED/ESCALATED toast notifications
- Cancelled alerts fire CANCELLED toast notifications
- Escalation upgrades play sound; plain updates and cancellations do not
- Hook notify_lifecycle_changes() into main_window.py weather update path
- Add 6 tests covering all lifecycle notification scenarios
@Orinks Orinks force-pushed the feat/alert-lifecycle-intelligence branch from 7ae5ef4 to aab78bd Compare February 24, 2026 01:56
…llback

Headline changes during updates (e.g. 'in effect until 3 PM' → '5 PM')
causing the hash to change — lifecycle diff would emit cancel+new instead
of updated. Switch to event+area+severity which are stable across updates.
@Orinks Orinks merged commit 4c6e856 into dev Feb 24, 2026
6 checks passed
@Orinks Orinks deleted the feat/alert-lifecycle-intelligence branch February 24, 2026 02:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant