Skip to content

mostlyright.core.schemas.observation_merged

mostlyright.core.schemas.observation_merged

Section titled “mostlyright.core.schemas.observation_merged”

Merged observation-grain schema (schema.observation.merged.v1).

Phase 30 (30-01). The frame-level identity contract for obs(granularity="observation") when the query is UNPINNED — the merged per-report rows produced by _dispatch_strategy + merge_observations, trimmed to the queried UTC window, pass-through with observation_type distinguishing METAR/SPECI (NO bucketing/resampling).

Why a DISTINCT schema (D-03, D-15). A merged frame’s df.attrs["source"] is the fused-policy tag "merged.live_v1", NOT a single upstream source — but its per-row source column is the TRUTHFUL bare parser tag (awc/iem/ghcnh). The canonical single-source schema.observation.v1 enforces per-row source == df.attrs["source"] (equality), so it correctly REJECTS a merged frame (the CWOP parity firewall stays intact — observation.py is NEVER modified). This schema instead declares:

  • _registered_sources = {"merged.live_v1"} — the ONLY frame-level identity it accepts. Declared as the PLURAL set (no singular _registered_source) so the validator’s source_drift_allowed audit trap (validator.py:493-500, documented at cwop/_schema.py:91-97) never fires on a clean merged read.
  • _registered_row_sources = {"awc","iem","ghcnh"} — a NEW ClassVar the validator (30-01-4) reads to switch the per-row source check from equality-to-attrs to MEMBERSHIP in this set. Absent (None) on every other schema, so satellite/forecast.station/cwop are untouched.

Columns are declared over the ACTUAL observation-grain row keys that obs(granularity="observation") emits (the merged parser row dicts — see weather/_iem.py:246-277), so a genuine merged frame passes ALL four validator checks (source, column-presence, dtype, enum), not just the source check.

MERGED_LIVE_V1Frame-level fused-policy identity tag stamped on UNPINNED obs(granularity="observation") frames.
MergedObservationSchema()schema.observation.merged.v1 — merged per-report observation rows.

mostlyright.core.schemas.observation_merged.MERGED_LIVE_V1 : str = ‘merged.live_v1’

Section titled “mostlyright.core.schemas.observation_merged.MERGED_LIVE_V1 : str = ‘merged.live_v1’”

Frame-level fused-policy identity tag stamped on UNPINNED obs(granularity="observation") frames. Distinct from any single upstream source; single-source pinned schemas REJECT it.

class mostlyright.core.schemas.observation_merged.MergedObservationSchema

Section titled “class mostlyright.core.schemas.observation_merged.MergedObservationSchema”

Bases: Schema

schema.observation.merged.v1 — merged per-report observation rows.

Accepts the fused-policy frame identity merged.live_v1 while allowing the per-row source column to carry any of the bare parser tags {awc, iem, ghcnh} (membership, not equality — enforced by the validator via _registered_row_sources).

COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘station_code’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘ICAO/ASOS station ID (e.g. KNYC)’), ColumnSpec(name=‘observed_at’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘ISO-8601 UTC observation valid time (string, as parsers emit)’), ColumnSpec(name=‘observation_type’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘METAR’, ‘SPECI’), notes=‘METAR | SPECI’), ColumnSpec(name=‘source’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘bare parser tag (awc/iem/ghcnh); membership-checked, not equality’), ColumnSpec(name=‘temp_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘temp_f’, dtype=‘float64’, units=‘fahrenheit’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘dewpoint_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘dewpoint_f’, dtype=‘float64’, units=‘fahrenheit’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘wind_dir_degrees’, dtype=‘float64’, units=‘degrees’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘wind_speed_kt’, dtype=‘float64’, units=‘kt’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘wind_gust_kt’, dtype=‘float64’, units=‘kt’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘altimeter_inhg’, dtype=‘float64’, units=‘inHg’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sea_level_pressure_mb’, dtype=‘float64’, units=‘mb’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘visibility_miles’, dtype=‘float64’, units=‘miles’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘precip_1hr_inches’, dtype=‘float64’, units=‘inches’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_1’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_1_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_2’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_2_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_3’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_3_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_4’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_4_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘weather_codes’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘peak_wind_gust_kt’, dtype=‘float64’, units=‘kt’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘peak_wind_dir’, dtype=‘float64’, units=‘degrees’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘peak_wind_time’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘snow_depth_inches’, dtype=‘float64’, units=‘inches’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘qc_field’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘raw_metar’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘raw METAR text if source has it; null for structured-only sources’)]

Section titled “COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘station_code’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘ICAO/ASOS station ID (e.g. KNYC)’), ColumnSpec(name=‘observed_at’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘ISO-8601 UTC observation valid time (string, as parsers emit)’), ColumnSpec(name=‘observation_type’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘METAR’, ‘SPECI’), notes=‘METAR | SPECI’), ColumnSpec(name=‘source’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘bare parser tag (awc/iem/ghcnh); membership-checked, not equality’), ColumnSpec(name=‘temp_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘temp_f’, dtype=‘float64’, units=‘fahrenheit’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘dewpoint_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘dewpoint_f’, dtype=‘float64’, units=‘fahrenheit’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘wind_dir_degrees’, dtype=‘float64’, units=‘degrees’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘wind_speed_kt’, dtype=‘float64’, units=‘kt’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘wind_gust_kt’, dtype=‘float64’, units=‘kt’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘altimeter_inhg’, dtype=‘float64’, units=‘inHg’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sea_level_pressure_mb’, dtype=‘float64’, units=‘mb’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘visibility_miles’, dtype=‘float64’, units=‘miles’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘precip_1hr_inches’, dtype=‘float64’, units=‘inches’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_1’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_1_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_2’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_2_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_3’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_3_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_4’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=”), ColumnSpec(name=‘sky_base_4_ft’, dtype=‘float64’, units=‘ft’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘weather_codes’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘peak_wind_gust_kt’, dtype=‘float64’, units=‘kt’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘peak_wind_dir’, dtype=‘float64’, units=‘degrees’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘peak_wind_time’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘snow_depth_inches’, dtype=‘float64’, units=‘inches’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘qc_field’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘raw_metar’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘raw METAR text if source has it; null for structured-only sources’)]”