mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 17:31:34 +00:00
chore(central-ripout 2b): relocate satellite code to env/satellite/ (#162)
* chore(central-ripout 2b): create env/satellite package, move pass_predictor
pass_predictor.py was 100% live (no dead entrypoint) — SGP4 pass
computation used by both the native satpass adapter and the on-demand
!satpass command. Straight move, no code changes: meshai.central.pass_predictor
-> meshai.env.satellite.pass_predictor. Owner directive: satellite code gets
its own folder under the feed adapters, separate from env.satpass (the
adapter) to avoid colliding with env/satpass.py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(central-ripout 2b): split satpass_handler.py -> env/satellite/pass_format.py
satpass_handler.py was a split file: live wire-formatting/gate logic plus
dead Central-envelope ingest machinery whose only caller was the
already-deleted central/consumer.py NATS bridge.
Moved (live, verified via rg — external callers in env/satpass.py and
commands/satpass_cmd.py, or transitively called by them):
gate_consolidated_pass, format_pass, _check_rate_cap, _upsert_satpass,
_attach_commit, _map_severity, _canonical_id, _azimuth_to_compass,
_short_sat_name, _collapse_compass, _region_paren, _is_synthetic_observer,
_format_time_12h/24h, _format_ampm, _tz_abbr, _date_label,
plus the _SHORT_SAT_NAMES/_SHORT_NAME_SUBSTR/_SYNTHETIC_OBSERVERS tables.
Dropped (dead — zero callers outside the already-deleted consumer.py and
handle_satpass/consolidate_satpass_pending themselves; verified with rg):
handle_satpass, consolidate_satpass_pending, _cleanup_pending,
load_pending_schedule, _log_event_returning_id, _coerce_float,
_coerce_int, _parse_iso_epoch, _now, CONSOLIDATION_DELAY,
_pending_consolidation_ids, drain_pending_consolidation_ids,
_elevation_bucket (already-orphaned pre-ripout: superseded by numeric
"max NN°" wire format, zero callers anywhere but its own tests),
SCHEMA_SATPASS_EVENTS/SCHEMA_SATPASS_PENDING (unused string constants —
actual schema lives in persistence/migrations/*.sql, never imported).
Also dropped now-unused `json`/`time`/`Any` imports.
Straight code move otherwise — no logic changes to any moved function.
Two docstrings updated for accuracy (module docstring, and
gate_consolidated_pass's docstring which referenced the now-deleted
Central consumer path).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(central-ripout 2b): split tle_handler.py -> env/satellite/tle_store.py
tle_handler.py was a split file: live storage helpers plus a dead
Central-envelope ingest entrypoint whose only caller was the
already-deleted central/consumer.py NATS bridge.
Moved (live — used by env.tle_fetch, env.satpass, commands.satpass_cmd,
verified via rg): upsert_tle, get_fresh_tles, get_tle_by_norad,
search_tle_by_name.
Dropped (dead — handle_tle's only callers were tests and the deleted
consumer.py; verified with rg): handle_tle.
Straight code move otherwise — no logic changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(central-ripout 2b): repoint satellite consumers at env.satellite
Rewire the three production consumers (including their lazy/function-body
imports, not just module-top ones) to the new location:
- env/satpass.py: central.tle_handler -> env.satellite.tle_store,
central.pass_predictor -> env.satellite.pass_predictor,
central.satpass_handler -> env.satellite.pass_format
- env/tle_fetch.py: central.tle_handler.upsert_tle -> env.satellite.tle_store
- commands/satpass_cmd.py: all three, same mapping
Also refreshed docstrings that pointed at the old module paths or described
the now-fully-deleted Central consolidation path
(consolidate_satpass_pending / satpass_pending buffer) as a live
alternative, and updated central/__init__.py's module docstring to stop
listing the three relocated modules among central's remaining contents.
No behavior changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(central-ripout 2b): update satpass/tle test suite for the relocation
Repoints every remaining test import at the new env.satellite.* modules
and removes/adapts coverage for the Central envelope-ingest path deleted
in this pass (handle_satpass, consolidate_satpass_pending, handle_tle, and
the filtering/coercion/staleness logic that lived only inside them):
- test_satpass_native.py, test_tle_fetch.py, test_satpass_command.py:
import-path updates only (pass_predictor, tle_store). Also dropped
test_satpass_command.py's TestTLEUpsert.test_returns_none_always
(handle_tle-specific contract, no longer applicable) and rewrote its two
latest-wins tests to call upsert_tle directly — same behavior under test,
now exercised through the still-live primitive instead of the dead
wrapper.
- test_satpass_native.py: deleted test_central_consolidate_feeds_shared_gate_merged
(spied on consolidate_satpass_pending, which no longer exists). The
merge-across-observers logic it guarded is native-side (_consolidate)
and already covered by test_two_observers_consolidate_to_one_broadcast.
- test_satpass_handler.py: gutted to the one test that calls format_pass
directly (test_format_pass_worst_case_fits_140); the rest exercised
handle_satpass's observer/norad/elevation filters, which have no live
equivalent (the native adapter filters at the config level, not
per-envelope) and is redundant with test_satpass_native.py's dedup/wire
coverage via the real SatpassAdapter path.
- test_satpass_broadcast_safety.py: kept every test that calls format_pass
or gate_consolidated_pass-adjacent REGISTRY checks directly (wire format,
clean-format rules, REGISTRY defaults); deleted TestNoradIdTypeCoercion
and TestStalenessGuard (handle_satpass-only logic, no live equivalent)
and the 6 _elevation_bucket tests (_elevation_bucket itself was dead
before this pass too — zero callers anywhere but its own tests, already
superseded by the numeric "max NN°" wire format per its own docstring).
- test_satpass_persisted_timer.py: dropped test_due_at_persisted_on_normal_ingest
(handle_satpass-only); kept the two schema/migration tests, which don't
touch satpass_handler.
- Deleted outright (tested ONLY the dead Central envelope-ingest path, no
live equivalent to port to): test_satpass_event_path.py,
test_satpass_compass_fallback.py, test_satpass_wire_fields.py.
Full suite: 2059 passed, 0 failed (was 0 failed on main pre-change).
Satpass/TLE subset (99 tests across 8 files) verified green in isolation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ff127bee18
commit
41178831e4
18 changed files with 590 additions and 2483 deletions
|
|
@ -1,13 +1,12 @@
|
|||
"""Tests for the native SGP4 satpass adapter (env.satpass).
|
||||
|
||||
The native adapter computes every observer for a satellite in ONE tick, so it
|
||||
consolidates in-memory and gates synchronously via the SHARED
|
||||
`satpass_handler.gate_consolidated_pass` — with NO `satpass_pending` buffer and
|
||||
NO Central consumer/timer. These tests monkeypatch `compute_passes` and
|
||||
consolidates in-memory and gates synchronously via
|
||||
`env.satellite.pass_format.gate_consolidated_pass` — with no buffer table and
|
||||
no consumer/timer. These tests monkeypatch `compute_passes` and
|
||||
`get_observers` (no SGP4 / no network) and seed a fresh `sat_tles` row, then
|
||||
exercise: multi-observer consolidation, cross-tick dedup via `satpass_events`,
|
||||
resilient empty cases, the precomposed aos→peak→los wire, and a guard that the
|
||||
Central path still feeds the shared gate the correctly-merged consolidation.
|
||||
resilient empty cases, and the precomposed aos→peak→los wire.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
@ -18,8 +17,8 @@ import pytest
|
|||
|
||||
from meshai.env.satpass import SatpassAdapter
|
||||
from meshai.config import SatpassConfig
|
||||
from meshai.central.pass_predictor import PassInfo
|
||||
from meshai.central.tle_handler import upsert_tle
|
||||
from meshai.env.satellite.pass_predictor import PassInfo
|
||||
from meshai.env.satellite.tle_store import upsert_tle
|
||||
from meshai.persistence import get_db
|
||||
|
||||
|
||||
|
|
@ -85,7 +84,7 @@ def _adapter(**overrides) -> SatpassAdapter:
|
|||
|
||||
|
||||
def _patch_predictor(monkeypatch, fake):
|
||||
monkeypatch.setattr("meshai.central.pass_predictor.compute_passes", fake)
|
||||
monkeypatch.setattr("meshai.env.satellite.pass_predictor.compute_passes", fake)
|
||||
|
||||
|
||||
def _patch_observers(monkeypatch, observers):
|
||||
|
|
@ -253,63 +252,6 @@ def test_emitted_event_renders_aos_peak_los(monkeypatch):
|
|||
assert composed.startswith("\U0001F6F0") # satellite emoji
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# 5. SHARED-GATE EXTRACTION GUARD (Central path still feeds the gate right)
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
def test_central_consolidate_feeds_shared_gate_merged(monkeypatch):
|
||||
"""consolidate_satpass_pending must merge observers and hand the SAME
|
||||
shared gate a correctly-consolidated dict (earliest AOS / latest LOS /
|
||||
max-el observer / entry+exit / observer_list). Spying the gate proves the
|
||||
Central path routes through the extracted, source-agnostic function."""
|
||||
import meshai.central.satpass_handler as sh
|
||||
|
||||
conn = get_db()
|
||||
cid = f"25544:{T0 // 3600}"
|
||||
# Two pending rows for the same canonical id (boise entry, twin exit+peak).
|
||||
rows = [
|
||||
(cid, "boise", "ISS", 25544, 40.0, T0, T0 + 300, "SW", "NW", "E", T0, T0 + 5),
|
||||
(cid, "twin", "ISS", 25544, 70.0, T0 + 60, T0 + 400, "W", "NE", "S", T0, T0 + 5),
|
||||
]
|
||||
for r in rows:
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO satpass_pending("
|
||||
"consolidated_id, observer, sat_name, norad_id, max_elevation, "
|
||||
"aos_at, los_at, aos_compass, los_compass, peak_compass, "
|
||||
"received_at, due_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", r)
|
||||
|
||||
captured = {}
|
||||
|
||||
def _spy(consolidated, *, now):
|
||||
captured["c"] = consolidated
|
||||
captured["now"] = now
|
||||
return None # short-circuit: no broadcast side effects
|
||||
|
||||
monkeypatch.setattr(sh, "gate_consolidated_pass", _spy)
|
||||
|
||||
result = sh.consolidate_satpass_pending(cid)
|
||||
assert result is None
|
||||
|
||||
c = captured["c"]
|
||||
assert c["consolidated_id"] == cid
|
||||
assert c["norad_id"] == 25544
|
||||
assert c["max_elevation"] == 70.0 # twin (higher)
|
||||
assert c["aos_epoch"] == T0 # boise earliest AOS
|
||||
assert c["los_epoch"] == T0 + 400 # twin latest LOS
|
||||
assert c["aos_compass"] == "SW" # boise
|
||||
assert c["los_compass"] == "NE" # twin
|
||||
assert c["peak_compass"] == "S" # twin (max-el observer)
|
||||
assert c["entry_observer"] == "boise"
|
||||
assert c["exit_observer"] == "twin"
|
||||
assert c["observer_list"] == "boise,twin"
|
||||
|
||||
# Pending buffer is drained regardless of the gate's decision.
|
||||
left = conn.execute(
|
||||
"SELECT COUNT(*) AS n FROM satpass_pending WHERE consolidated_id=?",
|
||||
(cid,)).fetchone()
|
||||
assert left["n"] == 0
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# 6. IMMINENCE BROADCAST TRIGGER (satpass's "just received" analog)
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue