meshai/tests
Matt Johnson (via Claude) dd8e687aca feat(v0.7-fire-tracker-1): registry correlation + 2 new categories
Phase 1 of the FIRMS+WFIGS fusion design doc. v13.sql adds fire_pixels
table for per-fire pixel history + spread_radius_mi/current_centroid_*/
last_hotspot_at on fires. FIRMS handler now attributes incoming pixels
to fires via point-in-circle within configurable radius (default 5 mi),
updating per-fire centroid as median of recent pixels. Unattributed
pixels go through a cluster detector: 3+ pixels within 1 mi within 60
min triggers a single unattributed_hotspot_cluster broadcast (Possible
new fire). Two new ALERT_CATEGORIES: wildfire_declared (priority,
WFIGS first-sight) and unattributed_hotspot_cluster (priority, FIRMS
cluster). All thresholds GUI-editable via adapter_config.fires.* and
adapter_config.firms.*. Phases 2-4 (movement analysis, spotting, LLM
summaries) deferred to subsequent commits.

Schema (v13.sql):
- fire_pixels table (irwin_id FK CASCADE, acq_time, lat/lon, frp,
  satellite, pass_id, attributed_at). Indexed on (irwin_id, acq_time)
  for centroid queries + on (acq_time) for Phase 2.
- fires gains spread_radius_mi (nullable; NULL => use global default),
  current_centroid_lat/lon (median of last 24h pixels, distinct from
  the WFIGS-declared anchor lat/lon), last_hotspot_at (Phase 2 halt
  detector).
- firms_pixels gains attributed_at + cluster_broadcast_at + compound
  index on (attributed_at, cluster_broadcast_at, acq_time) for the
  cluster query.

adapter_config (defaults.py REGISTRY + ADAPTER_META):
- fires.spread_radius_mi_default = 5.0 (float)
- firms.cluster_min_pixels = 3 (int)
- firms.cluster_max_radius_mi = 1.0 (float)
- firms.cluster_time_window_minutes = 60 (int)
- ADAPTER_META["fires"] meta block (display_name + description).

ALERT_CATEGORIES (notifications/categories.py):
- wildfire_declared: priority/fire. WFIGS handler tags data["category"]
  on cases (i)+(ii) [INSERT or row-exists-but-never-broadcast]; case
  (iii) Update keeps the existing wildfire_incident category.
- unattributed_hotspot_cluster: priority/fire. FIRMS handler tags
  data["category"] + data["severity"] when emitting the cluster wire.

FIRMS handler (central/firms_handler.py):
- Unchanged storage path: filter, INSERT OR IGNORE into firms_pixels.
- New _attribute_or_cluster() runs on every newly-stored pixel (dedup
  hits skip -- the original insert had its shot already).
- Attribution: bbox prefilter on fires.tombstoned_at IS NULL, then
  exact Haversine to fires(current_centroid_lat ?? lat,
  current_centroid_lon ?? lon) inside spread_radius_mi (per-fire ?? global
  default). Multi-match resolves to nearest (design doc Q2). On match:
  INSERT fire_pixels, UPDATE firms_pixels.attributed_at,
  recompute centroid as median of last 24h pixels for this fire.
- Cluster: on attribution miss, query firms_pixels WHERE attributed_at
  IS NULL AND cluster_broadcast_at IS NULL AND acq_time > NOW-window.
  If count >= cluster_min_pixels, fire the cluster wire and stamp
  cluster_broadcast_at on every member so a 4th arrival cannot re-fire.

WFIGS handler (central/wfigs_handler.py): the existing prefix=New
branches (i)+(ii) now set data["category"]="wildfire_declared".
Existing _render() unchanged.

Wire strings:
- wildfire_declared: re-uses _render(prefix="New") -- emoji + name +
  type + anchor + acres + containment + coords.
- unattributed_hotspot_cluster: _render_cluster_wire() emits
  "Possible new fire: <N> hotspots within <r> mi @ <lat>,<lon>
  (combined <total_frp> MW)".

Tests (tests/test_fire_tracker_phase1.py, 10 cases all green):
- Pixel within radius -> attribution + centroid + last_hotspot_at.
- Centroid recomputes as median across multiple passes.
- Pixel outside radius -> NO attribution + stays unattributed.
- 3 unattributed within 1 mi within 60 min -> cluster broadcast fires
  exactly once, all 3 stamped cluster_broadcast_at.
- 4th pixel in the same footprint -> NO second broadcast (existing
  3 are stamped so SQL filter excludes them).
- 5th-7th pixels 2h later -> form a NEW cluster (window prune fires).
- WFIGS first-sight tags data["category"]="wildfire_declared".
- WFIGS Update branch does NOT retag wildfire_declared.
- New adapter_config rows seeded on init_db.
- ALERT_CATEGORIES contains both new entries with correct toggle/severity.

Live verification on CT108 after rebuild:
- v13 migration applied (schema_meta version=13, no Traceback).
- adapter_config.fires.spread_radius_mi_default = 5.0
- adapter_config.firms.cluster_min_pixels = 3
- adapter_config.firms.cluster_max_radius_mi = 1.0
- adapter_config.firms.cluster_time_window_minutes = 60
- fires gains 4 new columns; firms_pixels gains 2 new columns; fire_pixels
  table created.
- Container healthy, FIRMS pixels continue arriving (126 pre-deploy).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-06 05:34:22 +00:00
..
fixtures/central_envelopes feat(content): v0.5.8-state_511_atis -- central_normalizer with Photon nearest_town + composer bypass + SB->S route normalization 2026-06-04 21:38:40 +00:00
conftest.py feat(v0.6-3a): adapter_config foundation -- migration + defaults registry + typed accessor 2026-06-05 17:06:51 +00:00
test_adapter_avalanche.py feat(notifications): Phase 2.10 avalanche adapter pipeline integration 2026-05-27 23:08:24 +00:00
test_adapter_config_api.py feat(v0.6-tail): close 5 v0.6-phase1-complete.md follow-ups 2026-06-05 21:37:05 +00:00
test_adapter_config_foundation.py feat(v0.6-tail): close 5 v0.6-phase1-complete.md follow-ups 2026-06-05 21:37:05 +00:00
test_adapter_ducting.py feat(notifications): Phase 2.13 ducting adapter threshold-crossing emission (severity-tiered, Option C) 2026-05-28 00:01:40 +00:00
test_adapter_fires.py feat(notifications): Phase 2.11 NIFC fires adapter pipeline integration 2026-05-27 23:33:48 +00:00
test_adapter_firms.py fix(fire): v0.5.7-fire -- FIRMS NATS pattern + WFIGS tombstone dedup + remove fire_proximity + categories audit 2026-06-04 06:25:42 +00:00
test_adapter_nws.py feat(notifications): Phase 2.6 NWS adapter pipeline integration 2026-05-15 04:47:31 +00:00
test_adapter_roads511.py feat(notifications): Phase 2.8 roads511 adapter pipeline integration 2026-05-27 21:18:21 +00:00
test_adapter_swpc.py feat(notifications): Phase 2.12 SWPC space weather adapter + dedup fix 2026-05-27 23:41:30 +00:00
test_adapter_traffic.py feat(notifications): Phase 2.7 traffic adapter pipeline integration 2026-05-27 19:17:27 +00:00
test_adapter_usgs.py feat(notifications): Phase 2.9 usgs water adapter pipeline integration 2026-05-27 21:58:13 +00:00
test_adapter_usgs_quake.py feat(notifications): Phase 2.14 USGS earthquake adapter (new) -- closes Rule 16 Seismic standalone path 2026-05-28 00:10:39 +00:00
test_avalanche_v057.py fix(avalanche): v0.5.7-avalanche -- Central avalanche check + categories audit 2026-06-04 06:55:27 +00:00
test_band_conditions.py feat(v0.5.11): band conditions scheduled broadcaster (3x/day HF propagation) 2026-06-05 07:38:51 +00:00
test_central_consumer.py feat(v0.5.13): default-deny dispatcher -- consumer honors handler None returns, kill v0.5.7 regression at the root 2026-06-05 14:17:41 +00:00
test_central_envelope_to_wire_v057.py feat(v0.5.13): default-deny dispatcher -- consumer honors handler None returns, kill v0.5.7 regression at the root 2026-06-05 14:17:41 +00:00
test_central_normalizer.py feat(v0.5.9): unified incident pipeline + state_511_atis Idaho cutover + two-sided freshness gate 2026-06-05 06:41:21 +00:00
test_central_region_routing.py fix(water): v0.5.7-water -- USGS NWIS hydro NATS pattern + categories audit 2026-06-04 06:42:06 +00:00
test_central_sub_adapter_routing.py feat(v0.5.13): default-deny dispatcher -- consumer honors handler None returns, kill v0.5.7 regression at the root 2026-06-05 14:17:41 +00:00
test_channel_rendering.py feat(notifications): Phase 2.5b per-channel-type renderers 2026-05-15 04:25:44 +00:00
test_cold_start_grace.py feat(v0.5.8b): persistence foundation + WFIGS handler + universal cold-start grace 2026-06-05 03:54:04 +00:00
test_config_loader.py fix(notifications): Phase 2.16.1 unblock pipeline -- grouper flush + rules coercion + toggle warning 2026-05-28 00:36:13 +00:00
test_config_source_field.py feat(central): v0.4 C.1 Central connector backend (no-op until adapter source flipped) 2026-05-28 02:28:19 +00:00
test_consumer_default_deny.py feat(v0.6-1): FIRMS handler -- storage-only, closes silent-drop on central.fire.hotspot.> 2026-06-05 15:50:33 +00:00
test_curation.py feat(v0.6-4): gauge_sites + town_anchors curation tables + GUI CRUD 2026-06-05 20:19:13 +00:00
test_dashboard_config_save.py fix(dashboard): v0.4 C.2.1 -- route PUT /config to multi-file save_section (Rule 17 persistence unblocked) 2026-05-28 03:17:30 +00:00
test_dispatcher_persistence.py feat(v0.6-2): dispatcher state persistence -- cold-start, cooldowns, dedup LRU to SQLite 2026-06-05 16:35:40 +00:00
test_env_reporter.py feat(v0.6-5): env_reporter + router wiring + include_in_llm_context per-adapter toggle -- LLM gains read access to every adapter table via the existing mesh_reporter pre-rendered prompt-injection pattern 2026-06-05 20:11:40 +00:00
test_fire_tracker_phase1.py feat(v0.7-fire-tracker-1): registry correlation + 2 new categories 2026-06-06 05:34:22 +00:00
test_fire_v057.py feat(v0.5.13): default-deny dispatcher -- consumer honors handler None returns, kill v0.5.7 regression at the root 2026-06-05 14:17:41 +00:00
test_firms_handler.py feat(v0.6-1): FIRMS handler -- storage-only, closes silent-drop on central.fire.hotspot.> 2026-06-05 15:50:33 +00:00
test_incident_handler.py feat(v0.6-tail): close 5 v0.6-phase1-complete.md follow-ups 2026-06-05 21:37:05 +00:00
test_include_roundtrip.py fix(v0.6-tail-4): register !include YAML tag constructor in config loader -- closes prod PUT 500 2026-06-06 04:37:24 +00:00
test_itd_511_work_zone.py feat(v0.5.9): unified incident pipeline + state_511_atis Idaho cutover + two-sided freshness gate 2026-06-05 06:41:21 +00:00
test_notification_toggles.py feat(v0.6-phase2): rip out quiet hours entirely -- dashboard toggle, config schema, pipeline checks. Per Matt's repeated feedback (saved as feedback-quiet-hours-trash.md): silent is better than ugly, mesh users who need a fire alert at 3 AM need it at 3 AM. No replacement. 2026-06-05 20:39:36 +00:00
test_nwis_handler.py feat(v0.6-4): gauge_sites + town_anchors curation tables + GUI CRUD 2026-06-05 20:19:13 +00:00
test_nws_dedup_relaxation.py feat(v0.6-phase3): reminder system + schema split + NWS dedup relaxation 2026-06-05 21:11:32 +00:00
test_nws_handler.py feat(v0.5.10): nws + usgs_quake + swpc handlers 2026-06-05 07:27:01 +00:00
test_or_arch_continuous.py feat(v0.6-tail-3): enforce OR-not-AND continuously -- close USGS direct-lookup leak + flag environmental config changes as restart-required 2026-06-06 03:51:10 +00:00
test_persistence.py feat(v0.5.8b): persistence foundation + WFIGS handler + universal cold-start grace 2026-06-05 03:54:04 +00:00
test_pipeline_digest.py fix(fire): v0.5.7-fire -- FIRMS NATS pattern + WFIGS tombstone dedup + remove fire_proximity + categories audit 2026-06-04 06:25:42 +00:00
test_pipeline_grouper.py fix(notifications): Phase 2.16.1 unblock pipeline -- grouper flush + rules coercion + toggle warning 2026-05-28 00:36:13 +00:00
test_pipeline_inhibitor_grouper.py fix(notifications): Phase 2.16.1 unblock pipeline -- grouper flush + rules coercion + toggle warning 2026-05-28 00:36:13 +00:00
test_pipeline_persistence.py feat(v0.6-6): inhibit_state + grouper_held persistence + ToggleFilter live-reload + Inhibitor/Grouper config knobs 2026-06-05 20:23:34 +00:00
test_pipeline_scheduler.py feat(notifications): Phase 2.5a channel interface unification 2026-05-15 03:45:27 +00:00
test_pipeline_skeleton.py chore(meshai): v0.5.5 -- cleanup bundle (gitignore env anchor, ducting health event_count, mesh_sources secret stripping, delete unused SeverityRouter) 2026-06-04 02:50:45 +00:00
test_pipeline_toggle_filter.py fix(fire): v0.5.7-fire -- FIRMS NATS pattern + WFIGS tombstone dedup + remove fire_proximity + categories audit 2026-06-04 06:25:42 +00:00
test_quake_handler.py feat(v0.5.10): nws + usgs_quake + swpc handlers 2026-06-05 07:27:01 +00:00
test_reminders.py feat(v0.6-phase3): reminder system + schema split + NWS dedup relaxation 2026-06-05 21:11:32 +00:00
test_renderers.py fix(notifications): v0.5.7-regression -- consumer title fallback uses registry name, mesh renderer drops [Family] prefix 2026-06-04 16:06:47 +00:00
test_rf_v057.py feat(v0.5.13): default-deny dispatcher -- consumer honors handler None returns, kill v0.5.7 regression at the root 2026-06-05 14:17:41 +00:00
test_router_env_scope.py feat(v0.6-5): env_reporter + router wiring + include_in_llm_context per-adapter toggle -- LLM gains read access to every adapter table via the existing mesh_reporter pre-rendered prompt-injection pattern 2026-06-05 20:11:40 +00:00
test_save_section_secret_preserve.py chore(meshai): v0.5.5 -- cleanup bundle (gitignore env anchor, ducting health event_count, mesh_sources secret stripping, delete unused SeverityRouter) 2026-06-04 02:50:45 +00:00
test_seismic_v057.py fix(seismic): v0.5.7-seismic -- USGS quake NATS pattern + severity=5 great-quake clamp + categories audit 2026-06-04 06:33:31 +00:00
test_swpc_handler.py feat(v0.5.10): nws + usgs_quake + swpc handlers 2026-06-05 07:27:01 +00:00
test_tail_followups.py feat(v0.6-tail): close 5 v0.6-phase1-complete.md follow-ups 2026-06-05 21:37:05 +00:00
test_tracking_v057.py fix(tracking): v0.5.7-tracking -- Central tracking check + categories audit 2026-06-04 07:00:22 +00:00
test_traffic_v057.py fix(traffic): v0.5.7-traffic -- NATS pattern fix + itd_511 sub-adapter routing + categories audit 2026-06-04 06:10:12 +00:00
test_v052_dispatcher.py feat(v0.5.8b): persistence foundation + WFIGS handler + universal cold-start grace 2026-06-05 03:54:04 +00:00
test_water_v057.py fix(water): v0.5.7-water -- USGS NWIS hydro NATS pattern + categories audit 2026-06-04 06:42:06 +00:00
test_weather_v057.py fix(weather): v0.5.7-weather -- NWS HTML strip + ALERT_CATEGORIES audit (NATS pattern already valid) 2026-06-04 06:00:10 +00:00
test_wfigs_handler.py feat(v0.5.8b): persistence foundation + WFIGS handler + universal cold-start grace 2026-06-05 03:54:04 +00:00
test_work_zone_renderer.py feat(content): v0.5.8-state_511_atis -- central_normalizer with Photon nearest_town + composer bypass + SB->S route normalization 2026-06-04 21:38:40 +00:00