Historical Weather Event Explorer #22
Labels
No labels
area:ai
area:ci-cd
area:notifications
area:observability
area:public-pages
backlog
bug
duplicate
enhancement
help wanted
invalid
question
security
type:decision
type:feature
type:infra
type:maintenance
type:security
v1.0.1
v1.1.0
v1.2.0
v1.3.0
v2.0.0
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/WeatherBot#22
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Target release: v2.0.0 — epic. Implementation is tracked in the child issues indexed below.
Add a historical event reconstruction system (calendar + event review) so users can pick a date and see weather activity across all locations they can access, reconstructing related products into understandable events (SPC outlook → MCDs → watches → warnings → all-clears → radar loops → delivered summaries).
Design pass (2026-07-27)
Key finding: the correlation spine already exists
SentAlert.nws_alert_idstores the VTEC-derived lifecycle id, not the raw NWS feature URN —alert_processor.py:910assignsnws_alert_id=lifecycle_id, built byalert_identity.alert_lifecycle_idasNWS_{office}_{phenomenon}_{significance}_{etn}. That same string is alreadynws_alert_snapshots.lifecycle_id,public_alert_pages.lifecycle_id, half the radar snapshot filename, and the AI summarysource_id. SPC lineage is already recorded explicitly inspc_outlook_risk_transitions.The Explorer therefore does not need an event-correlation layer built from nothing — it needs a grouping layer over keys that already line up. This removes most of the risk originally assumed in this issue.
The real problems are elsewhere
nws_alert_snapshots(full text, geometry, hazards), is only written whenPUBLIC_ALERT_PAGES_ENABLEDis on and the location ispublic_enabled. Both default off. Radar snapshots are likewise off by default. Lightning persists nothing at all. For a private location, all that survives an event today is event name, severity, headline, and times — not enough to reconstruct anything. History not captured is gone forever, so the capture issues must land first.Location.sent_alertscascadesall, delete-orphan— deleting a location destroys its entire history.Decisions taken
Child issues
Capture — land first, every day unshipped is history lost
Data integrity and retention
Correlation
weather_events)Views
Cross-cutting
Open questions — status
Originally sourced from the retired
docs/ROADMAP.md→ Under Investigation → Historical Weather Event Explorer.Engineering complete (2026-08-01)
Every child issue is closed. The full arc, as merged on
main:Foundation — capture ungated (#129–#132, earlier), unified 13-month horizon (#133), location soft-delete so deletion can't destroy history (#134, PR #169).
Correlation — rules decided and ratified (#136: cores-vs-context, 90-min gap, per-location events; manual merge/split deferred to #167), derived rebuildable
weather_eventslayer (#135, PR #168).Views — calendar (#137, PR #170), day detail with SPC risk band (#138, PR #171), event timeline with full official text, delivery record incl. failures, inline AI summaries (#139, PR #172; #23 closed as delivered), radar loop replay (#140, PR #173), JSON export (#142, PR #175).
Performance — bounded /stats, five benchmark-justified indexes, partitioning rejected with measurements on record, Postgres-tier tests (#141, PR #176; also resolved the #174 test flake at root cause).
All open questions in this epic's list are now answered on their respective issues. Remaining before this closes: cut the v2.0.0 release (changelog, tag → registry image, iac pin bump, play) and verify the Explorer against real production history. #158 (capture-table storage measurement after a convective season) stays open independently by design.
Production migration rehearsal: PASS (2026-08-21)
The 1.8.1 → 2.0.0 jump has now been exercised against real production data. Dev only ever migrated incrementally across rc1/rc2/rc3, so the combined
0033 → 0037path had been exercised nowhere — and v1.4.0 rolled back on exactly this class of gap (an empty throwaway hiding what real rows do).Method. Latest production dump (
weatherbot-20260821-033003.sql.gz, 4.6 MB) restored into a throwaway Postgres and migrated with the realweatherbot:2.0.0-rc3image. Run ondocker-hostitself, deliberately: production data includes channel credentials, so copying it to another host to test it would have created a worse problem than the one being tested. Everything created was namespacedwb-rehearsal-*and torn down on exit;weatherbot-db-1and its volume were never touched, and live production remains at0033.Result — all four migrations applied cleanly, exit code 0:
No data loss. Post-migration counts match live production exactly:
sent_alertslocationsnotification_channelsusersSchema objects verified present:
weather_events,weather_event_members,locations.deleted_at, and 22 indexes across the history tables.0037 backfill on real rows:
radar_enabled IS DISTINCT FROM radar_animatedreturns 0 rows. All 4 production channels landt/t.What this does NOT prove
Two honest limits worth recording rather than glossing:
weather_eventsfrom all retained history within 30 minutes of startup — on production that means deriving events across 1,721sent_alertsplus snapshots and lightning, on hardware also serving live alert polling. That job has only ever run against dev's much smaller history. It is the most likely source of a GA surprise now that the migrations are cleared.radar_animated=true, so no real row exercises thefalse → radar_enabled=falsecase that 0037 exists to protect. It passes only in the Postgres-tier test.Remaining before v2.0.0 final
1.8.1→2.0.0and deploy productionAlso worth noting for the record: production's history now has a 9.7-day hole (2026-08-11 to 08-20) from the outage in #186. The Explorer will render those days as "no activity", which is indistinguishable from genuinely quiet weather.
v2.0.0-rc5 tagged and published (2026-10-13) — not yet deployed anywhere
Tag
v2.0.0-rc5on83bd6d1.release.ymlrun 247 built and pushedgit.rhoving.com/rbrooks/weatherbot:2.0.0-rc5(digestsha256:e08bdd82…f5b5a), confirmed from the job log.Since rc4, no Explorer changes and no migrations:
Also closed today: #186 (production cleanup done; outage detection handed to Rhoving/iac-repo#636, which does not gate v2.0.0).
Deliberately held until after 2.0.0: Renovate #178 (SQLAlchemy 2.1 and the rest of the minor/patch group), #199 (Python 3.15), #193 (timezonefinder 9), #197 (signal-cli 0.101).
State of the hosts
1.8.1, database0033, healthy.2.0.0-rc4, database0037, healthy. Two temporary soak locations still present (Jackson MS (rc3 soak),Huntsville AL (rc4 soak)).Remaining before v2.0.0 final
docker-test)issued_atpopulating on newspc_outlook_pagesrows, and the parse warning gone1.8.1→2.0.0, with a dump taken first; an image-only rollback will crash-loop once 0034–0037 have runrc5 deployed to dev, 2026-10-13 16:48 UTC
Pin bump Rhoving/iac-repo#637 (
e3c981d, merged asb2bfe76); play againstdocker-test:ok=23 changed=3 failed=0. The dry run beforehand showed the image line as the only change. Production untouched (group pin still1.8.1).Verified on dev
weatherbot:2.0.0-rc5healthy, 0 restarts, PID 1 is uvicorn as uid 10001 from/opt/venv, reportsv2.0.0-rc5, nogccpresent. Image is 723 MB against 1.02 GB for rc4.0037, scheduler started, no errors./health200,/metrics200,/and/explorer307 to login,/auth/login200,/static/css/app.css200.D1_202610131629hasissued_at16:29Z andD3_202610130708has 07:08Z, matching their product ids. "missing parseable issue time" warnings since start: 0 (rc4 logged about 1,900 a day). Same-risk reissues were recognised as continuations and dispatch was suppressed, so the fix re-sent nothing. Active records expire where expected: Day 1 at 2026-10-14 08:00Z, Day 3 at 2026-10-16 08:00Z.Not verified (needs a browser session)
Seen on dev, pre-existing, not caused by rc5
Checklist
issued_atpopulating, parse warning gone1.8.1→2.0.0rc6 deployed to dev, 2026-10-13 17:50 UTC
Tag
v2.0.0-rc6on421b02d;release.ymlrun 255 pushedweatherbot:2.0.0-rc6(digestsha256:448a009b…9571). Pin bump Rhoving/iac-repo#639 (merged asbd7ed86); play againstdocker-test:ok=23 changed=3 failed=0, image line the only diff. Production untouched on1.8.1.Contents since rc5, all found while checking rc5 on dev, no migrations:
Verified on dev
v2.0.0-rc6, database still0037.Pruned 1 NWS alert freshness row(s) for states no longer monitored. Thenws_alertsfreshness rows are now exactly the five monitored states (AL, KS, MO, MS, OK), all seconds old.nws_alerts:TXis gone.Not verified (needs a browser)
Convective soak in progress
SPC Day 1 (16:29Z) has a Slight Risk from northwest Missouri and Kansas into the southern High Plains, with initiation expected over central Kansas mid-to-late afternoon. @rbrooks added three temporary dev locations at Advisory severity:
Salina, KS (rc5 soak),Wichita, KS (rc5 soak),Enid, OK (rc5 soak). All three resolved (ready) and are being polled. No convective warnings were active nationwide at 17:23Z.Dev now carries five temporary soak locations to remove before GA (these three plus the Jackson MS and Huntsville AL ones).
rc6 browser checks passed (confirmed by @rbrooks, 2026-10-13)
Radar capture is running on rc6
As of 19:20Z dev has captured 24 radar frames since 17:29Z, with every
alert_radar_frameand NOAA MapServer fetch recorded as a success. The frames are riding on Flood Watches for the Wichita and Enid soak locations, not on a convective warning yet, so this proves capture on the two-stage image but not storm motion in a loop.Still open before v2.0.0 final
1.8.1→2.0.0Production migration rehearsal repeated for
0033 → 0038: PASS (2026-10-14)@rbrooks approved the v2.0.0 production release on 2026-10-14 after checking the Kansas loops in the Explorer. Animated notifier radar will be checked on production, as @rbrooks decided.
Method. Same as 2026-08-21, run on
docker-hostso production data never left the host: the newest nightly dump (weatherbot-20261014-033459.sql.gz, 19 MB) restored into a throwawaypostgres:16.15-alpinenamedwb-rehearsal-*, migrated with the realweatherbot:2.0.0-rc7image. Then the scheduler's own correlation job function was run against it in a one-off container. Nothing but the migration and that one function ran: production's data includes channel credentials, and a full app against a copy would send real notifications. Torn down afterwards and confirmed (0 containers, 0 networks, 0 temp files left); the rc7 image it pulled was removed from the host.Migrations: all five applied, 9 seconds, exit 0.
alembic_versionsent_alertslocationsnotification_channelsusersRestore errors: 0. New tables present;
radar_enabledmatchesradar_animatedon all 4 channels.First correlation pass (the one flagged in August as the likeliest go-live surprise): 19.9 seconds, 297 events (287 hazard, 10 watch-only), 909 members, from 1,798 alerts and 297,384 lightning records. Second (steady-state) pass: 1.0 second, event count unchanged.
One thing to watch. The first pass peaked at 597 MB RSS in a standalone process. The production app container has a 1 GiB memory limit and sits at about 216 MiB. In-process the pass should land well under the limit, but an OOM kill during it would restart the app into another first pass, so memory gets watched when the pass runs (30 minutes after startup).
v2.0.0 released and deployed to production, 2026-10-14 05:50 UTC
v2.0.0on859a88a(identical to rc7 apart fromCHANGELOG.md).release.ymlrun 268 pushedweatherbot:2.0.0, digestsha256:97ec7f3c…0197.7b6537c): group pin1.8.1→2.0.0; dev's temporary RC override deleted, so both hosts follow the group pin again.ok=23 changed=3 failed=0,v2.0.0healthy, 0 restarts, no errors.weatherbot-backup.service:weatherbot-20261014-054752.sql.gz(19 MB), gzip verified,alembic_version0033inside, matching live. A copy is pinned as/opt/weatherbot-svc/backups/weatherbot-pre-2.0.0-20261014.sql.gz. Note that the backup unit's own pruning deletesweatherbot-*.sql.gzfiles older than 14 days, the pinned copy included.ok=24 changed=3 failed=0, all pre-flight assertions passed, image line the only diff.Production after the upgrade
weatherbot:2.0.0healthy, 0 restarts,weatherbot.serviceactive, reportsv2.0.0.0033 → 0038applied, all five, as rehearsed.radar_enabled=t, radar_animated=t.Fetched 4 active NWS alerts across 1 states)./health200,/auth/login200. ZeroERRORor traceback lines; the only warnings are discord.py's voice-support notices, unchanged from 1.8.1.Still to watch
weatherbot:2.0.0to close #195Post-deploy watch complete (2026-10-14 07:05Z)
derived 297 event(s) across 5 location(s) (full-history backfill), matching the rehearsal exactly. Container memory peaked at 711 MiB of 1 GiB, no OOM, no restart.LIKEin the per-day record match, latent since before 2.0.0). Hotfixed as v2.0.1, deployed to dev then production at 06:57Z with @rbrooks's approval. SPC outlook processing was down 05:55–07:02Z; NWS warning alerts were unaffected.Production is now on
weatherbot:2.0.1, healthy, 0 errors.Still open
I'd close this epic once the first real notification has gone out cleanly.