feat(streamer): weather subscription channel — obs snapshot + windowed tick + on-demand forecasts (#184)#197
Merged
Merged
Conversation
Models + Postgres query layer for the new streamer weather channel (weather_observations/weather_forecasts, populated by packages/tools/weather-recon). Nullable numerics scan as *float64/*int straight into the model (no COALESCE, matching item.go's CalcDuration/Sort precedent); nullable text uses the existing derefStr pattern. No db-layer tests, per repo convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W179bqEPFP92a3JrsPkD5c
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mirrors the flights pattern for the const/window/horizon plumbing and the usenet pattern for the tick's Postgres read: weather observations and forecasts are sparse enough (usenet/news window scale) to read Postgres directly on the tick rather than warming a Redis cache. SendWeather suppresses empty batches; SendWeatherForecast always sends (even with a nil forecast) so the client sees an explicit "no forecast for this zone" rather than ambiguous silence. Renamed usenetTickTimeout -> pgTickTimeout since weather now shares it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W179bqEPFP92a3JrsPkD5c
Wires the weather channel into the ws.go handler: knownChannel accepts "weather"; sendWeatherSnapshot (CurrentWeatherObs) is wired into both sendChannelSnapshot (subscribe) and sendSubscribedSnapshots (init/seek); a new weather_forecast message validates the zone against the UGC zone shape before it reaches a SQL LIKE, silently drops when not subscribed or the zone is invalid (mirroring flights_history's gating), and otherwise replies via SendWeatherForecast. Also fixes a known test oversight by adding the previously-missing "flights" channel (alongside "weather") to TestWSHandlerAllChannelsSubscribeIndependently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W179bqEPFP92a3JrsPkD5c
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
✅ Playwright E2E — 1 passed · 0 failed · 0 flaky · 0 skipped |
This was referenced Jul 13, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 3 of the Weather app (#184): the streamer's
weathersubscription channel. Clock-synced conditions and forecasts now flow over the WebSocket — live-verified end-to-end against production data (all 8 checks, including KJFK's 9/11 morning at 21.1 °C / FEW / 16 km and the real OKX zone forecast text).What's in here
model/weather.go+ 4 Postgres queries — pointer-nullable scanning throughout (no COALESCE-to-zero: 0 °C is a real temperature),DISTINCT ONlatest-per-station snapshot, NULL-zone guard on the tick query.weatherchannel const, 600 s window, usenet-shaped Postgres tick branch (lock discipline: plan undermu, query and send outside), one combinedweatherframe (windowed obs + newly-issued forecast segments), suppressed when empty.{"type":"weather_forecast","zone","id"}request with^[A-Z]{2}Z\d{3}$validation (also blocks LIKE-wildcard injection), silent drop on invalid/unsubscribed, explicit empty reply when no product exists. Also fixes a latent test omission:flights(andweather) added to the all-channels subscribe test.plans/weather-app-design.md) — flagging for reviewVerification
go test ./...,-raceon the weather tests, vet, gofmt all clean; final review traced mid-tick-seek ordering, Close-during-query, and horizon races (duplicates-only-never-gaps, matching existing channels). Existing frontend untouched — additive-only wire changes (omitemptyon both new fields), confirmed no new frames reach clients that don't subscribe.Phase-4 client contract notes (carried to the frontend PR)
Clear weather state on seek and keep max-
start_dateper station (late stale windows carry fresh ids); start request ids at 1 (id:0is omitted by the envelope); pre-init requests silently drop (existing convention).🤖 Generated with Claude Code
https://claude.ai/code/session_01W179bqEPFP92a3JrsPkD5c