Skip to content

feat(weather-recon): Phase 1 — curated stations + Directus weather schema (#184)#191

Merged
robbiebyrd merged 9 commits into
mainfrom
feat/weather-recon-phase1
Jul 12, 2026
Merged

feat(weather-recon): Phase 1 — curated stations + Directus weather schema (#184)#191
robbiebyrd merged 9 commits into
mainfrom
feat/weather-recon-phase1

Conversation

@robbiebyrd

Copy link
Copy Markdown
Collaborator

Phase 1 of the Weather app (#184): new packages/tools/weather-recon package — curated station reference table + the three Directus weather collections. Design spec: plans/weather-app-design.md.

What's in here

  • data/stations.csv — 188 curated METAR stations (US 153 / CA 17 / MX 18, every state except Delaware) built from NOAA isd-history.csv by scripts/build_stations.py; each row carries isd_id (USAF-WBAN), the NCEI global-hourly join key Phase 2's observations flow needs. Curation notes: substituted CYQB→CWQB, KMDT→KCXY, KRSW→KFMY (no 2001-09 ISD coverage under the primary ICAO); dropped KHOU/KBTR/KFLL/KGPT.
  • weather_recon/stations.py — validated CSV loader (test_committed_csv_is_valid gates the committed file).
  • weather_recon/directus.py — flight-recon's client ported verbatim + weather COLLECTIONS (weather_stations / weather_observations / weather_forecasts) + delete_all that derives its filter from the collection PK.
  • weather_recon/flow.pyload-weather-stations Prefect flow: validate → ensure schema → idempotent reload.
  • Dockerfile / deploy.py / README — mirrors flight-recon (weather-recon-k8s pool; worker Deployment + secret are infra-repo follow-ups).

Verification

  • 22/22 pytest, ruff clean.
  • Live-verified against prod Directus: three collections created, 188 rows loaded, KORD/CYYZ/MMMX spot-checked, idempotent re-run confirmed (delete 188 → insert 188, no dupes), per-country counts match.

Follow-ups (Phase 2)

wfo/nws_zone/ghcn_id station columns (added via ensure_collection's missing-field path), observations/radar/forecasts/almanac flows, fail-fast env check in _client, insert_many fields param → PK-derived, KMRY placeholder-USAF (999999-23259) join check.

🤖 Generated with Claude Code

https://claude.ai/code/session_01W179bqEPFP92a3JrsPkD5c

Robbie Byrd and others added 9 commits July 12, 2026 19:32
Adds scripts/build_stations.py (pick_station_rows/station_record pure
functions, TDD'd) and the committed data/stations.csv it generates from
NOAA's isd-history.csv: 187 stations covering 2001-09-09..12 (US 152,
CA 17, MX 18).

7 of the original 175 curated ICAOs lacked ISD coverage for the window;
resolved by checking data/isd-history.csv for a same-city substitute:
- CYQB (Quebec City) -> substituted CWQB (same airport, alternate
  identifier, continuous 1955-2025 coverage)
- KMDT (Harrisburg) -> substituted KCXY (Harrisburg Capital City,
  covers 2000-2003)
- KHOU (Houston Hobby) -> dropped; KIAH already covers Houston in the
  curated set
- KBTR (Baton Rouge), KFLL (Fort Lauderdale), KGPT (Gulfport-Biloxi),
  KRSW (SW Florida/Fort Myers) -> dropped; no same-city ISD row with
  2001-09 coverage found (each has a pre-1998/pre-2000 gap and a
  post-2005/2006 row, but nothing spanning 2001)

data/isd-history.csv (~3 MB NOAA cache) is gitignored, not committed.

Co-Authored-By: Claude Fable 5 <[email protected]>
Task review caught that the KRSW drop was based on a wrong data read:
data/isd-history.csv row 722106-12835 "PAGE FIELD AIRPORT" (KFMY,
26.585,-81.861) covers 19430101-20250826, i.e. full 2001-09 coverage at
Fort Myers. The original grep for "FORT MYERS" only matched the retired
999999-12835 row whose name includes the city; the covering row's name
field ("PAGE FIELD AIRPORT") does not, so it was missed.

Adds KFMY to CURATED_ICAOS as the KRSW substitute (like CYQB->CWQB /
KMDT->KCXY), regenerates data/stations.csv (187 -> 188 stations: US 153,
CA 17, MX 18), and updates the stale curated-list header comment to the
real counts.

Co-Authored-By: Claude Fable 5 <[email protected]>
TDD implementation of load_stations() function that validates and parses
stations.csv into typed dicts. Includes 10 test cases covering valid rows,
type conversion, empty elevation handling, and comprehensive error validation
(lat/lon ranges, country codes, required fields, duplicates).

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01W179bqEPFP92a3JrsPkD5c
Implement DirectusClient with weather collections (weather_stations,
weather_observations, weather_forecasts). Ported from flight_recon with
three changes: new module docstring, weather-specific COLLECTIONS dict,
and delete_all method (vs flight_date windowed delete_window).

Co-Authored-By: Claude Fable 5 <[email protected]>
weather_forecasts has no station_id field; derive the _nnull delete
filter from the collection's primary key instead.

Co-Authored-By: Claude Fable 5 <[email protected]>
@github-actions

Copy link
Copy Markdown

Playwright E2E — 1 passed · 0 failed · 0 flaky · 0 skipped

Full report

@robbiebyrd robbiebyrd merged commit 8f71549 into main Jul 12, 2026
6 checks passed
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