3.6 KiB
Normalizer Internals
Purpose
Normalizers convert raw provider events into canonical weather events. They are weather-domain mapping code and should stay independent of runtime wiring, source polling, and sink persistence.
Detailed package conventions live in internal/normalizers/doc.go.
Inputs And Outputs
Inputs are raw feed events whose schemas identify provider payload shape.
Outputs are canonical feed events using model payloads and weather.*
schemas.
Current mappings:
| Raw schema | Canonical schema |
|---|---|
raw.nws.observation.v1 |
weather.observation.v1 |
raw.openmeteo.current.v1 |
weather.observation.v1 |
raw.openweather.current.v1 |
weather.observation.v1 |
raw.nws.hourly.forecast.v1 |
weather.forecast.v1 |
raw.nws.narrative.forecast.v1 |
weather.forecast.v1 |
raw.openmeteo.hourly.forecast.v1 |
weather.forecast.v1 |
raw.nws.forecast_discussion.v1 |
weather.forecast_discussion.v1 |
raw.nws.weatherstories.v1 |
weather.weather_story.v1 |
raw.nws.alerts.v1 |
weather.alert.v1 |
raw.spc.convective_outlook.v1 |
weather.outlook.v1 |
Boundaries
- Normalizers match by
Event.Schema. - Normalizers decode raw payloads into provider structs.
- Normalizers map provider data into canonical
modelpayloads. - Normalizers do not fetch network data, read config, route events, or write sinks.
- Shared cross-provider behavior belongs in
internal/normalizers/common. - Provider-specific helper logic shared with sources belongs in
internal/providers/<provider>.
Config Fields Used
Normalizers do not read config. They operate only on incoming events.
External Adapters Used
Runtime composition creates feedkit's normalize processor with
RequireMatch=false. Events without a matching normalizer pass through
unchanged.
Weatherfeeder registers normalizers in a stable order:
- NWS
- Open-Meteo
- OpenWeather
- SPC
The current normalizers avoid ambiguous matches by using schema equality.
The SPC outlook normalizer decodes the raw multi-document bundle, maps each
GeoJSON feature to a canonical outlook, and enriches all outlooks for a day with
the matching print-page headline, summary, and discussion. It preserves compact
GeoJSON feature geometry and computes containsLocation with
internal/geo.ContainsPoint using the source-configured point. Boundary points
count as contained, and all polygons are preserved whether or not they contain
the point.
State
Normalizers should be stateless. Shared helpers should be deterministic and free of I/O.
Failure Behavior
Malformed required raw payload data should produce contextual errors from the owning normalizer. Successful normalization validates the output event before it continues through the pipeline.
internal/normalizers/common.Finalize preserves the input event envelope except
for schema, payload, and effective time. It also rounds canonical float values
to four digits after the decimal point.
Tests To Inspect
internal/normalizers/builtins_test.go- provider normalizer tests under
internal/normalizers/nws - provider normalizer tests under
internal/normalizers/openmeteo - provider normalizer tests under
internal/normalizers/openweather - provider normalizer tests under
internal/normalizers/spc - common helper tests under
internal/normalizers/common
Invariants
- Match by schema constants from
standards. - Preserve the event envelope except for intentional canonical changes.
- Produce canonical payload structs from
model. - Validate normalized events before returning them.
- Keep normalizers independent of sources, sinks, config loading, and runtime composition.