diff --git a/meshai/adapter_config/defaults.py b/meshai/adapter_config/defaults.py index 3198729..1d8d6e4 100644 --- a/meshai/adapter_config/defaults.py +++ b/meshai/adapter_config/defaults.py @@ -630,6 +630,11 @@ REGISTRY: dict[tuple[str, str], dict[str, Any]] = { "type": "bool", "description": "Dry-run mode: log wire text at INFO with DRY-RUN prefix instead of dispatching. Default true so satpass re-enables inert.", }, + ("satpass", "max_aos_horizon_hours"): { + "default": 24, + "type": "int", + "description": "Maximum hours ahead for AOS. Passes with AOS further in the future are rejected as stale predictions. 0 disables.", + }, # ================================================================= # DASHBOARD -- UI-only settings persisted for the operator diff --git a/meshai/central/satpass_handler.py b/meshai/central/satpass_handler.py index d17bc74..7558293 100644 --- a/meshai/central/satpass_handler.py +++ b/meshai/central/satpass_handler.py @@ -314,6 +314,14 @@ def handle_satpass(envelope: dict, subject: str, los_epoch, now) return None + # AOS horizon guard: reject passes too far in the future (likely stale prediction) + max_horizon_h = float(getattr(cfg, "max_aos_horizon_hours", 24)) + if max_horizon_h > 0 and aos_epoch > now + max_horizon_h * 3600: + logger.debug( + "satpass_handler: AOS %d is %.1fh away, beyond %gh horizon; skipping", + aos_epoch, (aos_epoch - now) / 3600, max_horizon_h) + return None + # Observer filter (empty = all) observers = getattr(cfg, "observers", []) or [] if observers and observer not in observers: