meshai/work/meshai/central
malice 5dd8266abe
fix(firms): repair the FIRMS fire-fusion Event contract (issues #117-#119) (#120)
Three independent bugs kept firms_handler's growth/spotting/halt/cluster
fusion decisions from reaching a correct mesh Event:

- #117: consumer._normalize() computed `category` from the raw Central
  category BEFORE the per-adapter handler ran and never re-read
  data["category"] afterward, so every firms_handler category stamp was a
  silent no-op. Now re-read post-dispatch, validated against the known
  category registry (unrecognized overrides are logged and ignored).

- #118: consumer.py only ever honors data["_severity_override"], but
  firms_handler's halt/spotting/cluster sites stamped the plain
  data["severity"] key instead (only growth used the right key). Switched
  all three sites to `_severity_override` for one consistent contract.
  This is severity plumbing only -- it does not change which events fire.

- #119: FirePacer's gate only matched source in ("fires","wfigs") at
  severity=="priority", so FIRMS fusion broadcasts (source="firms",
  growth/spotting at "immediate") never reached the pacer. Broadened the
  gate to cover "firms" + {"priority","immediate"}, and gave FirePacer
  head-of-line insertion so an "immediate" event is never stuck behind
  already-queued "priority" events. Still unbounded/never-drops.

Cluster detection is left exactly as main ships it: live, always on, no
toggle (PR #73's curated new-fire cluster broadcasts with cold-start
silent-seeding). Only its severity-override key changes, under #118.

Updated existing tests that asserted the old (buggy) data["severity"]
contract, and added tests/test_firms_fusion_event_contract.py covering
all three fixes end-to-end through consumer._normalize()/_handle() and
FirePacer directly.

Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 17:41:40 -06:00
..
__init__.py refactor: move source tree into work/, multi-stage Docker build, fix satpass 2026-06-16 03:40:31 +00:00
avy_handler.py refactor(phase1): quake + swpc(Kp+flare) + avalanche, behind staged-cutover gate (#29) 2026-07-04 15:58:46 -06:00
budget.py refactor(phase0): source-agnostic formatter/gating scaffold + harness (inert) (#28) 2026-07-04 12:55:48 -06:00
consumer.py fix(firms): repair the FIRMS fire-fusion Event contract (issues #117-#119) (#120) 2026-07-11 17:41:40 -06:00
firms_handler.py fix(firms): repair the FIRMS fire-fusion Event contract (issues #117-#119) (#120) 2026-07-11 17:41:40 -06:00
idaho_gauge_sites.py refactor: move source tree into work/, multi-stage Docker build, fix satpass 2026-06-16 03:40:31 +00:00
incident_handler.py refactor(phase2): migrate nws + incident/roads to formatter+decider (tier-a) (#30) 2026-07-04 18:16:34 -06:00
nwis_handler.py refactor(phase3a): migrate hydro/nwis to formatter+decider (tier-a) (#32) 2026-07-04 22:22:33 -06:00
nws_handler.py chore(config): delete 51 dead keys, fix usgs_quake floor, secret-flag consistency (#46) 2026-07-05 17:34:27 -06:00
pass_predictor.py feat(phase4a): peak_compass end-to-end + repair stale satpass test suite (#35) 2026-07-05 01:06:29 -06:00
quake_handler.py refactor(phase1): quake + swpc(Kp+flare) + avalanche, behind staged-cutover gate (#29) 2026-07-04 15:58:46 -06:00
satpass_handler.py fix(satpass): clean broadcast format (short names, degrees, compass, friendly observers) (#76) 2026-07-06 20:44:02 -06:00
swpc_handler.py refactor(phase1): quake + swpc(Kp+flare) + avalanche, behind staged-cutover gate (#29) 2026-07-04 15:58:46 -06:00
tle_handler.py feat(phase4c): native SGP4 satpass — standalone satellite passes, no Central (#39) 2026-07-05 02:25:55 -06:00
wfigs_handler.py refactor(phase3b): migrate WFIGS fire to formatter+decider (tier-a) (#33) 2026-07-04 22:51:26 -06:00