mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-06-10 17:04:45 +02:00
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> |
||
|---|---|---|
| .. | ||
| fixtures/central_envelopes | ||
| conftest.py | ||
| test_adapter_avalanche.py | ||
| test_adapter_config_api.py | ||
| test_adapter_config_foundation.py | ||
| test_adapter_ducting.py | ||
| test_adapter_fires.py | ||
| test_adapter_firms.py | ||
| test_adapter_nws.py | ||
| test_adapter_roads511.py | ||
| test_adapter_swpc.py | ||
| test_adapter_traffic.py | ||
| test_adapter_usgs.py | ||
| test_adapter_usgs_quake.py | ||
| test_avalanche_v057.py | ||
| test_band_conditions.py | ||
| test_central_consumer.py | ||
| test_central_envelope_to_wire_v057.py | ||
| test_central_normalizer.py | ||
| test_central_region_routing.py | ||
| test_central_sub_adapter_routing.py | ||
| test_channel_rendering.py | ||
| test_cold_start_grace.py | ||
| test_config_loader.py | ||
| test_config_source_field.py | ||
| test_consumer_default_deny.py | ||
| test_curation.py | ||
| test_dashboard_config_save.py | ||
| test_dispatcher_persistence.py | ||
| test_env_reporter.py | ||
| test_fire_tracker_phase1.py | ||
| test_fire_v057.py | ||
| test_firms_handler.py | ||
| test_incident_handler.py | ||
| test_include_roundtrip.py | ||
| test_itd_511_work_zone.py | ||
| test_notification_toggles.py | ||
| test_nwis_handler.py | ||
| test_nws_dedup_relaxation.py | ||
| test_nws_handler.py | ||
| test_or_arch_continuous.py | ||
| test_persistence.py | ||
| test_pipeline_digest.py | ||
| test_pipeline_grouper.py | ||
| test_pipeline_inhibitor_grouper.py | ||
| test_pipeline_persistence.py | ||
| test_pipeline_scheduler.py | ||
| test_pipeline_skeleton.py | ||
| test_pipeline_toggle_filter.py | ||
| test_quake_handler.py | ||
| test_reminders.py | ||
| test_renderers.py | ||
| test_rf_v057.py | ||
| test_router_env_scope.py | ||
| test_save_section_secret_preserve.py | ||
| test_seismic_v057.py | ||
| test_swpc_handler.py | ||
| test_tail_followups.py | ||
| test_tracking_v057.py | ||
| test_traffic_v057.py | ||
| test_v052_dispatcher.py | ||
| test_water_v057.py | ||
| test_weather_v057.py | ||
| test_wfigs_handler.py | ||
| test_work_zone_renderer.py | ||