Production: SPC outlook poll fails every cycle after 2.0.0 (unescaped LIKE in the SPC day match) #214
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
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/WeatherBot#214
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?
Found 2026-10-14 06:22Z during the post-deploy watch of v2.0.0 on production.
Impact
poll_spc_jobhas raised on every run since the upgrade (05:55, 06:00, 06:05, 06:10, 06:15, 06:21Z; 24 tracebacks).poll_alerts_jobsucceeded 31 of 31 runs in the same window.Error
Seen for three keys:
D1_202610140100_1_MRGLandD2_202610140521_2_MRGLon one location,D2_202610140521_2_MRGLon another.Cause
_upgrade_check(app/services/spc_processor.py) finds a location's active SPC dashboard rows for one outlook day with:In SQL
LIKE,_matches any single character. Product ids are timestamps, so the pattern matches almost every row. Checked against production's real ids:SPC_OUTLOOK_D1_202610140100_1_MRGLSPC_OUTLOOK_D2_202610140521_2_MRGLSPC_OUTLOOK_D3_202610131930_3_MRGLThe loop then treats the first same-risk row it gets as a "continuation" and renames it to the new product's dedup id. When that row belongs to a different day, and the correct day's row already holds that id, the partial unique index
uq_sent_alerts_dashboard_deduprejects it and the whole poll fails.Why it surfaced with 2.0.0. The match itself predates 2.0.0, and production's data shows the scars: rows whose
sent_atbelongs to one day's record now carry another day's id. The query had noORDER BY. The likely trigger is migration0036's newix_sent_alerts_location_sent_atindex, which changed the plan, and so which row comes first, from "usually the right one" to "the wrong one every time". That is inference, not something I measured. Either way the root defect is the unescapedLIKE.Why tests and dev missed it. Every test uses product ids like
D1_P1, which never have a digit next to an underscore. Dev's locations carry only one or two outlook days at a time.The same unescaped pattern is in
app/api/alerts.py(the dashboard's per-day SPC history), where it only mixes other days' rows into a read-only list.Fix
contains(day_suffix, autoescape=True)in both places._upgrade_check, skip any row whose parsed day differs from the outlook's day (backstop), and order the rows bysent_atso the result is deterministic.Existing data
Rows already renamed across days are not repaired by the fix. Each still has a single active row per day-id, so the continuation logic recovers as new products arrive. Checking that on production after the hotfix is part of verifying it.
Fix merged via #215 (
ad8184a). CI run 269 green in 6m3s, both test tiers.The regression test seeds production's exact shape (one active MRGL row per outlook day, timestamp product ids). Without the fix it raises the same
IntegrityErrorproduction logs; with the fix it passes, each row stays on its own day and nothing re-notifies.v2.0.1 changelog is up as #216. Releasing and deploying to dev follows once that is green. Production deploy of 2.0.1 is waiting on @rbrooks's go-ahead: the 2.0.0 approval did not cover a second release. Until then SPC outlook notifications stay off on production; NWS warnings are unaffected.
Production status at 06:21Z, for the record: the first correlation pass completed (297 events, matching the rehearsal) with a memory peak of 711 MiB of 1 GiB, no OOM, no restarts.
Fixed in v2.0.1, deployed to dev and production (2026-10-14)
Tag
v2.0.1on12b59a3;release.ymlrun 273 pushedweatherbot:2.0.1(digestsha256:2c1c6136…c9aa3). Pin Rhoving/iac-repo#643 (merged as60b6266). Production deploy approved by @rbrooks, conditional on dev testing clean.Dev (06:50Z): play
ok=23 changed=3 failed=0; first SPC poll succeeded with each day's record continued on its own day; 0 errors.Production (play 06:56–06:57Z,
ok=24 changed=3 failed=0):weatherbot:2.0.1healthy, 0 restarts, reportsv2.0.1.poll_spc_job1 ok, 0 raised). On 2.0.0 every run raised.ERRORor traceback lines since start. Alert polling 7 of 7.Outage window for SPC outlook processing on production: 05:55Z to 07:02Z, about 67 minutes. NWS warning alerts were unaffected throughout.
Closing. The pre-existing drift (rows whose
sent_atbelongs to another day's record) is left to settle as SPC issues new outlooks; nothing in the current data violates the per-day uniqueness the fix now relies on.