Skip to content

feat: net-new models + StaticFeed/ArcGIS/Archive clients (Workstream C / PR-2)#2

Merged
Reddimus merged 2 commits into
mainfrom
workstream-c/pr2-full-surface
May 17, 2026
Merged

feat: net-new models + StaticFeed/ArcGIS/Archive clients (Workstream C / PR-2)#2
Reddimus merged 2 commits into
mainfrom
workstream-c/pr2-full-surface

Conversation

@Reddimus
Copy link
Copy Markdown
Owner

Workstream C — PR-2 (spc-cpp full surface)

Completes the spc-cpp v0.1.0 surface on top of PR-1.

Net-new product models

Each carries its own product-specific severity mapper — none reuse the verbatim categorical severity_from_label (different label sets, per the locked decision):

  • convective.* — Day 4-8 probabilistic + conditional intensity (cig_severity_from_label CIG1..3).
  • fire_weather.*fire_severity_from_label ELEV/CRIT/EXTM.
  • watch.* — IEM spcwatch (TOR/SVR + hail/wind params).
  • mesoscale.* — MD metadata + geometry only (narrative deliberately NOT parsed).
  • storm_report.* — IEM LSR Point features.

Geometry

  • Net-new detail::parse_esri_rings, separate from the verbatim parse_rings. Tuned to match the verbatim outer-ring-only semantics: drops counter-clockwise Esri hole rings so the Polygon set is parity-exact with the GeoJSON path. The verbatim parse_rings is untouched (byte-identity gate depends on it).

Clients (Result<T>, pimpl, move-only)

  • StaticFeedClient (7 static feeds + day4-8), ArcGISClient (primary; ArcGISPager 2000-rec paging; convective queries request f=geojson so the verbatim parser gets its native shape), ArchiveClient (IEM; conservative RateLimiter + retry).
  • examples/ + Makefile run-*: parse_outlook / static_feed / arcgis / archive.

Verification (live upstreams)

  • All 3 network examples run against live sources: SPC static = 4 categorical features; ArcGIS = 4 categorical + 4 prob-tornado isopleths; IEM = 624 LSRs parsed.
  • test_arcgis.cpp: Esri-vs-GeoJSON PIP parity (risk #8) proven probe-for-probe over the live corpus. Empirical finding documented in-test: ArcGIS f=json vs f=geojson are independently quantized ~1.3 m apart with different vertex sequences, so strict ring equality is impossible by construction; the test asserts identical interior/exterior classification on a dense grid excluding a ~5 m boundary skip-band (a real divergence flips whole regions; quantization does not).
  • 23/23 ctest green; clang-format + cpp_auto_audit clean; single glaze::glaze (_deps has exactly one glaze tree).

Merges with a merge commit, then v0.1.0 is tagged (PR-3 FetchContent-pins it). Series: PR-0 ✓ → PR-1 ✓ → PR-2 (this) → PR-3 (spc-data refactor + byte-identity gate).

Reddimus added 2 commits May 17, 2026 02:00
…C / PR-2)

Completes the spc-cpp v0.1.0 surface.

Net-new models (own product-specific severity mappers — do NOT reuse
the verbatim categorical severity_from_label):
- convective.* — Day4-8 probabilistic + conditional intensity
  (cig_severity_from_label CIG1..3).
- fire_weather.* — fire_severity_from_label ELEV/CRIT/EXTM.
- watch.* — IEM spcwatch GeoJSON (TOR/SVR + hail/wind params).
- mesoscale.* — MD metadata + geometry ONLY (narrative not parsed).
- storm_report.* — IEM LSR Point features.

geo/common:
- net-new detail::parse_esri_rings, SEPARATE from the verbatim
  parse_rings. Tuned to MATCH the verbatim outer-ring-only semantics:
  it drops counter-clockwise Esri hole rings so the Polygon set is
  parity-exact with the GeoJSON path (the byte-identity gate depends
  on parse_rings being untouched; this makes the Esri adapter agree
  with it rather than expose raw Esri shape).
- detail::ring_signed_area helper.

spc_api clients (Result<T>, pimpl, move-only):
- StaticFeedClient (7 static feeds + day4-8), ArcGISClient (primary;
  ArcGISPager 2000-rec paging; convective queries request f=geojson
  so the verbatim parser consumes its native shape), ArchiveClient
  (IEM; conservative RateLimiter + retry).
- spc/spc.hpp umbrella expanded to the full surface.

Examples + Makefile run-* : parse_outlook, static_feed, arcgis,
archive. All three network examples verified against LIVE upstreams
(SPC static: 4 cat features; ArcGIS: 4 cat + 4 prob isopleths; IEM:
624 LSRs).

Tests: test_arcgis.cpp added — Esri-vs-GeoJSON PIP parity (risk #8)
proven probe-for-probe over the live corpus (with a ~5 m skip band
because ArcGIS f=json vs f=geojson are independently quantized ~1.3 m
apart — documented in the test), plus full net-new model coverage.
23/23 green; clang-format + cpp_auto_audit clean; single glaze::glaze
(_deps has exactly one glaze tree).
install(EXPORT ... NAMESPACE spc::) only creates spc::spc for installed
find_package(spc) consumers. A FetchContent consumer (e.g. the spc-data
refactor in Workstream C / PR-3) only sees the bare 'spc' target and
fails 'target spc::spc not found'. Add namespaced ALIAS targets so
spc::spc (and spc::spc_*) resolve identically either way — the
idiomatic fix matching how the rest of the estate vendors these SDKs.
Additive; build + 23/23 ctest still green.
@Reddimus Reddimus merged commit c81d497 into main May 17, 2026
3 checks passed
@Reddimus Reddimus deleted the workstream-c/pr2-full-surface branch May 17, 2026 09:10
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