v1.0.2 — Alert correctness & integrity #92

Merged
claude-bot merged 6 commits from fix/v1.0.2-alert-correctness into main 2026-07-18 06:56:42 +00:00
Contributor

Patch release fixing the highest-severity alert-pipeline defects from the 2026-07-17 codebase audit. Bug fixes only, no new features.

Fixes

Issue Finding Fix
#40 F-01 Transient NWS fetch failure mass-cleared all active alerts (false all-clears during live warnings). Fetches now retry with jittered backoff and return None on failure; the poll cycle is skipped (no clearing/dispatch). Mass-clear gated on non-empty locations; alerts with no ends/expires get a synthetic 6h expiry.
#41 F-02 /alerts/active pagination now followed (bounded to 10 pages, logged) so large outbreaks aren't truncated to page one and then cleared as "disappeared".
#42 F-03 SPC convective outlooks record/dispatch per day (1/2/3) instead of collapsing to the single highest risk — lower-risk same-day outlooks are no longer dropped.
#43 F-04 MCD state matching parses the AREAS AFFECTED line instead of the whole narrative, so "in"/"or" no longer match Indiana/Oregon.
#44 F-05 Same-risk SPC reissuance treated as a continuation (row refreshed, no re-dispatch) — ends duplicate notifications and orphaned dashboard rows.
#48 F-09 Channel deletion preserves sent_alerts history (DB SET NULL) instead of cascade-deleting it.
#49 F-10 Public location page server-renders current active alerts with a "No active alerts" empty state instead of "Loading alerts…" forever.
#54 F-15 Details-link generation guarded at every notifier call site (all six channels) — a link failure sends without a link instead of dropping the alert.
#62 F-23 Per-feature SPC parsing and gathers made failure-tolerant — one malformed upstream feature is skipped, not fatal to the whole poll.

Testing

Full suite green on the dev server (Postgres-deps venv, all channels installed): 344 passed, including 27 new regression tests across the five fix areas — false-all-clear injection, pagination, cross-day SPC, MCD collision words, same-risk reissuance, channel-delete history, public-page backfill, per-channel link-failure injection, and malformed-feature skip.

Notes

  • F-15 (#54) was found partly stale — the details-link helper is already internally guarded — so the change is defense-in-depth at the call sites plus regression tests; signal was added for full six-channel parity.
  • The sent_alerts history test asserts the ORM no longer cascade-deletes; the DB-level SET NULL semantics are authoritative on Postgres (SQLite test tier doesn't enforce FKs).

Closes #40, #41, #42, #43, #44, #48, #49, #54, #62

🤖 Generated with Claude Code

Patch release fixing the highest-severity alert-pipeline defects from the 2026-07-17 codebase audit. **Bug fixes only, no new features.** ## Fixes | Issue | Finding | Fix | |---|---|---| | #40 | F-01 | Transient NWS fetch failure mass-cleared all active alerts (false all-clears during live warnings). Fetches now retry with jittered backoff and return `None` on failure; the poll cycle is skipped (no clearing/dispatch). Mass-clear gated on non-empty locations; alerts with no `ends`/`expires` get a synthetic 6h expiry. | | #41 | F-02 | `/alerts/active` pagination now followed (bounded to 10 pages, logged) so large outbreaks aren't truncated to page one and then cleared as "disappeared". | | #42 | F-03 | SPC convective outlooks record/dispatch **per day** (1/2/3) instead of collapsing to the single highest risk — lower-risk same-day outlooks are no longer dropped. | | #43 | F-04 | MCD state matching parses the `AREAS AFFECTED` line instead of the whole narrative, so "in"/"or" no longer match Indiana/Oregon. | | #44 | F-05 | Same-risk SPC reissuance treated as a continuation (row refreshed, no re-dispatch) — ends duplicate notifications and orphaned dashboard rows. | | #48 | F-09 | Channel deletion preserves `sent_alerts` history (DB `SET NULL`) instead of cascade-deleting it. | | #49 | F-10 | Public location page server-renders current active alerts with a "No active alerts" empty state instead of "Loading alerts…" forever. | | #54 | F-15 | Details-link generation guarded at every notifier call site (all six channels) — a link failure sends without a link instead of dropping the alert. | | #62 | F-23 | Per-feature SPC parsing and gathers made failure-tolerant — one malformed upstream feature is skipped, not fatal to the whole poll. | ## Testing Full suite green on the dev server (Postgres-deps venv, all channels installed): **344 passed**, including **27 new regression tests** across the five fix areas — false-all-clear injection, pagination, cross-day SPC, MCD collision words, same-risk reissuance, channel-delete history, public-page backfill, per-channel link-failure injection, and malformed-feature skip. ## Notes - F-15 (#54) was found partly stale — the details-link helper is already internally guarded — so the change is defense-in-depth at the call sites plus regression tests; `signal` was added for full six-channel parity. - The `sent_alerts` history test asserts the ORM no longer cascade-deletes; the DB-level `SET NULL` semantics are authoritative on Postgres (SQLite test tier doesn't enforce FKs). Closes #40, #41, #42, #43, #44, #48, #49, #54, #62 🤖 Generated with [Claude Code](https://claude.com/claude-code)
A failed /alerts/active fetch returned [] indistinguishable from an empty
feed, so one transient NWS error cleared every active alert (all-clears
during live warnings) and re-alerted next poll. fetch_alerts_for_states now
retries with jittered backoff and returns None on failure; poll_alerts_job
skips the cycle (no clearing, no dispatch) on None. The mass-clear path is
also gated on a non-empty locations list, and alerts with no ends/expires
get a synthetic 6h expiry so they stay visible and clearable.

Also follow /alerts/active pagination (bounded to 10 pages, logged) so
large multi-state outbreaks aren't truncated to page one and then cleared
as "disappeared". api/alerts.py handles the new None contract.

Closes #40, #41

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Convective outlooks now record and dispatch per day (1/2/3) instead of
  collapsing to the single globally-highest risk, so a lower-risk same-day
  outlook is no longer dropped when a later day is higher (#42).
- MCD state matching parses the AREAS AFFECTED line instead of scanning the
  whole narrative, so "in"/"or" no longer match Indiana/Oregon (#43).
- Same-risk SPC reissuance is treated as a continuation (row refreshed, no
  re-dispatch) instead of a new outlook, ending duplicate notifications and
  orphaned dashboard rows (#44).
- Per-feature parsing and the SPC gathers are failure-tolerant, so one
  malformed upstream feature is skipped rather than aborting the poll (#62).

Closes #42, #43, #44, #62

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sent_alerts relationship declared cascade="all, delete-orphan", which
overrode the DB FK's ON DELETE SET NULL and hard-deleted alert history on
channel deletion. Drop the cascade and set passive_deletes=True so deleting
a channel leaves its rows as dashboard-only records (channel_id NULL).

Closes #48

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The public page relied solely on SSE deltas, so a visitor during an active
alert saw "Loading alerts…" forever and pre-existing alerts never appeared.
Server-render the location's current active alerts with an explicit
"No active alerts" empty state, keeping SSE (de-duped by alert id) for live
updates.

Closes #49

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The details-link helper is internally guarded, but the richer channels
awaited it without a local guard, so any future regression could abort the
send and permanently drop the alert. Wrap the call at every site (all six
channels, including signal) as SMS already does: on failure, log and send
without a link. Adds a failure-injection regression test per channel.

Closes #54

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add v1.0.2 changelog entry
All checks were successful
CI / test (pull_request) Successful in 4m39s
deb996bf5c
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
claude-bot deleted branch fix/v1.0.2-alert-correctness 2026-07-18 06:56:43 +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!92
No description provided.