From 2dddc1a67bbae6d37392a7e479e1c4053562aa31 Mon Sep 17 00:00:00 2001 From: Matt Johnson Date: Thu, 16 Jul 2026 17:30:40 +0000 Subject: [PATCH] fix(satpass): default feed_source to native; correct misleading config comments Central is retired -- its NATS broker (nats://central.echo6.mesh:4222) no longer exists -- but SatpassConfig.feed_source still defaulted to "central", overriding the _SourcedFeed mixin default of "native". A fresh install that enabled satpass got a silently dead adapter. The dashboard reinforced it: Environment.tsx seeded feed_source 'central' and labelled the adapter "via Central". Also corrects comments that documented the opposite of the code: the adapter_config keys usgs_quake.global_mag_floor / regional_mag_floor were labelled "CENTRAL-PATH ONLY", but notifications/gating/quake.py reads them unconditionally in the native path. Following those comments would have led someone to delete live config keys. - config.py: SatpassConfig.feed_source "central" -> "native" + docstring - adapter_config/defaults.py: correct the two "CENTRAL-PATH ONLY" comments - Environment.tsx: seed 'native'; reword the satpass subtitle - tests: assert the native default; pin central explicitly where a test exercises the central path or the feed_source flip Suite: 2337 passed, 6 pre-existing failures (stale SCHEMA_VERSION x3, expired TLE fixtures x2, one order-dependent), no new failures. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/pages/Environment.tsx | 4 ++-- work/meshai/adapter_config/defaults.py | 4 ++-- work/meshai/config.py | 18 ++++++++++-------- work/tests/test_env_hot_reload.py | 9 ++++++--- work/tests/test_satpass_registration.py | 12 ++++++------ 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/work/dashboard-frontend/src/pages/Environment.tsx b/work/dashboard-frontend/src/pages/Environment.tsx index 58db532..aae7b6d 100644 --- a/work/dashboard-frontend/src/pages/Environment.tsx +++ b/work/dashboard-frontend/src/pages/Environment.tsx @@ -66,7 +66,7 @@ const SATPASS_NATIVE_DEFAULT: EnvConfig['satpass'] = { window_hours: 24, tle_refresh_seconds: 21600, broadcast_lead_seconds: 3600, - feed_source: 'central', + feed_source: 'native', } // Sane defaults for the ipaws block so a GET payload predating the IPAWS @@ -304,7 +304,7 @@ const META: Record = { usgs_quake: { label: 'USGS Earthquakes', subtitle: 'Seismic events from the USGS feed', health: 'usgs_quake', hasCentral: true, nativeOnly: false, hasKey: true }, usgs: { label: 'USGS Stream Gauges', subtitle: 'River and stream water levels', health: 'usgs', hasCentral: true, nativeOnly: false, hasKey: true }, avalanche: { label: 'Avalanche Advisories', subtitle: 'Backcountry avalanche danger ratings', health: 'avalanche', hasCentral: true, nativeOnly: false, hasKey: true }, - satpass: { label: 'Satellite Passes', subtitle: 'Observer pass alerts via Central', health: 'satpass', hasCentral: true, nativeOnly: false, hasKey: true }, + satpass: { label: 'Satellite Passes', subtitle: 'Observer pass alerts from native TLE tracking', health: 'satpass', hasCentral: true, nativeOnly: false, hasKey: true }, ipaws: { label: 'FEMA IPAWS civil alerts', subtitle: 'Evacuations, AMBER, HazMat, 911 outages (non-weather)', health: 'ipaws', hasCentral: false, nativeOnly: true, hasKey: false }, } diff --git a/work/meshai/adapter_config/defaults.py b/work/meshai/adapter_config/defaults.py index 9f702ba..0318dab 100644 --- a/work/meshai/adapter_config/defaults.py +++ b/work/meshai/adapter_config/defaults.py @@ -105,12 +105,12 @@ REGISTRY: dict[tuple[str, str], dict[str, Any]] = { ("usgs_quake", "global_mag_floor"): { "default": 3.0, # quake_handler.py:69 "type": "float", - "description": "Global magnitude floor for unconditional broadcasts. CENTRAL-PATH ONLY (central/quake_handler.py); the native feed_source gates on environmental.usgs_quake.min_magnitude instead.", + "description": "Global magnitude floor for unconditional broadcasts. Gates the shared native gating decider (meshai.notifications.gating.quake.decide), read regardless of feed_source.", }, ("usgs_quake", "regional_mag_floor"): { "default": 2.5, # quake_handler.py:70 "type": "float", - "description": "Reduced magnitude floor for quakes within regional_radius_mi of centroid. CENTRAL-PATH ONLY (central/quake_handler.py); the native feed_source gates on environmental.usgs_quake.min_magnitude instead.", + "description": "Reduced magnitude floor for quakes within regional_radius_mi of centroid. Gates the shared native gating decider (meshai.notifications.gating.quake.decide), read regardless of feed_source.", }, ("usgs_quake", "escalate_mag_floor"): { "default": 5.0, # quake_handler.py:76 diff --git a/work/meshai/config.py b/work/meshai/config.py index 52cd438..8e1dab6 100644 --- a/work/meshai/config.py +++ b/work/meshai/config.py @@ -444,8 +444,10 @@ class USGSQuakeConfig(_SourcedFeed): # Native-path broadcast magnitude floor: the native adapter # (env/usgs_quake.py) gates on this. THIS is the GUI-editable quake # magnitude floor for the native feed_source. (The adapter_config - # REGISTRY keys usgs_quake.global_mag_floor / regional_mag_floor apply - # only to the Central-firehose path in central/quake_handler.py.) + # REGISTRY keys usgs_quake.global_mag_floor / regional_mag_floor are + # separate: they gate the shared gating decider, + # meshai.notifications.gating.quake.decide(), which both the native + # path and central/quake_handler.py delegate to.) min_magnitude: float = 2.5 # [west, south, east, north] -- Magic Valley -> Borah Peak -> Yellowstone bbox: list = field(default_factory=lambda: [-115.5, 42.0, -110.0, 45.2]) @@ -522,15 +524,15 @@ class FIRMSConfig(_SourcedFeed): class SatpassConfig(_SourcedFeed): """Satellite pass prediction settings. - Historically a Central-only feed (`feed_source="central"`). The native - path (`feed_source="native"`) adds a Celestrak TLE fetcher - (`env.tle_fetch`) and a native SGP4 predictor; the fields below feed - those. `feed_source` default stays "central" — the flip to "native" - happens at cutover, not here. + Native (`feed_source="native"`) is the default and only supported path: + a Celestrak TLE fetcher (`env.tle_fetch`) plus a native SGP4 predictor; + the fields below feed those. Central is RETIRED — its NATS broker + (`nats://central.echo6.mesh:4222`) no longer exists — so this no longer + overrides the `_SourcedFeed` mixin default. """ enabled: bool = False - feed_source: str = "central" + feed_source: str = "native" # -- native path (TLE fetch + SGP4 predictor) ----------------------------- # Ground stations the predictor computes passes for; each entry is a diff --git a/work/tests/test_env_hot_reload.py b/work/tests/test_env_hot_reload.py index 286cae6..24f09b0 100644 --- a/work/tests/test_env_hot_reload.py +++ b/work/tests/test_env_hot_reload.py @@ -114,9 +114,12 @@ def test_feed_source_flip_to_central_requires_restart_and_does_not_swap(): def test_feed_source_flip_from_central_to_native_requires_restart(): - # satpass defaults feed_source="central"; flip it to native. - store = EnvironmentalStore(_cfg()) - assert "satpass" not in store._adapters # central by default -> no native instance + # satpass now defaults to feed_source="native", so pin the starting state + # to "central" explicitly -- this exercises the flip, not the default. + base_cfg = _cfg() + base_cfg.satpass = dataclasses.replace(base_cfg.satpass, feed_source="central") + store = EnvironmentalStore(base_cfg) + assert "satpass" not in store._adapters # central -> no native instance new_cfg = _cfg() new_cfg.satpass = dataclasses.replace( diff --git a/work/tests/test_satpass_registration.py b/work/tests/test_satpass_registration.py index 1d3464d..99d9ddf 100644 --- a/work/tests/test_satpass_registration.py +++ b/work/tests/test_satpass_registration.py @@ -1,7 +1,7 @@ """Tests for satpass adapter registration on EnvironmentalConfig. Verifies: - - SatpassConfig exists and defaults to feed_source="central" + - SatpassConfig exists and defaults to feed_source="native" - EnvironmentalConfig.satpass field is present and correctly typed - _subject_owned() includes central.sat.* subjects when satpass is registered - adapter_config REGISTRY contains satpass keys with valid types @@ -15,7 +15,7 @@ import pytest def test_satpass_config_exists(): from meshai.config import SatpassConfig cfg = SatpassConfig() - assert cfg.feed_source == "central" + assert cfg.feed_source == "native" assert cfg.enabled is False @@ -37,10 +37,10 @@ def test_environmental_config_has_satpass(): assert isinstance(env.satpass, SatpassConfig) -def test_environmental_satpass_default_central(): +def test_environmental_satpass_default_native(): from meshai.config import EnvironmentalConfig env = EnvironmentalConfig() - assert env.satpass.feed_source == "central" + assert env.satpass.feed_source == "native" # -- adapter_config REGISTRY -------------------------------------------------- @@ -87,10 +87,10 @@ def test_yaml_parsing_satpass(): from meshai.config import SatpassConfig, _dict_to_dataclass, EnvironmentalConfig import yaml - yaml_str = "environmental:\n satpass:\n enabled: true\n feed_source: central\n" + yaml_str = "environmental:\n satpass:\n enabled: true\n feed_source: native\n" data = yaml.safe_load(yaml_str) env = _dict_to_dataclass(EnvironmentalConfig, data["environmental"]) assert isinstance(env.satpass, SatpassConfig) assert env.satpass.enabled is True - assert env.satpass.feed_source == "central" + assert env.satpass.feed_source == "native"