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: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Move all application source (meshai/, dashboard-frontend/, tests/,
config/, docs/, Dockerfile, etc.) into work/ directory
- Add Node.js multi-stage build to Dockerfile for frontend compilation;
remove compiled static assets from git tracking
- Fix satpass missing time windows: consolidation was splitting wire on
newline and only putting line 1 in event.title, dropping the time
window line that the composer uses for precomposed broadcasts
- Fix satpass burst flooding: stagger consolidation timers (+60s per
pending pass) so Central batch publishes don't blast the mesh
- Update CI workflow build context to work/
- Anchor lib/ and data/ gitignore patterns to repo root to prevent
false matches on nested directories
- Add dashboard-frontend/node_modules/ to .dockerignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>