mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 09:21:33 +00:00
chore(central-ripout 2d-i): relocate the fire engine + renderer out of central/ (#164)
Moves the last two live files out of the retired-Central folder. central/ is now EMPTY and deleted entirely (incl. __init__.py). - fire-fusion engine (ingest_hotspot_pixel + the growth/cluster/spotting engine) → env/fire_fusion.py, next to its sole consumer env/firms.py. - wildfire text renderer (_render + its live helpers) → env/fire_render.py. THE COUPLING RESOLVED: firms_handler._handle_pass_boundary had a LAZY import inside a function body — `from meshai.central.wfigs_handler import _render` — sitting on the live FIRMS fire-growth path. It is now a normal top-of-file import (`from meshai.env.fire_render import _render`), visible and greppable. PURE MOVE — no behavior change: - The parity oracle (test_fire_refactor.py) PASSES UNCHANGED (only its import paths updated) — proving the fire wire output is byte-for-byte identical before and after. Fire alerts say exactly what they said. - handle_firms / handle_wfigs (dead entrypoints, only caller was the deleted consumer.py) were KEPT and moved rather than dropped — the wording-cleanup PR removes them deliberately. "When unsure, keep." - fire_render.py's geo-helper imports still point at central_normalizer — that file's split is a SEPARATE PR; carried the imports along, did not touch it. Consumers + test import paths rewired. Full suite: 2059 passed, 0 failed. 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
dd932b4ee9
commit
de91751bbc
19 changed files with 97 additions and 72 deletions
|
|
@ -1,8 +0,0 @@
|
|||
"""Central connector package (v0.4) — historically consumed Central's NATS
|
||||
JetStream firehose and normalized it into meshai pipeline Events. The NATS
|
||||
consumer is retired (Central is gone); this package now only holds the
|
||||
split-file modules still used by the native adapter paths (firms_handler,
|
||||
wfigs_handler _render). The satellite pieces (satpass_handler, tle_handler,
|
||||
pass_predictor) have moved to meshai.env.satellite, and the gauge-site
|
||||
lookups have moved to meshai.env.gauge_sites — they're feed-adapter support
|
||||
code, not consumer leftovers."""
|
||||
|
|
@ -1,5 +1,15 @@
|
|||
"""v0.7-fire-tracker-3 FIRMS handler -- storage + attribution + cluster + growth/halt/spotting.
|
||||
|
||||
Relocated from `meshai.central.firms_handler` during the Central ripout
|
||||
(central/ handler retirement, chore/ripout-2d). ``ingest_hotspot_pixel`` is
|
||||
the LIVE fire-fusion engine with one consumer: the native FIRMS adapter
|
||||
(`meshai.env.firms` -> `_run_fusion`). ``handle_firms`` (the Central
|
||||
NATS-envelope entrypoint) has no live production caller -- Central's
|
||||
consumer that drove it is gone -- but it remains the parity-tested legacy
|
||||
contract (see `tests/test_firms_handler.py`, `tests/test_firms_refactor.py`,
|
||||
`tests/test_fire_tracker_phase1/2/3.py`) -- kept verbatim, not deleted, per
|
||||
that coverage.
|
||||
|
||||
Pre-v0.6-1 the v0.5.13 default-deny gate at consumer._normalize() silently
|
||||
dropped every `central.fire.hotspot.>` envelope because no per-adapter handler
|
||||
existed (audit doc v0.6-phase1-audit.md finding #2). The `firms_pixels`
|
||||
|
|
@ -70,6 +80,7 @@ from datetime import datetime, timezone
|
|||
from typing import Any, Optional
|
||||
|
||||
from meshai.persistence import get_db
|
||||
from meshai.env.fire_render import _render
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -919,7 +930,6 @@ def _handle_pass_boundary(conn, *, irwin_id, pass_id, lat, lon,
|
|||
if fire is None:
|
||||
return None
|
||||
|
||||
from meshai.central.wfigs_handler import _render
|
||||
movement = {"direction": drift_direction, "speed_mph": drift_mi_per_hour or 0.0}
|
||||
normalized = dict(fire)
|
||||
normalized["irwin_id"] = irwin_id
|
||||
|
|
@ -948,7 +958,14 @@ def _handle_pass_boundary(conn, *, irwin_id, pass_id, lat, lon,
|
|||
|
||||
def _render_growth_wire(*, incident_name, direction, speed_mph,
|
||||
lat, lon):
|
||||
"""Per design doc section 4 + Phase 2 spec item 3."""
|
||||
"""Per design doc section 4 + Phase 2 spec item 3.
|
||||
|
||||
NOTE: unreferenced (verified via repo-wide rg during the chore/ripout-2d
|
||||
relocation -- zero callers in source or tests). `_handle_pass_boundary`
|
||||
renders growth wires via the WFIGS `_render` instead. Left in place
|
||||
(moved verbatim, not deleted) since dropping dead code is out of scope
|
||||
for this pure-move PR.
|
||||
"""
|
||||
near_part = ""
|
||||
try:
|
||||
from meshai.central_normalizer import nearest_town
|
||||
|
|
@ -1,5 +1,15 @@
|
|||
"""WFIGS handler: persistence-backed change-detection + wire renderer.
|
||||
|
||||
Relocated from `meshai.central.wfigs_handler` during the Central ripout
|
||||
(central/ handler retirement, chore/ripout-2d). ``handle_wfigs`` has no live
|
||||
production caller (Central's NATS consumer that drove it is gone), but it
|
||||
remains the parity-tested legacy contract for the WFIGS wildfire wire format
|
||||
(see `tests/test_fire_refactor.py`, `tests/test_wfigs_handler.py`) -- kept
|
||||
verbatim, not deleted, per that oracle. ``_render`` IS live: it is imported
|
||||
by `meshai.env.fire_fusion._handle_pass_boundary` on the FIRMS growth path
|
||||
(`env/firms.py` -> `ingest_hotspot_pixel` -> ... -> `_handle_pass_boundary`
|
||||
-> `_render`) to render the `wildfire_growth` wire.
|
||||
|
||||
v0.5.8b refactor: New: vs Update: decision now keys on `last_broadcast_at`,
|
||||
not on row existence. Cold-start scenarios where the dispatcher drops the
|
||||
broadcast (cold-start grace, stale filter, cooldown, dedup) leave the fires
|
||||
|
|
@ -469,7 +479,7 @@ def _render(n: dict, *, prefix: str = "",
|
|||
lines: list[str] = []
|
||||
|
||||
# Line 1: header
|
||||
lines.append(f"🔥 {name} \u2014 {prefix}")
|
||||
lines.append(f"🔥 {name} — {prefix}")
|
||||
|
||||
# Line 2: size / containment with delta (plain text -- no bold markdown).
|
||||
acres_str = f"{int(acres):,} ac" if acres is not None else "size unknown"
|
||||
6
work/meshai/env/firms.py
vendored
6
work/meshai/env/firms.py
vendored
|
|
@ -138,7 +138,7 @@ class FIRMSAdapter:
|
|||
new_events = self._parse_csv(csv_data)
|
||||
|
||||
# Feed every fetched pixel into the SHARED source-agnostic fusion engine
|
||||
# (central.firms_handler.ingest_hotspot_pixel): attribution + growth /
|
||||
# (env.fire_fusion.ingest_hotspot_pixel): attribution + growth /
|
||||
# spotting / halt. DB-level dedup (firms_pixels unique key) makes this
|
||||
# idempotent across ticks, so re-fetched pixels never double-count.
|
||||
# NEVER broadcasts raw hotspots -- only the fusion wires it returns.
|
||||
|
|
@ -422,14 +422,14 @@ class FIRMSAdapter:
|
|||
engine and collect the fire-fusion broadcasts.
|
||||
|
||||
Every parsed pixel is mapped to the canonical FIRMS schema and passed to
|
||||
``central.firms_handler.ingest_hotspot_pixel`` -- the exact same engine
|
||||
``env.fire_fusion.ingest_hotspot_pixel`` -- the exact same engine
|
||||
the Central NATS handler drives. The engine INSERTs the pixel, runs
|
||||
attribution, and runs the growth / spotting / halt fusion; it returns
|
||||
ONLY fusion wires (never a raw-hotspot / cluster broadcast). DB-level
|
||||
dedup makes re-fetched pixels no-ops, so nothing double-counts.
|
||||
"""
|
||||
try:
|
||||
from meshai.central.firms_handler import (
|
||||
from meshai.env.fire_fusion import (
|
||||
ingest_hotspot_pixel, _parse_acq_epoch,
|
||||
)
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import time
|
|||
import pytest
|
||||
|
||||
import meshai.notifications.clock as clock_mod
|
||||
import meshai.central.wfigs_handler as wfigs_handler
|
||||
import meshai.env.fire_render as wfigs_handler
|
||||
|
||||
|
||||
_FROZEN_TS = 1_700_000_000.0
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""Step 3 fire age-gate tests (Step 5 verification, age-gate part).
|
||||
|
||||
Targets `meshai.central.wfigs_handler._fire_too_old_to_announce` and the
|
||||
Targets `meshai.env.fire_render._fire_too_old_to_announce` and the
|
||||
handler's "New"-path suppression behaviour.
|
||||
|
||||
The gate exists because MeshAI broadcast a 6-week-old, already-closed fire
|
||||
|
|
@ -21,7 +21,7 @@ import time
|
|||
|
||||
import pytest
|
||||
|
||||
from meshai.central.wfigs_handler import _fire_too_old_to_announce
|
||||
from meshai.env.fire_render import _fire_too_old_to_announce
|
||||
|
||||
|
||||
_14D = 14 * 86400
|
||||
|
|
@ -131,7 +131,7 @@ def test_handler_new_path_suppresses_old_fire():
|
|||
"""Case (i): a brand-new fire whose declared_at is ~45d old is INSERTed
|
||||
but the 'New' broadcast is suppressed (wire is None), and the New-path
|
||||
category tag is NOT applied."""
|
||||
from meshai.central.wfigs_handler import handle_wfigs
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
from meshai.persistence import get_db
|
||||
|
||||
now = int(time.time())
|
||||
|
|
@ -154,7 +154,7 @@ def test_handler_new_path_suppresses_old_fire():
|
|||
def test_handler_new_path_announces_recent_fire():
|
||||
"""Case (i): a recent fire (~5d) DOES broadcast 'New' and tags
|
||||
wildfire_declared."""
|
||||
from meshai.central.wfigs_handler import handle_wfigs
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
|
||||
now = int(time.time())
|
||||
declared = now - _5D
|
||||
|
|
@ -171,7 +171,7 @@ def test_handler_update_path_still_emits_for_old_fire():
|
|||
"""An already-broadcast OLD fire that grows acreage still emits an
|
||||
'Update' (Case (iii) is NOT gated -- genuine old-but-active fires keep
|
||||
getting containment/acreage updates)."""
|
||||
from meshai.central.wfigs_handler import handle_wfigs
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
from meshai.persistence import get_db
|
||||
|
||||
now = int(time.time())
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import pytest
|
|||
|
||||
from meshai import central_normalizer as cn
|
||||
from meshai.notifications.formatters._budget import budget_for
|
||||
from meshai.central.wfigs_handler import (
|
||||
from meshai.env.fire_render import (
|
||||
_build_canonical,
|
||||
_render as _wfigs_render,
|
||||
handle_wfigs,
|
||||
|
|
@ -55,7 +55,7 @@ def mem_db(monkeypatch, tmp_path):
|
|||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from meshai.central import wfigs_handler as _wh
|
||||
from meshai.env import fire_render as _wh
|
||||
_wh._last_cleanup = 0
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ def _envelope(*, lat, lon, acq_date="2026-06-06", acq_time="1200",
|
|||
|
||||
|
||||
def test_pixel_within_radius_attributes_to_fire():
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
# Cache Peak Fire stub @ 42.118, -113.643.
|
||||
|
|
@ -120,7 +120,7 @@ def test_pixel_within_radius_attributes_to_fire():
|
|||
def test_centroid_recomputes_as_median_across_passes():
|
||||
"""A second attributed pixel updates the centroid to the median, not
|
||||
just the latest pixel's coords."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
_seed_fire(irwin_id="ID-TEST-002",
|
||||
|
|
@ -157,7 +157,7 @@ def test_centroid_recomputes_as_median_across_passes():
|
|||
|
||||
|
||||
def test_pixel_outside_radius_stays_unattributed():
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
_seed_fire(irwin_id="ID-TEST-003",
|
||||
|
|
@ -196,7 +196,7 @@ def _hhmm(h, m=0):
|
|||
|
||||
|
||||
def test_three_unattributed_pixels_fire_cluster_once():
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
# No fires seeded -- everything is unattributed.
|
||||
|
|
@ -235,7 +235,7 @@ def test_three_unattributed_pixels_fire_cluster_once():
|
|||
|
||||
|
||||
def test_fourth_pixel_in_same_cluster_does_not_refire():
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
base_lat, base_lon = 43.500, -114.500
|
||||
|
|
@ -279,7 +279,7 @@ def test_fifth_pixel_after_time_window_can_form_new_cluster():
|
|||
no nearby unstamped pixels to count, so it stays silent -- but if
|
||||
we then ingest TWO more nearby pixels (also outside the original
|
||||
window), we should fire a NEW cluster."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
|
||||
base_lat, base_lon = 43.500, -114.500
|
||||
# First cluster at 12:00..12:20 -> fires + stamps all 3.
|
||||
|
|
@ -321,7 +321,7 @@ def test_fifth_pixel_after_time_window_can_form_new_cluster():
|
|||
|
||||
|
||||
def test_wfigs_first_sight_tags_wildfire_declared():
|
||||
from meshai.central.wfigs_handler import handle_wfigs
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
|
||||
normalized = {
|
||||
"_kind": "wfigs_incident",
|
||||
|
|
@ -351,7 +351,7 @@ def test_wfigs_first_sight_tags_wildfire_declared():
|
|||
def test_wfigs_update_does_not_retag_wildfire_declared():
|
||||
"""After a row exists AND has been broadcast, an acres-grew Update
|
||||
must NOT carry the wildfire_declared category."""
|
||||
from meshai.central.wfigs_handler import handle_wfigs
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
from meshai.persistence import get_db
|
||||
|
||||
# Pre-existing row that has already been broadcast.
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ def _envelope(*, lat, lon, acq_date="2026-06-06", acq_time="1200",
|
|||
def test_two_pass_drift_emits_growth_with_direction_and_speed():
|
||||
"""Pass 1 (N20 bucket A), pass 2 (N20 bucket B, ~6h later, centroid
|
||||
1.0 mi N of pass 1). Drift should be ~1.0 mi N, broadcast must fire."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
_seed_fire(irwin_id="ID-GROWTH-001",
|
||||
|
|
@ -139,7 +139,7 @@ def test_two_pass_drift_emits_growth_with_direction_and_speed():
|
|||
def test_drift_below_threshold_does_not_emit_growth():
|
||||
"""0.3 mi drift between consecutive passes -- below the 0.5 mi
|
||||
default -- must NOT broadcast wildfire_growth."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
_seed_fire(irwin_id="ID-DRIFT-001",
|
||||
|
|
@ -181,7 +181,7 @@ def test_drift_below_threshold_does_not_emit_growth():
|
|||
def test_halt_detector_fires_once_after_12h_idle():
|
||||
"""Fire with last_pass_at 14h ago + no new pixels in that fire
|
||||
triggers halt on the next FIRMS pixel arrival (for any fire)."""
|
||||
from meshai.central.firms_handler import handle_firms, _maybe_emit_halt
|
||||
from meshai.env.fire_fusion import handle_firms, _maybe_emit_halt
|
||||
from meshai.persistence import get_db
|
||||
|
||||
now_epoch = 1780768800 # 2026-06-06 18:00 UTC
|
||||
|
|
@ -214,7 +214,7 @@ def test_halt_detector_fires_once_after_12h_idle():
|
|||
|
||||
def test_halt_detector_no_second_broadcast_for_same_fire():
|
||||
"""Once halt_broadcast_at is stamped, the detector skips that fire."""
|
||||
from meshai.central.firms_handler import _maybe_emit_halt
|
||||
from meshai.env.fire_fusion import _maybe_emit_halt
|
||||
from meshai.persistence import get_db
|
||||
|
||||
now_epoch = 1780768800
|
||||
|
|
@ -238,7 +238,7 @@ def test_halt_eligibility_returns_after_new_pass_arrives():
|
|||
"""A previously halted fire that receives a new pixel becomes eligible
|
||||
for halt again if it goes idle a second time. The detector filter is
|
||||
halt_broadcast_at IS NULL OR halt_broadcast_at < last_pass_at."""
|
||||
from meshai.central.firms_handler import _maybe_emit_halt
|
||||
from meshai.env.fire_fusion import _maybe_emit_halt
|
||||
from meshai.persistence import get_db
|
||||
|
||||
now_epoch = 1780768800
|
||||
|
|
@ -267,7 +267,7 @@ def test_halt_eligibility_returns_after_new_pass_arrives():
|
|||
|
||||
def test_bearing_and_direction_round_trip():
|
||||
"""Bearing helper + 8-way mapping cover all cardinals/intercardinals."""
|
||||
from meshai.central.firms_handler import _bearing, _direction_8
|
||||
from meshai.env.fire_fusion import _bearing, _direction_8
|
||||
# Source point.
|
||||
s_lat, s_lon = 42.0, -114.0
|
||||
# Each cardinal/intercardinal direction we test by walking ~1 mi.
|
||||
|
|
@ -289,7 +289,7 @@ def test_bearing_and_direction_round_trip():
|
|||
|
||||
|
||||
def test_direction_8_boundary_cases():
|
||||
from meshai.central.firms_handler import _direction_8
|
||||
from meshai.env.fire_fusion import _direction_8
|
||||
# Bearings on the boundary -- check the +22.5 offset rounds correctly.
|
||||
assert _direction_8(0.0) == "N"
|
||||
assert _direction_8(22.4) == "N"
|
||||
|
|
@ -339,7 +339,7 @@ def test_pass_row_aggregates_match_member_pixels():
|
|||
"""5 pixels attributed in the same pass yield ONE fire_passes row
|
||||
with pixel_count=5, total_frp = sum, pass_started_at = min(acq),
|
||||
pass_ended_at = max(acq), centroid = median."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
_seed_fire(irwin_id="ID-AGG-001",
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ def test_pass_close_stamps_perimeter_geojson():
|
|||
"""Pass A: 6 pixels in a hex around the seeded center. First pixel
|
||||
of pass B triggers boundary close -> perimeter_geojson written for
|
||||
pass A as a closed GeoJSON Polygon."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
center_lat, center_lon = 42.500, -114.500
|
||||
|
|
@ -121,7 +121,7 @@ def _seed_pass_a_hex_then_close(*, irwin_id, center_lat, center_lon,
|
|||
start_now=1780747200):
|
||||
"""Helper: seed a fire + 6 hex-vertex pass A pixels. Caller follows up
|
||||
with a pass B pixel to trigger boundary close + perimeter write."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
_seed_fire(irwin_id=irwin_id, lat=center_lat, lon=center_lon,
|
||||
name=irwin_id)
|
||||
for i in range(6):
|
||||
|
|
@ -138,7 +138,7 @@ def _seed_pass_a_hex_then_close(*, irwin_id, center_lat, center_lon,
|
|||
def test_pixel_2mi_ne_of_perimeter_emits_spotting():
|
||||
"""Pass B pixel 2 mi NE of pass A's perimeter centroid fires
|
||||
wildfire_spotting with the correct distance + direction."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
|
||||
center_lat, center_lon = 43.000, -115.000
|
||||
|
|
@ -188,7 +188,7 @@ def test_pixel_2mi_ne_of_perimeter_emits_spotting():
|
|||
|
||||
|
||||
def test_pixel_inside_perimeter_no_spotting():
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
|
||||
center_lat, center_lon = 43.500, -114.500
|
||||
_seed_pass_a_hex_then_close(irwin_id="ID-SPOT-003",
|
||||
|
|
@ -223,7 +223,7 @@ def test_pixel_inside_perimeter_no_spotting():
|
|||
|
||||
|
||||
def test_second_spotting_within_cooldown_suppressed():
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
|
||||
center_lat, center_lon = 44.000, -116.000
|
||||
_seed_pass_a_hex_then_close(irwin_id="ID-SPOT-004",
|
||||
|
|
@ -257,7 +257,7 @@ def test_second_spotting_within_cooldown_suppressed():
|
|||
|
||||
|
||||
def test_spotting_refires_after_cooldown():
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
|
||||
center_lat, center_lon = 44.500, -116.500
|
||||
_seed_pass_a_hex_then_close(irwin_id="ID-SPOT-005",
|
||||
|
|
@ -286,7 +286,7 @@ def test_spotting_refires_after_cooldown():
|
|||
|
||||
|
||||
def test_convex_hull_basic():
|
||||
from meshai.central.firms_handler import _convex_hull
|
||||
from meshai.env.fire_fusion import _convex_hull
|
||||
pts = [(0, 0), (1, 0), (1, 1), (0, 1), (0.5, 0.5)]
|
||||
hull = _convex_hull(pts)
|
||||
assert (0.5, 0.5) not in hull
|
||||
|
|
@ -294,7 +294,7 @@ def test_convex_hull_basic():
|
|||
|
||||
|
||||
def test_point_in_polygon_basic():
|
||||
from meshai.central.firms_handler import _point_in_polygon
|
||||
from meshai.env.fire_fusion import _point_in_polygon
|
||||
square = [(0, 0), (0, 10), (10, 10), (10, 0)] # (lat, lon)
|
||||
assert _point_in_polygon((5, 5), square) is True
|
||||
assert _point_in_polygon((15, 5), square) is False
|
||||
|
|
@ -303,7 +303,7 @@ def test_point_in_polygon_basic():
|
|||
|
||||
def test_geojson_round_trip_via_hull():
|
||||
"""Hull -> GeoJSON -> parse -> ring shape sane."""
|
||||
from meshai.central.firms_handler import _convex_hull, _hull_to_geojson
|
||||
from meshai.env.fire_fusion import _convex_hull, _hull_to_geojson
|
||||
hull = _convex_hull([(0, 0), (1, 0), (0, 1), (1, 1)])
|
||||
raw = _hull_to_geojson(hull)
|
||||
parsed = json.loads(raw)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ def _pixel(*, lat, lon, acq_date="2026-06-06", acq_time="1200",
|
|||
|
||||
|
||||
def _feed(pixel, *, now, seed=False):
|
||||
from meshai.central.firms_handler import ingest_hotspot_pixel
|
||||
from meshai.env.fire_fusion import ingest_hotspot_pixel
|
||||
return ingest_hotspot_pixel(pixel, now=now, seed=seed)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ Envelope shape sourced from firms-investigation.md sampling (250 envelopes
|
|||
"""
|
||||
import pytest
|
||||
|
||||
from meshai.central import firms_handler
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env import fire_fusion as firms_handler
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import close_thread_connection, init_db
|
||||
from meshai.persistence import db as persistence_db
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ def _offset_mi(lat, lon, north_mi, east_mi):
|
|||
|
||||
|
||||
def _feed(pixel, *, now):
|
||||
from meshai.central.firms_handler import ingest_hotspot_pixel
|
||||
from meshai.env.fire_fusion import ingest_hotspot_pixel
|
||||
return ingest_hotspot_pixel(pixel, now=now)
|
||||
|
||||
|
||||
|
|
@ -407,7 +407,7 @@ _SUBJECT = "central.fire.hotspot.N20.high.us.id"
|
|||
|
||||
class TestCentralPathUnchanged:
|
||||
def test_storage_only_pixel_still_stores_and_returns_none(self):
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
from meshai.persistence import get_db
|
||||
env = _envelope(lat=42.19664, lon=-113.70981)
|
||||
out = handle_firms(env, subject=_SUBJECT, data={}, now=1780660000)
|
||||
|
|
@ -427,7 +427,7 @@ class TestCentralPathUnchanged:
|
|||
def test_central_growth_wire_and_stamps_identical(self):
|
||||
"""The extracted core produces the SAME growth wire/stamps on the
|
||||
Central envelope path that the inline handler did."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
center_lat, center_lon = 42.0, -114.0
|
||||
_seed_fire(irwin_id="ID-CG", lat=center_lat, lon=center_lon,
|
||||
name="Pine Gulch")
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ _SUBJECT = "central.fire.hotspot.N20.high.us.id"
|
|||
def _drive_two_pass_growth(irwin_id, center_lat, center_lon):
|
||||
"""Seed a fire + pass A (5 px) + first pass-B pixel 1 mi N. Returns the
|
||||
(wire, data) from the boundary pixel that fires wildfire_growth."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
_seed_fire(irwin_id=irwin_id, lat=center_lat, lon=center_lon, name="Pine Gulch")
|
||||
for i in range(5):
|
||||
env = _envelope(lat=center_lat + 0.0001 * i,
|
||||
|
|
@ -136,7 +136,7 @@ def _drive_two_pass_growth(irwin_id, center_lat, center_lon):
|
|||
|
||||
def _seed_pass_a_hex_then_close(irwin_id, center_lat, center_lon,
|
||||
start_now=1780747200):
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
_seed_fire(irwin_id=irwin_id, lat=center_lat, lon=center_lon, name=irwin_id)
|
||||
for i in range(6):
|
||||
angle = i * math.pi / 3
|
||||
|
|
@ -156,7 +156,7 @@ def _offset_mi(lat, lon, north_mi, east_mi):
|
|||
def _drive_spotting(irwin_id, center_lat, center_lon, now=1780768800):
|
||||
"""Seed hex pass A + closed perimeter, then a pass-B pixel 2 mi NE that
|
||||
fires wildfire_spotting. Returns (wire, data)."""
|
||||
from meshai.central.firms_handler import handle_firms
|
||||
from meshai.env.fire_fusion import handle_firms
|
||||
_seed_pass_a_hex_then_close(irwin_id, center_lat, center_lon)
|
||||
sp_lat, sp_lon = _offset_mi(center_lat, center_lon,
|
||||
north_mi=2.0 / math.sqrt(2),
|
||||
|
|
@ -354,7 +354,7 @@ class TestFormatterGolden:
|
|||
_clear_cache()
|
||||
|
||||
def test_halt_wire_golden(self, monkeypatch):
|
||||
from meshai.central.firms_handler import _maybe_emit_halt
|
||||
from meshai.env.fire_fusion import _maybe_emit_halt
|
||||
from meshai.persistence import get_db
|
||||
_cutover(monkeypatch, "wildfire_halted")
|
||||
try:
|
||||
|
|
@ -416,7 +416,7 @@ class TestNotCutoverLegacyVerbatim:
|
|||
assert "_on_broadcast_committed" not in data
|
||||
|
||||
def test_halt_eager_latch_stamped(self, _no_cutover):
|
||||
from meshai.central.firms_handler import _maybe_emit_halt
|
||||
from meshai.env.fire_fusion import _maybe_emit_halt
|
||||
from meshai.persistence import get_db
|
||||
now = 1780768800
|
||||
_seed_stale_fire("ID-HN", now_epoch=now, idle_hours=14)
|
||||
|
|
@ -439,7 +439,7 @@ class TestNotCutoverLegacyVerbatim:
|
|||
|
||||
class TestClusterBelowThreshold:
|
||||
def test_maybe_emit_cluster_below_threshold_returns_none(self):
|
||||
from meshai.central.firms_handler import _maybe_emit_cluster
|
||||
from meshai.env.fire_fusion import _maybe_emit_cluster
|
||||
from meshai.persistence import get_db
|
||||
data = {}
|
||||
# No pixels in firms_pixels -> the cluster query finds < min_pixels
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@ must be importable without error after the budget shim refactor.
|
|||
|
||||
This guards against a broken import chain (e.g. circular imports or a bad
|
||||
re-export in the shim) that would silently break all handlers.
|
||||
|
||||
chore/ripout-2d: the last two central/ handlers (firms_handler.py,
|
||||
wfigs_handler.py) relocated to meshai/env/fire_fusion.py + fire_render.py
|
||||
(central/ has no *_handler.py left -- the fusion engine's only consumer is
|
||||
the native env/firms.py adapter). The glob below now also covers those two
|
||||
explicitly so this guard still exercises the relocated live import chain;
|
||||
it keeps globbing central/ too in case a future handler lands back there.
|
||||
"""
|
||||
|
||||
import glob
|
||||
|
|
@ -11,17 +18,16 @@ import os
|
|||
|
||||
|
||||
def _handler_modules():
|
||||
"""Collect meshai.central.*_handler module names by globbing the source tree."""
|
||||
pattern = os.path.join(
|
||||
"""Collect handler-ish module names: meshai.central.*_handler (glob) +
|
||||
the fire-fusion modules relocated out of central/ during the ripout."""
|
||||
central_pattern = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "meshai", "central", "*_handler.py",
|
||||
)
|
||||
paths = sorted(glob.glob(pattern))
|
||||
assert paths, "No *_handler.py files found — check the glob path"
|
||||
modules = []
|
||||
for p in paths:
|
||||
name = os.path.basename(p)[:-3] # strip .py
|
||||
modules.append(f"meshai.central.{name}")
|
||||
central_paths = sorted(glob.glob(central_pattern))
|
||||
modules = [f"meshai.central.{os.path.basename(p)[:-3]}" for p in central_paths]
|
||||
modules += ["meshai.env.fire_fusion", "meshai.env.fire_render"]
|
||||
assert modules, "No handler-ish modules found — check the glob path"
|
||||
return modules
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ def test_fires_has_tombstoned_at_column():
|
|||
|
||||
def test_wfigs_tombstone_stamps_column():
|
||||
"""A tombstone envelope sets fires.tombstoned_at."""
|
||||
from meshai.central.wfigs_handler import handle_wfigs
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
conn = get_db()
|
||||
# Seed an active fire row.
|
||||
irwin = "TOMB-1"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import time
|
|||
|
||||
import pytest
|
||||
|
||||
from meshai.central.wfigs_handler import handle_wfigs
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
from meshai.notifications.env_reporter import EnvReporter
|
||||
from meshai.persistence import get_db
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ def test_dedup_suffix_lets_updates_pass_and_repeats_dedup():
|
|||
|
||||
|
||||
def test_wfigs_handler_stamps_dedup_suffix():
|
||||
from meshai.central.wfigs_handler import _attach_commit_handles
|
||||
from meshai.env.fire_render import _attach_commit_handles
|
||||
data = {}
|
||||
_attach_commit_handles(data, irwin_id="{X}", acres=42.0,
|
||||
contained_pct=15, event_log_row_id=None)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import time
|
|||
import pytest
|
||||
|
||||
from meshai import central_normalizer as cn
|
||||
from meshai.central.wfigs_handler import (
|
||||
from meshai.env.fire_render import (
|
||||
WFIGS_BROADCAST_COOLDOWN_S,
|
||||
handle_wfigs,
|
||||
_render as _wfigs_render,
|
||||
|
|
@ -47,7 +47,7 @@ def mem_db(monkeypatch, tmp_path):
|
|||
pass
|
||||
# Reset the stale-fire cleanup throttle so it runs deterministically.
|
||||
try:
|
||||
from meshai.central import wfigs_handler as _wh
|
||||
from meshai.env import fire_render as _wh
|
||||
_wh._last_cleanup = 0
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue