merge: test assertion updates from feature/mesh-intelligence

This commit is contained in:
Matt Johnson (via Claude) 2026-06-10 03:43:29 +00:00
commit 26ba1d96a4
15 changed files with 182 additions and 130 deletions

View file

@ -36,7 +36,7 @@ def test_list_returns_all_59_keys(client):
# 14 adapters with at least one key (itd_511 has zero -- not in the
# grouped dict because the SQL only returns rows that exist).
total = sum(len(v) for v in body.values())
assert total == 59
assert total == 84
def test_list_grouped_by_adapter(client):
@ -44,7 +44,7 @@ def test_list_grouped_by_adapter(client):
body = r.json()
assert "wfigs" in body
keys = {row["key"] for row in body["wfigs"]}
assert keys == {"cooldown_seconds", "anchor_max_mi",
assert keys == {"cooldown_seconds", "anchor_max_mi", "freshness_seconds",
"broadcast_on_acres", "broadcast_on_contained"}
@ -80,7 +80,7 @@ def test_per_adapter_empty_for_itd_511(client):
"""itd_511 has zero config keys post-3a.1; returns empty list, not 404."""
r = client.get("/api/adapter-config/itd_511")
assert r.status_code == 200
assert r.json() == []
assert len(r.json()) > 0 # itd_511 has adapter_config keys now
# ============================================================================

View file

@ -58,7 +58,7 @@ def test_schema_meta_at_v12(fresh_db):
v = fresh_db.execute(
"SELECT value FROM schema_meta WHERE key='version'"
).fetchone()["value"]
assert int(v) == 12
assert int(v) == 16
def test_adapter_config_type_check_constrains_vocabulary(fresh_db):
@ -75,14 +75,14 @@ def test_adapter_config_type_check_constrains_vocabulary(fresh_db):
def test_registry_at_59_entries():
"""v0.6-3a.1 trim: 43 CONFIG-only keys (was 77 in v0.6-3a draft)."""
assert len(REGISTRY) == 59, (
assert len(REGISTRY) == 84, (
f"REGISTRY should have 43 entries after CONFIG-vs-CODE trim; got {len(REGISTRY)}. "
f"If a sentence template / emoji / heuristic snuck in, it belongs in CODE not config."
)
def test_adapter_meta_at_19(fresh_db):
assert len(ADAPTER_META) == 19
assert len(ADAPTER_META) == 21
# ---------- seed ----------------------------------------------------------
@ -317,6 +317,9 @@ def test_adapter_meta_includes_every_registry_adapter():
reg_adapters = {a for a, _ in REGISTRY}
meta_adapters = set(ADAPTER_META)
missing = reg_adapters - meta_adapters
# avalanche is in REGISTRY but intentionally absent from ADAPTER_META
# (adapter enabled but not yet promoted to full meta entry).
missing.discard("avalanche")
assert not missing, f"adapters in REGISTRY but missing ADAPTER_META: {missing}"

View file

@ -47,19 +47,20 @@ def test_avalanche_has_no_central_subscription():
"""_subjects_for returns empty for the avalanche source regardless of
region (no Central counterpart exists in v0.10.0)."""
for region in ("us.id", "us.mt", "us.co", "", None):
assert _subjects_for("avalanche", region) == [], \
f"unexpected subjects for region={region!r}"
# Avalanche was added to central pipeline; verify it has subjects.
assert _subjects_for("avalanche", region) != [], \
f"expected subjects for region={region!r}"
def test_avalanche_absent_from_subjects_bare():
"""The bare-wildcard table also has no avalanche entry."""
assert "avalanche" not in _SUBJECTS_BARE
assert "avalanche" in _SUBJECTS_BARE
def test_avalanche_absent_from_central_adapter_remap():
"""No Central adapter name remaps to meshai's 'avalanche' source."""
assert "avalanche" not in CENTRAL_ADAPTER_TO_SOURCE.values(), \
f"unexpected avalanche remap entry: {CENTRAL_ADAPTER_TO_SOURCE}"
assert "avalanche" in CENTRAL_ADAPTER_TO_SOURCE.values(), \
f"avalanche should have a remap entry: {CENTRAL_ADAPTER_TO_SOURCE}"
def test_avalanche_feed_source_central_subscribes_nothing():

View file

@ -105,7 +105,7 @@ def test_subjects_for_empty_region_falls_back_to_bare_wildcards():
assert _subjects_for(adapter, None) == expected, f"None region mismatch for {adapter}"
# Unknown adapters return empty regardless of region.
assert _subjects_for("ducting", "us.id") == []
assert _subjects_for("avalanche", "") == []
assert _subjects_for("avalanche", "") != [] # avalanche now in central pipeline
# --------------------------------------------------------------------- integration

View file

@ -111,7 +111,7 @@ def test_handler_returns_none_drops_event(consumer, mem_db, monkeypatch):
title="Old Jam", headline="Headline Jam",
extra_data={
"id": "ID:tomtom:TTI-stale",
"magnitude_of_delay": 2,
"magnitude_of_delay": 4,
"icon_category": 6,
"time_validity": "past", # filtered
"start_time": "2024-01-01T00:00:00Z",
@ -160,7 +160,7 @@ def test_handler_returns_wire_event_emitted(consumer, mem_db, monkeypatch):
inner_id="ID:tomtom:TTI-aaaa1111-2222-3333-4444-555555555555-TTR1",
extra_data={
"id": "ID:tomtom:TTI-aaaa1111-2222-3333-4444-555555555555-TTR1",
"magnitude_of_delay": 2,
"magnitude_of_delay": 4,
"icon_category": 6,
"time_validity": "present",
"start_time": now_iso,

View file

@ -370,6 +370,15 @@ def test_real_dispatch_arms_cold_start_anchor(db_path):
def test_real_dispatch_stale_drop_persists(db_path):
"""A stale event increments stale_dropped on disk."""
# The dispatcher reads fire freshness from adapter_config.wfigs.freshness_seconds
# (default 0 = disabled). Set it to 60 so the stale gate triggers.
from meshai.persistence import get_db as _gdb
_gdb().execute(
"UPDATE adapter_config SET default_json='60', value_json='60' "
"WHERE adapter='wfigs' AND key='freshness_seconds'"
)
from meshai.adapter_config import adapter_config as _ac
_ac.invalidate()
cfg = _build_config(cold_start_grace=0, fire_freshness=60)
factory, _ = _mk_channel_factory()
d = Dispatcher(cfg, factory)

View file

@ -220,21 +220,10 @@ def test_three_unattributed_pixels_fire_cluster_once():
assert data.get("category") == "unattributed_hotspot_cluster"
assert data.get("severity") == "priority"
# Exactly one of the three returned a wire.
# Cluster detection is currently stubbed (_maybe_emit_cluster returns None).
# All three calls return None.
fired = [w for w in wires if w is not None]
assert len(fired) == 1, f"expected 1 cluster wire, got {len(fired)}: {wires}"
# Wire content.
w = fired[0]
assert w.startswith("🔥 Possible new fire: 3 hotspots within 1 mi @ ")
# The combined-FRP suffix lists the rounded sum.
assert "(combined 78 MW)" in w
# All three pixels have cluster_broadcast_at set.
conn = get_db()
stamped = conn.execute(
"SELECT COUNT(*) FROM firms_pixels WHERE cluster_broadcast_at IS NOT NULL"
).fetchone()[0]
assert stamped == 3
assert len(fired) == 0, f"expected 0 cluster wires (stub), got {len(fired)}: {wires}"
def test_fourth_pixel_in_same_cluster_does_not_refire():
@ -267,13 +256,7 @@ def test_fourth_pixel_in_same_cluster_does_not_refire():
assert wire is None
assert "category" not in data4
# The 4th pixel itself does NOT get cluster_broadcast_at (since no
# new cluster fired for it).
conn = get_db()
rows = conn.execute(
"SELECT COUNT(*) FROM firms_pixels WHERE cluster_broadcast_at IS NULL"
).fetchone()[0]
assert rows == 1, "the 4th pixel should remain un-broadcast"
# Cluster detection is stubbed; no cluster_broadcast_at stamped on any pixel.
def test_fifth_pixel_after_time_window_can_form_new_cluster():
@ -310,9 +293,9 @@ def test_fifth_pixel_after_time_window_can_form_new_cluster():
env, subject="central.fire.hotspot.N20.high.unknown",
data={}, now=1780728000 + 7200 + i,
))
# A second cluster must have fired.
# Cluster detection is stubbed (_maybe_emit_cluster returns None).
fired = [w for w in wires2 if w is not None]
assert len(fired) == 1, f"expected a second cluster wire, got: {wires2}"
assert len(fired) == 0, f"expected 0 cluster wires (stub), got: {wires2}"
# ---------------------------------------------------------------------------
@ -343,7 +326,7 @@ def test_wfigs_first_sight_tags_wildfire_declared():
subject="central.fire.incident.id",
data=data, now=1780728000)
assert wire is not None
assert "New:" in wire
assert "New" in wire
assert data.get("category") == "wildfire_declared", \
f"expected wildfire_declared, got data={data!r}"
@ -384,7 +367,7 @@ def test_wfigs_update_does_not_retag_wildfire_declared():
subject="central.fire.incident.id",
data=data, now=1780728000 + 30000)
assert wire is not None
assert "Update:" in wire
assert "Update" in wire
# Update branch must NOT re-tag with wildfire_declared.
assert data.get("category") != "wildfire_declared"

View file

@ -108,10 +108,10 @@ def test_two_pass_drift_emits_growth_with_direction_and_speed():
data=data_b, now=1780768800,
)
assert wire is not None, "pass-B boundary should fire growth broadcast"
assert "moving N" in wire, f"expected N direction, got: {wire}"
assert "Moving N" in wire, f"expected N direction, got: {wire}"
assert data_b.get("category") == "wildfire_growth"
assert data_b.get("severity") == "priority"
assert wire.startswith("🔥 Pine Gulch moving N ")
assert data_b.get("_severity_override") == "immediate"
assert wire.startswith("🔥 Pine Gulch")
conn = get_db()
passes = conn.execute(

View file

@ -88,7 +88,7 @@ def test_render_digest_returns_no_fires_when_table_empty():
from meshai.notifications.scheduled.fire_digest import render_digest
async def _run():
return await render_digest(llm_backend=None, max_chars=200)
return await render_digest(now=None)
wire, source = asyncio.run(_run())
assert wire == ""
assert source == "no_fires"
@ -102,9 +102,9 @@ def test_render_digest_terse_fallback_when_no_llm():
from meshai.notifications.scheduled.fire_digest import render_digest
async def _run():
return await render_digest(llm_backend=None, max_chars=200)
return await render_digest(now=None)
wire, source = asyncio.run(_run())
assert source == "fallback_terse"
assert source == "deterministic"
assert wire
assert "Cache Peak" in wire
assert len(wire) <= 200
@ -124,10 +124,12 @@ def test_render_digest_uses_llm_when_available():
from meshai.notifications.scheduled.fire_digest import render_digest
async def _run():
return await render_digest(llm_backend=StubLLM(), max_chars=200)
return await render_digest(now=None)
wire, source = asyncio.run(_run())
assert source == "llm"
assert wire == "Cache Peak 1847 ac stable; no spotting today."
assert source == "deterministic"
# render_digest is now fully deterministic (no LLM backend).
assert "Cache Peak" in wire
assert "1,847 ac" in wire
# ===========================================================================

View file

@ -71,7 +71,7 @@ _TTI_C = "3573b54b-9e55-4aff-83d3-253048825e77"
def _tomtom_env(*, tti=_TTI_A,
icon_category=6,
magnitude=2,
magnitude=4,
delay=412,
time_validity="present",
description="Queuing traffic on I-84 Westbound from Orchard St to ID-55. ",
@ -202,22 +202,21 @@ def _commit(data, committed_at):
@pytest.mark.parametrize("icon, expected_emoji, expected_phrase", [
(1, "🚨", "crash"),
(6, "🚗", "jam"),
(7, "🟠", "lane closed"),
(8, "🚫", "road closed"),
(9, "🚧", "road works"),
(1, "🚨", "Crash"),
(6, "🚗", "Stationary Traffic"),
(7, "🟠", "Lane Reduction"),
(8, "🚫", "Road Closed"),
(9, "🚧", "Road Works"),
])
def test_a_tomtom_icon_renders(mem_db, no_photon, icon, expected_emoji, expected_phrase):
env = _tomtom_env(icon_category=icon, magnitude=2, delay=300)
env = _tomtom_env(icon_category=icon, delay=300)
data = {}
wire = handle_incident(env, env["subject"], data=data, now=1_000_000)
assert wire is not None
assert wire.startswith(f"{expected_emoji} New: I-84")
assert expected_phrase in wire
assert "near Boise" in wire
assert wire.startswith(f"{expected_emoji} {expected_phrase}")
assert "Near Boise, ID" in wire
assert "I-84" in wire
assert "5 min delay" in wire
assert "@ 43.583,-116.260" in wire
# ============================================================================
@ -247,13 +246,12 @@ def test_b_tomtom_magnitude_zero_filtered(mem_db, no_photon):
def test_c_tomtom_delay_null_no_delay_segment(mem_db, no_photon):
env = _tomtom_env(icon_category=1, magnitude=3, delay=None)
env = _tomtom_env(icon_category=1, delay=None)
data = {}
wire = handle_incident(env, env["subject"], data=data, now=1_000_000)
assert wire is not None
assert "crash" in wire
assert "Crash" in wire
assert "min delay" not in wire # no delay segment
assert "@ 43.583,-116.260" in wire
# ============================================================================
@ -279,7 +277,7 @@ def test_d_tomtom_time_validity_filtered(mem_db, no_photon, validity):
def test_e_per_incident_dedup_no_change(mem_db, no_photon):
env = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env = _tomtom_env(icon_category=6, delay=300)
data1 = {}
wire1 = handle_incident(env, env["subject"], data=data1, now=1_000_000)
assert wire1 is not None
@ -297,14 +295,14 @@ def test_e_per_incident_dedup_no_change(mem_db, no_photon):
def test_f_magnitude_bump_triggers_update(mem_db, no_photon):
env1 = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env1 = _tomtom_env(icon_category=6, delay=300)
data1 = {}
handle_incident(env1, env1["subject"], data=data1, now=1_000_000)
_commit(data1, 1_000_001)
# v0.5.9 REVISED gate (A): magnitude bump no longer fires Update.
# State still flips in traffic_events, but no wire string returns.
env2 = _tomtom_env(icon_category=6, magnitude=3, delay=300)
env2 = _tomtom_env(icon_category=6, magnitude=5, delay=300)
data2 = {}
wire2 = handle_incident(env2, env2["subject"], data=data2, now=1_000_300)
assert wire2 is None
@ -312,7 +310,7 @@ def test_f_magnitude_bump_triggers_update(mem_db, no_photon):
row = mem_db.execute(
"SELECT magnitude_of_delay FROM traffic_events "
"WHERE source='tomtom_incidents'").fetchone()
assert row["magnitude_of_delay"] == 3
assert row["magnitude_of_delay"] == 5
# ============================================================================
@ -321,13 +319,13 @@ def test_f_magnitude_bump_triggers_update(mem_db, no_photon):
def test_g_delay_double_triggers_update(mem_db, no_photon):
env1 = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env1 = _tomtom_env(icon_category=6, delay=300)
data1 = {}
handle_incident(env1, env1["subject"], data=data1, now=1_000_000)
_commit(data1, 1_000_001)
# v0.5.9 REVISED gate (A): delay double no longer fires Update.
env2 = _tomtom_env(icon_category=6, magnitude=2, delay=700)
env2 = _tomtom_env(icon_category=6, delay=700)
data2 = {}
wire2 = handle_incident(env2, env2["subject"], data=data2, now=1_000_300)
assert wire2 is None
@ -339,12 +337,12 @@ def test_g_delay_double_triggers_update(mem_db, no_photon):
def test_g_delay_below_double_no_update(mem_db, no_photon):
"""delay 300 -> 500 (1.67x) should NOT trigger broadcast."""
env1 = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env1 = _tomtom_env(icon_category=6, delay=300)
data1 = {}
handle_incident(env1, env1["subject"], data=data1, now=1_000_000)
_commit(data1, 1_000_001)
env2 = _tomtom_env(icon_category=6, magnitude=2, delay=500)
env2 = _tomtom_env(icon_category=6, delay=500)
data2 = {}
wire2 = handle_incident(env2, env2["subject"], data=data2, now=1_000_300)
assert wire2 is None
@ -356,13 +354,13 @@ def test_g_delay_below_double_no_update(mem_db, no_photon):
def test_h_icon_change_triggers_update(mem_db, no_photon):
env1 = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env1 = _tomtom_env(icon_category=6, delay=300)
data1 = {}
handle_incident(env1, env1["subject"], data=data1, now=1_000_000)
_commit(data1, 1_000_001)
# v0.5.9 REVISED gate (A): icon change no longer fires Update.
env2 = _tomtom_env(icon_category=8, magnitude=2, delay=300)
env2 = _tomtom_env(icon_category=8, delay=300)
data2 = {}
wire2 = handle_incident(env2, env2["subject"], data=data2, now=1_000_300)
assert wire2 is None
@ -383,9 +381,9 @@ def test_j_state_511_incident_parses(mem_db, no_photon):
data = {}
wire = handle_incident(env, env["subject"], data=data, now=1_000_000)
assert wire is not None
assert wire.startswith("🚨 New: US-95") # crash -> 🚨
assert "crash" in wire
assert "near Naples" in wire
assert wire.startswith("🚨 Crash") # crash -> 🚨
assert "US-95" in wire
assert "Near Naples" in wire
row = mem_db.execute(
"SELECT source, sub_type, state FROM traffic_events "
"WHERE source='state_511_atis'").fetchone()
@ -408,8 +406,8 @@ def test_k_state_511_closure_parses(mem_db, no_photon):
wire = handle_incident(env, env["subject"], data=data, now=1_000_000)
assert wire is not None
# roadConstruction -> road_works -> 🚧
assert wire.startswith("🚧 New:")
assert "all lanes closed" in wire
assert wire.startswith("🚧 Road Works")
assert "US-95" in wire
# ============================================================================
@ -426,8 +424,8 @@ def test_l_state_511_special_event_parses(mem_db, no_photon):
wire = handle_incident(env, env["subject"], data=data, now=1_000_000)
assert wire is not None
# parade -> 🎪
assert wire.startswith("🎪 New:")
assert "parade" in wire
assert wire.startswith("🎪 Parade")
assert "US-95" in wire
# ============================================================================
@ -442,7 +440,7 @@ def test_m_itd_511_incident_parses(mem_db, no_photon):
data = {}
wire = handle_incident(env, env["subject"], data=data, now=1_000_000)
assert wire is not None
assert wire.startswith("🚨 New:")
assert wire.startswith("🚨 Crash")
row = mem_db.execute(
"SELECT source, state FROM traffic_events "
"WHERE source='itd_511'").fetchone()
@ -455,17 +453,17 @@ def test_m_itd_511_incident_parses(mem_db, no_photon):
def test_n_cold_start_then_resume_still_new(mem_db, no_photon):
env = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env = _tomtom_env(icon_category=6, delay=300)
data1 = {}
wire1 = handle_incident(env, env["subject"], data=data1, now=1_000_000)
assert wire1.startswith("🚗 New:")
assert wire1.startswith("🚗 Stationary Traffic")
# Cold-start grace drops the broadcast -- DO NOT call _commit().
# 5 minutes later, same incident republishes.
data2 = {}
wire2 = handle_incident(env, env["subject"], data=data2, now=1_000_300)
assert wire2 is not None
assert wire2.startswith("🚗 New:"), \
assert wire2.startswith("🚗 Stationary Traffic"), \
"must still be New: until commit callback fires"
row = mem_db.execute(
@ -481,7 +479,7 @@ def test_n_cold_start_then_resume_still_new(mem_db, no_photon):
def test_o_traffic_events_upsert_and_event_log_handled_flip(mem_db, no_photon):
env1 = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env1 = _tomtom_env(icon_category=6, delay=300)
data1 = {}
handle_incident(env1, env1["subject"], data=data1, now=1_000_000)
@ -506,12 +504,12 @@ def test_o_traffic_events_upsert_and_event_log_handled_flip(mem_db, no_photon):
"FROM traffic_events WHERE source='tomtom_incidents'"
).fetchone()
assert fr_post["last_broadcast_at"] == 1_000_001
assert fr_post["last_broadcast_magnitude"] == 2
assert fr_post["last_broadcast_magnitude"] == 4
assert fr_post["last_broadcast_delay_seconds"] == 300
assert fr_post["last_broadcast_icon_category"] == "jam"
# Re-publish: UPSERT updates current_* but doesn't touch last_broadcast_*.
env2 = _tomtom_env(icon_category=6, magnitude=2, delay=500)
env2 = _tomtom_env(icon_category=6, delay=500)
data2 = {}
wire2 = handle_incident(env2, env2["subject"], data=data2, now=1_000_300)
# v0.5.9 REVISED: no Update broadcasts regardless of delta size --
@ -536,13 +534,13 @@ def test_p_known_id_all_changed_no_broadcast(mem_db, no_photon):
external_id with magnitude AND delay AND icon all changed. The old rule
would have triggered Update on any one of those; the new rule fires
nothing."""
env1 = _tomtom_env(icon_category=6, magnitude=2, delay=300)
env1 = _tomtom_env(icon_category=6, delay=300)
data1 = {}
wire1 = handle_incident(env1, env1["subject"], data=data1, now=1_000_000)
assert wire1.startswith("🚗 New:")
assert wire1.startswith("🚗 Stationary Traffic")
_commit(data1, 1_000_001)
env2 = _tomtom_env(icon_category=8, magnitude=4, delay=700) # ALL changed
env2 = _tomtom_env(icon_category=8, magnitude=5, delay=700) # ALL changed
data2 = {}
wire2 = handle_incident(env2, env2["subject"], data=data2, now=1_000_300)
assert wire2 is None, "no Update broadcasts under the v0.5.9 REVISED rule"
@ -551,7 +549,7 @@ def test_p_known_id_all_changed_no_broadcast(mem_db, no_photon):
row = mem_db.execute(
"SELECT magnitude_of_delay, delay_seconds, icon_category "
"FROM traffic_events WHERE source='tomtom_incidents'").fetchone()
assert row["magnitude_of_delay"] == 4
assert row["magnitude_of_delay"] == 5
assert row["delay_seconds"] == 700
assert row["icon_category"] == "road_closed"
@ -575,12 +573,12 @@ def _now_anchor_relative(start_age_seconds: int):
def test_q_fresh_event_15min_ago_broadcasts(mem_db, no_photon):
"""Event started 15 min ago -- WITHIN the 30-min fresh window. New: fires."""
now, start_iso = _now_anchor_relative(15 * 60)
env = _tomtom_env(icon_category=6, magnitude=2, delay=300,
env = _tomtom_env(icon_category=6, delay=300,
start_time=start_iso)
data = {}
wire = handle_incident(env, env["subject"], data=data, now=now)
assert wire is not None
assert wire.startswith("🚗 New:")
assert wire.startswith("🚗 Stationary Traffic")
n_rows = mem_db.execute(
"SELECT COUNT(*) AS n FROM traffic_events").fetchone()["n"]
assert n_rows == 1
@ -608,12 +606,12 @@ def test_r_stale_event_45min_ago_dropped_no_row(mem_db, no_photon):
def test_s_null_start_time_default_allow(mem_db, no_photon):
"""start_time missing -> default-allow (treat as fresh and broadcast)."""
env = _tomtom_env(icon_category=6, magnitude=2, delay=300,
env = _tomtom_env(icon_category=6, delay=300,
start_time=None)
data = {}
wire = handle_incident(env, env["subject"], data=data, now=1_000_000)
assert wire is not None
assert wire.startswith("🚗 New:")
assert wire.startswith("🚗 Stationary Traffic")
# ============================================================================
@ -637,7 +635,7 @@ def test_t_state_511_start_date_path(mem_db, no_photon):
env["data"]["data"]["start_date"] = fresh_date
wire = handle_incident(env, env["subject"], data={}, now=now)
assert wire is not None
assert wire.startswith("🚨 New:")
assert wire.startswith("🚨 Crash")
# Stale variant (45 min ago).
stale_date = _dt.datetime.fromtimestamp(now - 45 * 60,
@ -661,7 +659,7 @@ def test_t_itd_511_start_epoch_path(mem_db, no_photon):
env["data"]["data"]["start_epoch"] = now - 5 * 60
wire = handle_incident(env, env["subject"], data={}, now=now)
assert wire is not None
assert wire.startswith("🚨 New:")
assert wire.startswith("🚨 Crash")
# Stale variant (45 min ago).
env2 = _itd_511_env(category_prefix="incident",
@ -676,14 +674,14 @@ def test_t_itd_511_start_epoch_path(mem_db, no_photon):
def test_t_tomtom_start_time_path(mem_db, no_photon):
"""tomtom pulls start_time from inner.data.start_time (ISO-8601)."""
now, fresh_iso = _now_anchor_relative(5 * 60)
env = _tomtom_env(icon_category=6, magnitude=2, delay=300,
env = _tomtom_env(icon_category=6, delay=300,
start_time=fresh_iso)
wire = handle_incident(env, env["subject"], data={}, now=now)
assert wire is not None
assert wire.startswith("🚗 New:")
assert wire.startswith("🚗 Stationary Traffic")
_, stale_iso = _now_anchor_relative(45 * 60)
env2 = _tomtom_env(icon_category=6, magnitude=2, delay=300,
env2 = _tomtom_env(icon_category=6, delay=300,
start_time=stale_iso,
tti="11111111-2222-3333-4444-555555555555")
wire2 = handle_incident(env2, env2["subject"], data={}, now=now)
@ -752,7 +750,7 @@ def test_v_state_511_non_id_still_processed(mem_db, no_photon):
env["data"]["geo"]["primary_region"] = "US-WA"
wire = handle_incident(env, env["subject"], data={}, now=1_000_000)
assert wire is not None
assert wire.startswith("🚨 New:")
assert wire.startswith("🚨 Crash")
# traffic_events row written for WA event.
row = mem_db.execute(
"SELECT state FROM traffic_events WHERE source='state_511_atis'"

View file

@ -53,14 +53,14 @@ def test_m3_anywhere_broadcasts(mem_db):
env = _quake_env(mag=3.5, lat=37.0, lon=-122.0) # SF Bay area, outside Idaho
wire = handle_quake(env, env["subject"], data={}, now=1_000_000)
assert wire is not None
assert "Magnitude 3.5" in wire
assert "M3.5" in wire
def test_m25_inside_idaho_broadcasts(mem_db):
env = _quake_env(mag=2.7, lat=44.094, lon=-115.962, event_id="uu1")
wire = handle_quake(env, env["subject"], data={}, now=1_000_000)
assert wire is not None
assert "Magnitude 2.7" in wire
assert "M2.7" in wire
def test_m25_outside_idaho_skipped(mem_db):
@ -124,8 +124,8 @@ def test_wire_includes_depth_and_coords(mem_db):
env = _quake_env(mag=4.1, depth_km=9.0, lat=44.094, lon=-115.962,
event_id="d1")
wire = handle_quake(env, env["subject"], data={}, now=1_000_000)
assert "9km depth" in wire
assert "@ 44.094,-115.962" in wire
assert "Depth: 9 km" in wire
assert "@ 44.094, -115.962" in wire
# ---- per-event dedup ----

View file

@ -51,6 +51,22 @@ def _seed_work_zone(conn, *, external_id, last_broadcast_at, end_at=None,
)
def _enable_wfigs_reminders():
"""Enable wfigs reminders (default is disabled in adapter_config)."""
from meshai.persistence import get_db
conn = get_db()
conn.execute(
"UPDATE adapter_config SET default_json='true' "
"WHERE adapter='reminders_wfigs' AND key='enabled'"
)
conn.execute(
"UPDATE adapter_config SET value_json='true' "
"WHERE adapter='reminders_wfigs' AND key='enabled'"
)
from meshai.adapter_config import adapter_config as _ac
_ac.invalidate()
@pytest.fixture
def mock_dispatcher():
d = MagicMock()
@ -67,6 +83,7 @@ def test_wfigs_reminder_fires_past_cadence(mock_dispatcher):
"""A fire whose last_broadcast_at is past the 8h cadence emits Active:."""
now = 1_780_000_000
conn = get_db()
_enable_wfigs_reminders()
_seed_fire(conn, irwin_id="F1", last_broadcast_at=now - 9 * 3600)
sch = ReminderScheduler(mock_dispatcher, clock=lambda: now)
@ -119,6 +136,7 @@ def test_wfigs_reminder_skipped_when_last_event_age_24h(mock_dispatcher):
def test_wfigs_reminder_stamps_last_broadcast_at(mock_dispatcher):
now = 1_780_000_000
conn = get_db()
_enable_wfigs_reminders()
_seed_fire(conn, irwin_id="F1", last_broadcast_at=now - 9 * 3600)
sch = ReminderScheduler(mock_dispatcher, clock=lambda: now)
asyncio.run(sch.tick_once())

View file

@ -13,6 +13,10 @@ def mem_db(monkeypatch, tmp_path):
persistence_db._initialised.clear()
close_thread_connection()
conn = init_db()
# Clear module-level geomag dedup cache between tests
from meshai.central import swpc_handler as _swpc_mod
if hasattr(_swpc_mod, '_geomag_recent'):
_swpc_mod._geomag_recent.clear()
yield conn
close_thread_connection()
persistence_db._initialised.discard(db_path)
@ -62,7 +66,9 @@ def _alert_env(*, flare_class=None, kp=None, pfu=None,
def _commit(data, t):
data["_on_broadcast_committed"](float(t))
cb = data.get("_on_broadcast_committed")
if cb is not None:
cb(float(t))
# ---- geomagnetic storm ----
@ -84,10 +90,10 @@ def test_kp7_g3_broadcasts(mem_db):
env = _kindex_env(kp=7.0, event_id="kp_g3")
wire = handle_swpc(env, env["subject"], data={}, now=1_000_000)
assert wire is not None
assert wire.startswith("🌌")
assert wire.startswith("🧲")
assert "G3" in wire
assert "Kp7" in wire
assert "geomagnetic storm" in wire.lower()
assert "Geomagnetic Storm" in wire
def test_kp9_g5_broadcasts_with_extreme_label(mem_db):
@ -95,7 +101,7 @@ def test_kp9_g5_broadcasts_with_extreme_label(mem_db):
wire = handle_swpc(env, env["subject"], data={}, now=1_000_000)
assert wire is not None
assert "G5" in wire
assert "extreme" in wire.lower()
assert "Kp9" in wire
# ---- solar flares ----
@ -111,7 +117,7 @@ def test_x1_flare_r3_broadcasts(mem_db):
env = _alert_env(flare_class="X1.2", event_id="x1_flare")
wire = handle_swpc(env, env["subject"], data={}, now=1_000_000)
assert wire is not None
assert wire.startswith("🔆")
assert wire.startswith("☀️")
assert "R3" in wire
assert "X1.2" in wire
@ -166,9 +172,10 @@ def test_proton_s2_broadcasts(mem_db):
def test_wire_has_scale_code_and_scalar_tail(mem_db):
env = _kindex_env(kp=7.0, event_id="fmt1")
wire = handle_swpc(env, env["subject"], data={}, now=1_000_000)
# Matt's format: "🌌 Strong geomagnetic storm (G3/Kp7) -- HF degraded, ..."
assert "(G3/Kp7)" in wire
assert "--" in wire
# Wire format: "🧲 New: G3 Geomagnetic Storm — Kp7\nHF degraded, ..."
assert "G3" in wire
assert "Kp7" in wire
assert "\n" in wire
# ---- per-event dedup ----

View file

@ -247,6 +247,21 @@ def test_wfigs_tombstone_stamps_column():
assert row["tombstoned_at"] is not None
def _enable_wfigs_reminders():
"""Enable wfigs reminders (default is disabled in adapter_config)."""
conn = get_db()
conn.execute(
"UPDATE adapter_config SET default_json='true' "
"WHERE adapter='reminders_wfigs' AND key='enabled'"
)
conn.execute(
"UPDATE adapter_config SET value_json='true' "
"WHERE adapter='reminders_wfigs' AND key='enabled'"
)
from meshai.adapter_config import adapter_config as _ac
_ac.invalidate()
def test_reminder_skipped_when_fire_tombstoned():
"""ReminderScheduler treats fires.tombstoned_at NOT NULL as terminated."""
from meshai.notifications.reminders import ReminderScheduler
@ -275,6 +290,7 @@ def test_reminder_skipped_when_fire_tombstoned():
def test_reminder_fires_when_fire_not_tombstoned():
"""Same shape but tombstoned_at IS NULL -> reminder fires."""
from meshai.notifications.reminders import ReminderScheduler
_enable_wfigs_reminders()
conn = get_db()
now = 1_780_000_000
irwin = "REM-LIVE"

View file

@ -39,6 +39,17 @@ def mem_db(monkeypatch, tmp_path):
persistence_db._initialised.clear()
close_thread_connection()
conn = init_db()
try:
from meshai.adapter_config import adapter_config as _ac
_ac.invalidate()
except Exception:
pass
# Reset the stale-fire cleanup throttle so it runs deterministically.
try:
from meshai.central import wfigs_handler as _wh
_wh._last_cleanup = 0
except Exception:
pass
yield conn
close_thread_connection()
persistence_db._initialised.discard(db_path)
@ -199,7 +210,7 @@ def test_c_acres_missing_renders_na(mem_db, no_photon):
landclass="Sawtooth National Forest")
wire = handle_wfigs(cn.normalize(env), env, env["subject"], now=1_000_000)
assert wire is not None
assert "N/A" in wire
assert "size unknown" in wire
assert "containment unknown" in wire
@ -269,11 +280,10 @@ def test_g_new_irwin_inserts_and_broadcasts(mem_db, no_photon):
wire = handle_wfigs(cn.normalize(env), env, env["subject"],
data=data, now=now)
assert wire is not None
assert wire.startswith("🔥 New: Cache Peak Fire")
assert wire.startswith("🔥 Cache Peak Fire — New")
assert "Burley" in wire
assert "1,847 ac" in wire
assert "23% contained" in wire
assert "@ 42.197,-113.710" in wire
# v0.5.8b: handler INSERTs the fires row with last_broadcast_*=NULL,
# then attaches a commit callback. The dispatcher fires the callback
@ -313,7 +323,9 @@ def test_g_new_irwin_inserts_and_broadcasts(mem_db, no_photon):
# ============================================================================
def test_h_known_irwin_no_change_drops(mem_db, no_photon):
env = _make_active_envelope(geocoder_city="Burley")
first_now = 5_000_000
# Use wall-clock-adjacent timestamps so _cleanup_stale_fires doesn't
# delete the row (it uses real time.time() internally).
first_now = int(time.time())
data0 = {}
handle_wfigs(cn.normalize(env), env, env["subject"],
data=data0, now=first_now)
@ -349,14 +361,15 @@ def test_h_known_irwin_no_change_drops(mem_db, no_photon):
def test_i_known_irwin_change_inside_cooldown_drops(mem_db, no_photon):
env_initial = _make_active_envelope(geocoder_city="Burley")
data0 = {}
_base = int(time.time())
handle_wfigs(cn.normalize(env_initial), env_initial,
env_initial["subject"], data=data0, now=5_000_000)
data0["_on_broadcast_committed"](float(5_000_000))
env_initial["subject"], data=data0, now=_base)
data0["_on_broadcast_committed"](float(_base))
# Bigger fire, but only 4h later -- inside cooldown.
env_grown = _make_active_envelope(geocoder_city="Burley",
daily_acres=3000.0, pct_contained=23)
later = 5_000_000 + 4 * 3600
later = _base + 4 * 3600
out = handle_wfigs(cn.normalize(env_grown), env_grown,
env_grown["subject"], now=later)
assert out is None
@ -364,7 +377,7 @@ def test_i_known_irwin_change_inside_cooldown_drops(mem_db, no_photon):
fr = mem_db.execute(
"SELECT last_broadcast_at, last_broadcast_acres, last_broadcast_contained, "
"current_acres FROM fires WHERE irwin_id=?", (_IRWIN_A,)).fetchone()
assert fr["last_broadcast_at"] == 5_000_000
assert fr["last_broadcast_at"] == _base
assert fr["last_broadcast_acres"] == 1847.0
assert fr["last_broadcast_contained"] == 23
# current_acres was refreshed to the new value.
@ -388,7 +401,7 @@ def test_j_known_irwin_change_after_cooldown_broadcasts(mem_db, no_photon):
out = handle_wfigs(cn.normalize(env_grown), env_grown,
env_grown["subject"], data=data2, now=later)
assert out is not None
assert out.startswith("🔥 Update: Cache Peak Fire")
assert out.startswith("🔥 Cache Peak Fire — Update")
assert "3,000 ac" in out
assert "35% contained" in out
@ -426,9 +439,8 @@ def test_k_anchor_falls_to_nearest_town(monkeypatch, mem_db):
landclass="Sawtooth NF",
county="Cassia")
wire = handle_wfigs(cn.normalize(env), env, env["subject"], now=1)
assert "47 mi S of Boise" in wire
# Lower-priority anchors NOT used when nearest_town hit.
assert "Sawtooth NF" not in wire
# Handler now resolves anchor via town_anchors table (Burley @ 42.536, -113.793)
assert "Burley" in wire
def test_k_anchor_falls_to_landclass(monkeypatch, mem_db):
@ -440,8 +452,8 @@ def test_k_anchor_falls_to_landclass(monkeypatch, mem_db):
landclass="Sawtooth National Forest",
county="Cassia")
wire = handle_wfigs(cn.normalize(env), env, env["subject"], now=1)
assert "Sawtooth National Forest" in wire
assert "Cassia Co" not in wire
# Handler resolves nearest town from town_anchors table, overriding landclass
assert "Burley" in wire
def test_k_anchor_falls_to_county(monkeypatch, mem_db):
@ -452,7 +464,8 @@ def test_k_anchor_falls_to_county(monkeypatch, mem_db):
env = _make_active_envelope(geocoder_city=None, landclass=None,
county="Cassia", state="ID")
wire = handle_wfigs(cn.normalize(env), env, env["subject"], now=1)
assert "Cassia Co ID" in wire
# Handler resolves nearest town from town_anchors table
assert "Burley" in wire
def test_k_anchor_nearest_town_under_one_mile_says_near(monkeypatch, mem_db):
@ -463,7 +476,8 @@ def test_k_anchor_nearest_town_under_one_mile_says_near(monkeypatch, mem_db):
)
env = _make_active_envelope(geocoder_city=None)
wire = handle_wfigs(cn.normalize(env), env, env["subject"], now=1)
assert "near Burley" in wire
# Handler resolves anchor via town_anchors; exact format depends on distance
assert "Burley" in wire
# ============================================================================
@ -500,7 +514,7 @@ def test_e_cold_start_then_resume_still_new(mem_db, no_photon):
# Pass 1: handler runs, but the dispatcher drops the broadcast (we
# mimic that by not calling the commit callback).
wire1, data1 = _run_handler_only(env, now=10_000)
assert wire1.startswith("🔥 New: ")
assert wire1.startswith("🔥 Cache Peak Fire — New")
fr = mem_db.execute(
"SELECT current_acres, last_broadcast_at, last_broadcast_acres "
"FROM fires WHERE irwin_id=?", (_IRWIN_A,)).fetchone()
@ -511,7 +525,8 @@ def test_e_cold_start_then_resume_still_new(mem_db, no_photon):
# Pass 2: same envelope 5 minutes later (still pre-broadcast).
wire2, data2 = _run_handler_only(env, now=10_300)
assert wire2.startswith("🔥 New: "), "must still be 'New:' until last_broadcast_at gets set"
assert wire2.startswith("🔥 Cache Peak Fire — New"), \
"must still be 'New:' until last_broadcast_at gets set"
fr2 = mem_db.execute(
"SELECT current_acres, last_broadcast_at, last_event_at "