mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 17:31:34 +00:00
chore(central-ripout 2d-ii): remove dead fire scraps (NOT the 'rewrite' — there wasn't one) (#166)
* chore(fire-ripout 2dii-a): remove dead wildfire_growth cutover path + handle_firms
wildfire_growth events are always fully precomposed (env/firms.py sets
_meshai_precomposed=True + title=<wire from _render()>) and the category is
not in cutover.NATIVE_ALWAYS_DECIDE, so the registered fire formatter could
never be reached live via compose_mesh_message for this category -- the
precomposed-title bypass always won first. Removes the dead
is_cutover("wildfire_growth") NEW-PATH branch in
fire_fusion._handle_pass_boundary (kept the live legacy leg that calls
_render unconditionally) and the now-unreachable wildfire_growth formatter
registration in notifications/formatters/__init__.py.
Also removes handle_firms, the dead Central NATS-envelope entrypoint (zero
live production callers -- Central's consumer that drove it is gone), plus
its envelope-specific filtering helpers (_confidence_passes, _in_bbox,
_coerce_severity, _log_event, FIRMS_CONFIDENCE_FLOOR/FRP_FLOOR/BBOX_OPTIONAL)
that had no live callers left. The shared, LIVE fusion core
(_ingest_pixel_core, attribution, clustering, growth/spotting/halt) and
_parse_acq_epoch are unaffected -- still the engine behind the native
ingest_hotspot_pixel entrypoint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(fire-ripout 2dii-b): remove dead handle_wfigs entrypoint
handle_wfigs (the dead Central NATS-envelope entrypoint) had zero live
production callers -- Central's consumer that drove it is gone. The LIVE
WFIGS path is env/fires.py (native adapter) -> env/store.py::_emit_event,
forced onto gating.fire.decide + the shared fire formatter via
cutover.NATIVE_ALWAYS_DECIDE, independent of this dead handler.
Removes handle_wfigs and its private-only helpers (_coerce_severity,
_log_event, _log_event_returning_id) that had no callers left. _render
remains -- it is called directly by env.fire_fusion._handle_pass_boundary on
the FIRMS wildfire_growth path, and is used as a byte-identity oracle by
tests against the shared, live fire formatter. _build_canonical,
_attach_commit_handles, _fire_too_old_to_announce, _now, _cleanup_stale_fires
and WFIGS_BROADCAST_COOLDOWN_S are kept -- each has its own direct test
coverage independent of handle_wfigs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(fire-ripout 2dii-c): rewire fire tests off the deleted dead entrypoints
handle_firms and handle_wfigs (both removed in the prior two commits) were
used throughout this test suite purely as convenient DRIVERS for live logic
(pixel attribution/clustering/growth/spotting/halt fusion; the WFIGS
New/Update/cooldown/closed decider). Per-file disposition:
Rewired to drive the LIVE native entrypoint directly (no behavior change --
same underlying _ingest_pixel_core / gating.fire.decide engines):
- test_fire_tracker_phase1/2/3.py: handle_firms -> ingest_hotspot_pixel
- test_firms_refactor.py: handle_firms driver helpers -> ingest_hotspot_pixel;
dropped the dead wildfire_growth cutover test + the fully-redundant
TestNotCutoverLegacyVerbatim class (already covered by
test_firms_native_fusion.py's TestIngestGrowth/Spotting/Halt against the
live entrypoint); wildfire_growth formatter registration test now
asserts None (matches source change).
- test_wfigs_handler.py: handle_wfigs -> _render (the live WFIGS renderer)
called directly, for the anchor-priority + missing-acres cases that
exercise shared/live code (_location_anchor).
- test_fire_refactor.py: handle_wfigs -> gating.fire.decide() driven
directly, with state written the same unconditional shape the live
native path uses; TestGateSequenceParity trimmed to focus on the
tombstone/closed lifecycle step (not covered by
test_fire_native_growth.py's native-adapter New/Update/cooldown coverage).
- test_tombstone_broadcast.py, test_fire_age_gate.py: handle_wfigs ->
gating.fire.decide() driven directly; same assertions, off the dead path.
Deleted as pure dead-entrypoint contract testing with no live equivalent:
- test_firms_native_fusion.py::TestCentralPathUnchanged (2 tests) --
existed only to guard handle_firms's own envelope parsing.
- test_firms_handler.py: confidence/FRP/bbox filtering, missing-coords,
non-firms-adapter guard, event_log accounting (all handle_firms-specific;
the native adapter filters upstream in a different code path). Kept +
rewired: the shared _ingest_pixel_core dedup behavior and
_parse_acq_epoch's int/short acq_time parsing (both genuinely live/shared).
- test_wfigs_handler.py: envelope field-extraction (acres-fallback chain,
IA-placeholder-as-name), tombstone/perimeter subject -> event_log,
New/Update/cooldown decision + audit-row wiring (all redundant with
tests/test_fire_native_growth.py's coverage of gating.fire.decide()
through the real native adapter).
- test_tombstone_broadcast.py::test_commit_callback_flips_handled --
asserted handle_wfigs's own event_log-row flip on commit, a Central-only
concept the native path never used.
- test_tail_followups.py::test_wfigs_tombstone_stamps_column -- asserted
handle_wfigs's own inline tombstoned_at UPDATE; no live producer emits
_kind=wfigs_tombstone today, so nothing in the live system stamps it.
Both live renderers stay covered: fire_format (wildfire_declared/incident,
via test_fire_refactor.py + test_fire_native_growth.py, untouched) and
_render (wildfire_growth via FIRMS, via test_fire_tracker_phase2.py +
test_firms_native_fusion.py's TestIngestGrowth, both driving the live
ingest_hotspot_pixel entrypoint).
Collection: 2010 -> 1974 tests (net -36: dead-only tests deleted, live
behavior rewired 1:1 or consolidated onto already-existing native-path
coverage). Full suite: 1974 passed, 0 failed.
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
6050392d09
commit
67176d66d5
14 changed files with 629 additions and 2026 deletions
|
|
@ -16,6 +16,14 @@ broadcasts back through the normal pipeline guards (Grouper, cooldown).
|
|||
This file's expectations were written before that downgrade and never
|
||||
updated -- "immediate" here would be reverting a deliberate, documented
|
||||
incident fix.
|
||||
|
||||
chore/ripout-2dii: `handle_wfigs` (the dead Central NATS-envelope entrypoint
|
||||
T1/T2 used to drive) has been REMOVED from `meshai.env.fire_render` -- zero
|
||||
live production callers. T1/T2 now drive `gating.fire.decide` directly (the
|
||||
LIVE, shared decider -- `_kind="wfigs_tombstone"` is its all-clear branch,
|
||||
reused by the shared fire formatter). `test_commit_callback_flips_handled`
|
||||
(which asserted handle_wfigs's OWN event_log-row flip on commit -- a
|
||||
Central-only concept the native path never used) was deleted with it.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
@ -23,7 +31,7 @@ import time
|
|||
|
||||
import pytest
|
||||
|
||||
from meshai.env.fire_render import handle_wfigs
|
||||
from meshai.notifications.gating.fire import decide as fire_decide
|
||||
from meshai.notifications.env_reporter import EnvReporter
|
||||
from meshai.persistence import get_db
|
||||
|
||||
|
|
@ -49,7 +57,12 @@ def _seed_fire(conn, *, irwin_id, name, acres, contained=None,
|
|||
|
||||
|
||||
class TestTombstoneSeverityAndCommitHandles:
|
||||
"""T1: tombstone branch sets priority severity and attaches commit handles."""
|
||||
"""T1: tombstone branch sets priority severity and attaches commit handles.
|
||||
|
||||
Drives gating.fire.decide() directly (chore/ripout-2dii: handle_wfigs, the
|
||||
dead entrypoint this used to wrap, is gone). decide()'s data_patch carries
|
||||
the same stamps the dispatcher reads off event.data.
|
||||
"""
|
||||
|
||||
def test_severity_is_priority(self):
|
||||
conn = get_db()
|
||||
|
|
@ -58,20 +71,14 @@ class TestTombstoneSeverityAndCommitHandles:
|
|||
acres=500, contained=80,
|
||||
last_broadcast_at=now - 3600)
|
||||
|
||||
data = {}
|
||||
wire = handle_wfigs(
|
||||
normalized={"_kind": "wfigs_tombstone", "irwin_id": "FIRE-001"},
|
||||
envelope={"data": {"category": "wildfire", "severity": "immediate"}},
|
||||
subject="wfigs.tombstone",
|
||||
data=data,
|
||||
now=now,
|
||||
)
|
||||
assert wire is not None, "tombstone should produce wire for previously-broadcast fire"
|
||||
gate = fire_decide({"_kind": "wfigs_tombstone", "irwin_id": "FIRE-001"},
|
||||
source="wfigs", now=float(now))
|
||||
assert gate.broadcast is True, "tombstone should broadcast for previously-broadcast fire"
|
||||
# See module docstring: fire severity was deliberately downgraded
|
||||
# from "immediate" to "priority" (commit 2f677e85) so fire
|
||||
# broadcasts flow through the normal Grouper/cooldown guards.
|
||||
assert data.get("_severity_override") == "priority", (
|
||||
f"expected priority, got {data.get('_severity_override')}")
|
||||
assert gate.data_patch.get("_severity_override") == "priority", (
|
||||
f"expected priority, got {gate.data_patch.get('_severity_override')}")
|
||||
|
||||
def test_commit_handles_attached(self):
|
||||
conn = get_db()
|
||||
|
|
@ -80,19 +87,11 @@ class TestTombstoneSeverityAndCommitHandles:
|
|||
acres=1000, contained=95,
|
||||
last_broadcast_at=now - 7200)
|
||||
|
||||
data = {}
|
||||
wire = handle_wfigs(
|
||||
normalized={"_kind": "wfigs_tombstone", "irwin_id": "FIRE-002"},
|
||||
envelope={"data": {"category": "wildfire", "severity": "immediate"}},
|
||||
subject="wfigs.tombstone",
|
||||
data=data,
|
||||
now=now,
|
||||
)
|
||||
assert wire is not None
|
||||
assert "_on_broadcast_committed" in data, "commit callback missing"
|
||||
assert "_broadcast_audit" in data, "broadcast audit descriptor missing"
|
||||
assert "_cooldown_suffix" in data, "cooldown suffix missing"
|
||||
assert data["_cooldown_suffix"] == "FIRE-002"
|
||||
gate = fire_decide({"_kind": "wfigs_tombstone", "irwin_id": "FIRE-002"},
|
||||
source="wfigs", now=float(now))
|
||||
assert gate.broadcast is True
|
||||
assert callable(gate.commit), "commit callback missing"
|
||||
assert gate.data_patch.get("_cooldown_suffix") == "FIRE-002"
|
||||
|
||||
def test_dedup_suffix_is_closed(self):
|
||||
conn = get_db()
|
||||
|
|
@ -101,61 +100,32 @@ class TestTombstoneSeverityAndCommitHandles:
|
|||
acres=200, contained=100,
|
||||
last_broadcast_at=now - 600)
|
||||
|
||||
data = {}
|
||||
wire = handle_wfigs(
|
||||
normalized={"_kind": "wfigs_tombstone", "irwin_id": "FIRE-003"},
|
||||
envelope={"data": {"category": "wildfire", "severity": "immediate"}},
|
||||
subject="wfigs.tombstone",
|
||||
data=data,
|
||||
now=now,
|
||||
)
|
||||
assert wire is not None
|
||||
assert data.get("_dedup_suffix") == "closed", (
|
||||
f"expected 'closed', got {data.get('_dedup_suffix')}")
|
||||
|
||||
def test_commit_callback_flips_handled(self):
|
||||
"""The commit callback should flip event_log.handled to 1."""
|
||||
conn = get_db()
|
||||
now = int(time.time())
|
||||
_seed_fire(conn, irwin_id="FIRE-004", name="Callback Fire",
|
||||
acres=300, contained=50,
|
||||
last_broadcast_at=now - 1800)
|
||||
|
||||
data = {}
|
||||
wire = handle_wfigs(
|
||||
normalized={"_kind": "wfigs_tombstone", "irwin_id": "FIRE-004"},
|
||||
envelope={"data": {"category": "wildfire", "severity": "immediate"}},
|
||||
subject="wfigs.tombstone",
|
||||
data=data,
|
||||
now=now,
|
||||
)
|
||||
assert wire is not None
|
||||
assert "_on_broadcast_committed" in data
|
||||
|
||||
# Before commit: event_log row should have handled=0
|
||||
row_before = conn.execute(
|
||||
"SELECT id, handled FROM event_log WHERE event_id_external='FIRE-004' "
|
||||
"ORDER BY id DESC LIMIT 1"
|
||||
).fetchone()
|
||||
assert row_before is not None, "event_log row should exist"
|
||||
assert row_before["handled"] == 0, "should be unhandled before commit"
|
||||
|
||||
# Fire the commit callback
|
||||
data["_on_broadcast_committed"](float(now))
|
||||
|
||||
# After commit: handled should be 1
|
||||
row_after = conn.execute(
|
||||
"SELECT handled FROM event_log WHERE id=?",
|
||||
(row_before["id"],)
|
||||
).fetchone()
|
||||
assert row_after["handled"] == 1, "should be handled=1 after commit callback"
|
||||
gate = fire_decide({"_kind": "wfigs_tombstone", "irwin_id": "FIRE-003"},
|
||||
source="wfigs", now=float(now))
|
||||
assert gate.broadcast is True
|
||||
assert gate.data_patch.get("_dedup_suffix") == "closed", (
|
||||
f"expected 'closed', got {gate.data_patch.get('_dedup_suffix')}")
|
||||
|
||||
|
||||
class TestTombstoneAfterNewBroadcast:
|
||||
"""T2: closure dispatches when a New broadcast went out earlier."""
|
||||
"""T2: closure dispatches when a New broadcast went out earlier.
|
||||
|
||||
Drives gating.fire.decide() directly (chore/ripout-2dii: handle_wfigs is
|
||||
gone). The wire itself is rendered by the shared, LIVE fire formatter
|
||||
(notifications/formatters/fire.py::format) from decide()'s data_patch --
|
||||
the same contract the native WFIGS path uses.
|
||||
"""
|
||||
|
||||
def test_closure_wire_after_prior_broadcast(self):
|
||||
"""Fire that was broadcast 10 min ago gets a closure wire on tombstone."""
|
||||
from meshai.notifications.formatters.fire import format as fire_format
|
||||
from meshai.notifications.formatters._budget import budget_for
|
||||
|
||||
class _FakeEvent:
|
||||
def __init__(self, data, category=None):
|
||||
self.data = data
|
||||
self.category = category
|
||||
|
||||
conn = get_db()
|
||||
now = int(time.time())
|
||||
_seed_fire(conn, irwin_id="IA-1", name="IA 1",
|
||||
|
|
@ -163,22 +133,19 @@ class TestTombstoneAfterNewBroadcast:
|
|||
last_broadcast_at=now - 600, # 10 min ago
|
||||
last_event_at=now - 600)
|
||||
|
||||
data = {}
|
||||
wire = handle_wfigs(
|
||||
normalized={"_kind": "wfigs_tombstone", "irwin_id": "IA-1"},
|
||||
envelope={"data": {"category": "wildfire", "severity": "immediate"}},
|
||||
subject="wfigs.tombstone",
|
||||
data=data,
|
||||
now=now,
|
||||
)
|
||||
assert wire is not None, "tombstone should produce wire"
|
||||
assert "✅" in wire, "closure wire should contain checkmark"
|
||||
assert "IA 1" in wire, "closure wire should name the fire"
|
||||
assert data["category"] == "wildfire_closed"
|
||||
gate = fire_decide({"_kind": "wfigs_tombstone", "irwin_id": "IA-1"},
|
||||
source="wfigs", now=float(now))
|
||||
assert gate.broadcast is True, "tombstone should broadcast"
|
||||
assert gate.data_patch["category"] == "wildfire_closed"
|
||||
# See module docstring: downgraded from "immediate" to "priority"
|
||||
# by commit 2f677e85 to prevent Grouper/cooldown bypass.
|
||||
assert data["_severity_override"] == "priority"
|
||||
assert callable(data.get("_on_broadcast_committed"))
|
||||
assert gate.data_patch["_severity_override"] == "priority"
|
||||
assert callable(gate.commit)
|
||||
|
||||
wire = fire_format(_FakeEvent(gate.data_patch, category="wildfire_closed"),
|
||||
now=0.0, budget=budget_for("wfigs"))
|
||||
assert "✅" in wire, "closure wire should contain checkmark"
|
||||
assert "IA 1" in wire, "closure wire should name the fire"
|
||||
|
||||
def test_no_wire_when_never_broadcast(self):
|
||||
"""Fire that was never broadcast should NOT get a closure wire."""
|
||||
|
|
@ -189,36 +156,9 @@ class TestTombstoneAfterNewBroadcast:
|
|||
last_broadcast_at=None, # never broadcast
|
||||
last_event_at=now - 600)
|
||||
|
||||
data = {}
|
||||
wire = handle_wfigs(
|
||||
normalized={"_kind": "wfigs_tombstone", "irwin_id": "SILENT-1"},
|
||||
envelope={"data": {"category": "wildfire", "severity": "immediate"}},
|
||||
subject="wfigs.tombstone",
|
||||
data=data,
|
||||
now=now,
|
||||
)
|
||||
assert wire is None, "no closure wire for never-broadcast fire"
|
||||
|
||||
def test_tombstoned_at_stamped(self):
|
||||
"""Tombstone should stamp tombstoned_at on the fires row."""
|
||||
conn = get_db()
|
||||
now = int(time.time())
|
||||
_seed_fire(conn, irwin_id="STAMP-1", name="Stamp Fire",
|
||||
acres=10, contained=50,
|
||||
last_broadcast_at=now - 3600)
|
||||
|
||||
handle_wfigs(
|
||||
normalized={"_kind": "wfigs_tombstone", "irwin_id": "STAMP-1"},
|
||||
envelope={"data": {"category": "wildfire", "severity": "immediate"}},
|
||||
subject="wfigs.tombstone",
|
||||
data={},
|
||||
now=now,
|
||||
)
|
||||
row = conn.execute(
|
||||
"SELECT tombstoned_at FROM fires WHERE irwin_id='STAMP-1'"
|
||||
).fetchone()
|
||||
assert row is not None
|
||||
assert row["tombstoned_at"] == now
|
||||
gate = fire_decide({"_kind": "wfigs_tombstone", "irwin_id": "SILENT-1"},
|
||||
source="wfigs", now=float(now))
|
||||
assert gate.broadcast is False, "no closure wire for never-broadcast fire"
|
||||
|
||||
|
||||
class TestEnvSummaryExcludesContainedTombstoned:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue