mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 17:31:34 +00:00
fix: wire adapter name mismatch in satpass event path
Central publishes sat events with wire adapter names celestrak_tle, n2yo_visualpasses, and satpass_predict. Task C's routing matched on sat_tles/sat_tle/sat_passes — names that exist nowhere on the wire — so every sat event was silently dropped at three kill points: 1. CENTRAL_ADAPTER_TO_SOURCE map (consumer.py line ~216) 2. _normalize dispatch conditionals (consumer.py line ~549) 3. satpass_handler adapter guard (satpass_handler.py line ~118) All three now use the correct wire names. Both handlers also gain an enabled gate that returns None when satpass.enabled=false, logging at INFO once per process lifetime via a _disabled_logged function flag. Existing test fixtures updated for the new adapter names and the enabled gate (cfg.enabled=True in mock, _disabled_logged cleanup). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4a17c7b702
commit
be4443feb9
5 changed files with 51 additions and 14 deletions
|
|
@ -214,9 +214,9 @@ CENTRAL_ADAPTER_TO_SOURCE: dict[str, str] = {
|
|||
"itd_511": "roads511",
|
||||
"avalanche_org": "avalanche",
|
||||
"firms": "firms",
|
||||
"sat_passes": "satpass",
|
||||
"sat_tles": "satpass",
|
||||
"sat_tle": "satpass",
|
||||
"celestrak_tle": "satpass",
|
||||
"n2yo_visualpasses": "satpass",
|
||||
"satpass_predict": "satpass",
|
||||
}
|
||||
|
||||
# Central hierarchical category prefix -> meshai flat category.
|
||||
|
|
@ -546,10 +546,10 @@ class CentralConsumer:
|
|||
# commit #5 (env_reporter). Closes the v0.5.13
|
||||
# silent-drop on central.fire.hotspot.> (audit doc
|
||||
# finding #2).
|
||||
elif inner.get("adapter") in ("sat_tles", "sat_tle"):
|
||||
elif inner.get("adapter") == "celestrak_tle":
|
||||
from meshai.central.tle_handler import handle_tle
|
||||
synthesized = handle_tle(envelope, subject, data=data) or None
|
||||
elif inner.get("adapter") == "sat_passes":
|
||||
elif inner.get("adapter") in ("n2yo_visualpasses", "satpass_predict"):
|
||||
from meshai.central.satpass_handler import handle_satpass
|
||||
synthesized = handle_satpass(envelope, subject, data=data) or None
|
||||
elif inner.get("adapter") == "firms":
|
||||
|
|
|
|||
|
|
@ -115,8 +115,16 @@ def handle_satpass(envelope: dict, subject: str,
|
|||
inner = envelope.get("data") or {}
|
||||
adapter = inner.get("adapter") or ""
|
||||
|
||||
# Only handle sat_passes adapter
|
||||
if adapter != "sat_passes":
|
||||
# Only handle pass prediction adapters (wire names from Central)
|
||||
if adapter not in ("n2yo_visualpasses", "satpass_predict"):
|
||||
return None
|
||||
|
||||
# Enabled gate: silently drop when disabled, log once at INFO
|
||||
cfg = adapter_config.satpass
|
||||
if not getattr(cfg, "enabled", False):
|
||||
if not getattr(handle_satpass, "_disabled_logged", False):
|
||||
logger.info("satpass disabled; sat pass events dropped")
|
||||
handle_satpass._disabled_logged = True
|
||||
return None
|
||||
|
||||
d = inner.get("data") or {}
|
||||
|
|
@ -142,9 +150,6 @@ def handle_satpass(envelope: dict, subject: str,
|
|||
logger.debug("satpass_handler: could not parse aos time")
|
||||
return None
|
||||
|
||||
# Config filters
|
||||
cfg = adapter_config.satpass
|
||||
|
||||
# Observer filter (empty = all)
|
||||
observers = getattr(cfg, "observers", []) or []
|
||||
if observers and observer not in observers:
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@ def handle_tle(envelope: dict, subject: str,
|
|||
inner = envelope.get("data") or {}
|
||||
adapter = inner.get("adapter") or ""
|
||||
|
||||
# Enabled gate: silently drop when disabled, log once at INFO
|
||||
try:
|
||||
from meshai.adapter_config import adapter_config
|
||||
if not getattr(adapter_config.satpass, "enabled", False):
|
||||
if not getattr(handle_tle, "_disabled_logged", False):
|
||||
logger.info("satpass disabled; sat TLE events dropped")
|
||||
handle_tle._disabled_logged = True
|
||||
return None
|
||||
except Exception:
|
||||
pass # adapter_config may not be initialised in tests
|
||||
|
||||
# Accept both sat_tles and sat_passes adapter (Central may tag either)
|
||||
d = inner.get("data") or {}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,20 @@ import pytest
|
|||
from meshai.persistence import get_db
|
||||
|
||||
|
||||
def _enable_satpass():
|
||||
"""Set satpass.enabled=true for TLE handler tests."""
|
||||
conn = get_db()
|
||||
conn.execute(
|
||||
"UPDATE adapter_config SET value_json='true' "
|
||||
"WHERE adapter='satpass' AND key='enabled'"
|
||||
)
|
||||
try:
|
||||
from meshai.adapter_config import invalidate_cache
|
||||
invalidate_cache()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
# Well-known ISS TLE (epoch ~2024-06-15)
|
||||
ISS_LINE1 = "1 25544U 98067A 24167.54791667 .00016717 00000-0 10270-3 0 9003"
|
||||
ISS_LINE2 = "2 25544 51.6400 187.5200 0001234 35.0000 325.0000 15.49920000 07"
|
||||
|
|
@ -56,6 +70,7 @@ class TestTLEUpsert:
|
|||
"""T1: TLE upsert latest-wins on epoch."""
|
||||
|
||||
def test_newer_epoch_updates(self):
|
||||
_enable_satpass()
|
||||
from meshai.central.tle_handler import handle_tle
|
||||
conn = get_db()
|
||||
now = int(time.time())
|
||||
|
|
@ -67,7 +82,7 @@ class TestTLEUpsert:
|
|||
# Send newer TLE
|
||||
env = {
|
||||
"data": {
|
||||
"adapter": "sat_tles",
|
||||
"adapter": "celestrak_tle",
|
||||
"data": {
|
||||
"norad_id": 25544,
|
||||
"satellite_name": "ISS (ZARYA)",
|
||||
|
|
@ -84,6 +99,7 @@ class TestTLEUpsert:
|
|||
assert row["line2"] == "NEW2"
|
||||
|
||||
def test_older_epoch_skipped(self):
|
||||
_enable_satpass()
|
||||
from meshai.central.tle_handler import handle_tle
|
||||
conn = get_db()
|
||||
now = int(time.time())
|
||||
|
|
@ -95,7 +111,7 @@ class TestTLEUpsert:
|
|||
# Send older TLE — should be skipped
|
||||
env = {
|
||||
"data": {
|
||||
"adapter": "sat_tles",
|
||||
"adapter": "celestrak_tle",
|
||||
"data": {
|
||||
"norad_id": 25544,
|
||||
"satellite_name": "ISS (ZARYA)",
|
||||
|
|
@ -112,10 +128,11 @@ class TestTLEUpsert:
|
|||
|
||||
def test_returns_none_always(self):
|
||||
"""TLE handler is storage-only, never returns wire."""
|
||||
_enable_satpass()
|
||||
from meshai.central.tle_handler import handle_tle
|
||||
env = {
|
||||
"data": {
|
||||
"adapter": "sat_tles",
|
||||
"adapter": "celestrak_tle",
|
||||
"data": {
|
||||
"norad_id": 99999,
|
||||
"satellite_name": "TEST",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ def _envelope(norad_id=25544, sat_name="ISS", observer="Boise",
|
|||
"source": "central",
|
||||
"id": f"pass-{norad_id}-{aos}",
|
||||
"data": {
|
||||
"adapter": "sat_passes",
|
||||
"adapter": "n2yo_visualpasses",
|
||||
"category": "sat.pass",
|
||||
"severity": 0,
|
||||
"data": {
|
||||
|
|
@ -44,11 +44,15 @@ def mock_db():
|
|||
def mock_adapter_config():
|
||||
"""Mock adapter_config.satpass."""
|
||||
cfg = MagicMock()
|
||||
cfg.enabled = True
|
||||
cfg.observers = [] # empty = all observers
|
||||
cfg.min_elevation = 30
|
||||
cfg.norad_ids = [] # empty = all satellites
|
||||
with patch("meshai.central.satpass_handler.adapter_config") as mock:
|
||||
mock.satpass = cfg
|
||||
from meshai.central.satpass_handler import handle_satpass
|
||||
if hasattr(handle_satpass, "_disabled_logged"):
|
||||
del handle_satpass._disabled_logged
|
||||
yield cfg
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue