meshai/meshai/adapter_config/defaults.py
Matt Johnson (via Claude) 3e06aacc3f feat: hepburn tropo card — region selector dropdown persisted to adapter_config
Adds HepburnTropoCard to the dashboard with a 23-region dropdown
selector. Selected region is persisted to adapter_config via
(dashboard, tropo_region) key, defaulting to wam (Western North
America). Image loads from dxinfocentre.com/tr_map/fcst/{code}006.png
with date-based cache busting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-10 06:15:36 +00:00

749 lines
34 KiB
Python

"""v0.6-3a.1 trimmed adapter_config defaults registry.
Per Matt's locked CONFIG-vs-CODE rule:
CONFIG (lives here):
where we send (channels), how often (cadences/schedules),
thresholds (magnitude floors, severity gates, distance radius,
cooldown durations, freshness windows), curation data (which
sites/states/codes), toggles (enabled, include_in_llm_context,
drop_zero_magnitude).
CODE (stays in the handlers; not surfaced to the GUI):
sentence templates, emoji choices, mapping/translation functions
(TomTom icon_map, ITD sub_type_map, Central adapter_map and
category_map), rendering logic (anchor priority order,
expires-buckets formatting, threshold-state labels), heuristic
logic (band_conditions Kp/SFI -> Good/Fair/Poor function).
Trimmed from the v0.6-3a draft of 77 keys down to 43. The 34 dropped
keys are removed from the live DB on first boot by prune_orphans(),
which logs each delete at INFO level so docker logs carry a paper trail.
Adding a new tunable:
1. Add an entry to REGISTRY below with default + type + description.
2. Confirm it matches the CONFIG rule (if you're tempted to add a
sentence template, an emoji, or a translation map, STOP -- that's
CODE).
3. The next container restart calls seed_defaults() which
INSERT OR IGNOREs the row.
4. Wire the handler to read from adapter_config.<adapter>.<key>.
"""
from __future__ import annotations
from typing import Any
# REGISTRY[(adapter, key)] = {"default": ..., "type": ..., "description": ...}
# Type vocabulary: "int" | "float" | "str" | "bool" | "json"
REGISTRY: dict[tuple[str, str], dict[str, Any]] = {
# =================================================================
# WFIGS -- 4 settings (cooldown, anchor radius, two re-broadcast toggles)
# =================================================================
("wfigs", "cooldown_seconds"): {
"default": 28800, # central/wfigs_handler.py:43
"type": "int",
"description": "Per-fire broadcast cooldown in seconds (forward-only Update gate).",
},
("wfigs", "anchor_max_mi"): {
"default": 100.0, # central/wfigs_handler.py:322
"type": "float",
"description": "Max distance (mi) for the nearest_town anchor fallback.",
},
("wfigs", "broadcast_on_acres"): {
"default": True,
"type": "bool",
"description": "Re-broadcast when acres increase (forward-only).",
},
("wfigs", "broadcast_on_contained"): {
"default": True,
"type": "bool",
"description": "Re-broadcast when containment percent increases (forward-only).",
},
("wfigs", "freshness_seconds"): {
"default": 0,
"type": "int",
"description": "Staleness gate for wfigs events (0 = disabled). Fire events are always relevant regardless of age.",
},
# =================================================================
# NWS -- 3 settings (severity gate, tombstone msgTypes, suffix-promote toggle)
# =================================================================
("nws", "broadcast_severities"): {
"default": ["Extreme", "Severe"], # nws_handler.py:43
"type": "json",
"description": "CAP severity strings allowed onto the mesh.",
},
("nws", "tombstone_msgtypes"): {
"default": ["Cancel", "Expire"], # nws_handler.py:46
"type": "json",
"description": "CAP msgType values that mark an alert as gone.",
},
("nws", "warning_suffix_promotes"): {
"default": True, # nws_handler.py:172
"type": "bool",
"description": "Promote category-name-ending-in-_warning to Severe when CAP severity is missing.",
},
# =================================================================
# USGS_QUAKE -- 6 settings (regional geography + 3 mag floors + PAGER set)
# =================================================================
("usgs_quake", "regional_centroid"): {
"default": [44.36, -114.61], # quake_handler.py:36-37 (Idaho centroid)
"type": "json",
"description": "[lat, lon] of the regional gate origin; quakes within regional_radius_mi use regional_mag_floor.",
},
("usgs_quake", "regional_radius_mi"): {
"default": 250, # quake_handler.py:38
"type": "int",
"description": "Radius (mi) of the regional gate around regional_centroid.",
},
("usgs_quake", "broadcast_pager_alerts"): {
"default": ["orange", "red"], # quake_handler.py:40
"type": "json",
"description": "USGS PAGER alert levels that broadcast at any magnitude.",
},
("usgs_quake", "global_mag_floor"): {
"default": 3.0, # quake_handler.py:69
"type": "float",
"description": "Global magnitude floor for unconditional broadcasts.",
},
("usgs_quake", "regional_mag_floor"): {
"default": 2.5, # quake_handler.py:70
"type": "float",
"description": "Reduced magnitude floor for quakes within regional_radius_mi of centroid.",
},
("usgs_quake", "escalate_mag_floor"): {
"default": 5.0, # quake_handler.py:76
"type": "float",
"description": "Magnitude floor for the visual escalation emoji.",
},
# =================================================================
# SWPC -- 3 settings (three storm-tier broadcast floors)
# =================================================================
("swpc", "geomag_kp_floor"): {
"default": 7.0, # swpc_handler.py:66-68 (Kp >= 7 = G3)
"type": "float",
"description": "Kp value at or above which geomagnetic storms broadcast.",
},
("swpc", "flare_class_floor"): {
"default": "X1", # swpc_handler.py:40
"type": "str",
"description": "Minimum X-ray flare class to broadcast ('X1' = R3).",
},
("swpc", "proton_pfu_floor"): {
"default": 10.0, # swpc_handler.py:48 (S1)
"type": "float",
"description": "Proton flux floor in pfu (>=10 = S1 minor radiation storm).",
},
# =================================================================
# USGS_NWIS -- 2 settings (parameter-code curation + recede toggle)
# =================================================================
("usgs_nwis", "parameter_codes"): {
"default": ["00060", "00065"], # nwis_handler.py:57
"type": "json",
"description": "USGS parameter codes the handler processes (00060=discharge, 00065=gage height).",
},
("usgs_nwis", "broadcast_on_recede"): {
"default": False, # nwis_handler.py:204-209
"type": "bool",
"description": "Broadcast when a gauge transitions DOWN through a threshold band.",
},
# =================================================================
# INCIDENT -- 2 settings (shared freshness gate + Update-after-New toggle)
# =================================================================
("incident", "freshness_seconds"): {
"default": 1800, # incident_handler.py:49 + central_normalizer.py:917
"type": "int",
"description": "Drop incidents older than this many seconds.",
},
("incident", "broadcast_on_update"): {
"default": False, # incident_handler.py:594-602 (v0.5.9 REVISED)
"type": "bool",
"description": "Re-broadcast on magnitude bump / delay growth / icon flip after first New.",
},
# =================================================================
# TOMTOM_INCIDENTS -- 2 settings (per-source drop toggles)
# =================================================================
("tomtom_incidents", "drop_zero_magnitude"): {
"default": True, # incident_handler.py:250
"type": "bool",
"description": "Drop envelopes with magnitude_of_delay==0.",
},
("tomtom_incidents", "drop_non_present"): {
"default": True, # incident_handler.py:254
"type": "bool",
"description": "Drop envelopes whose time_validity != 'present'.",
},
("tomtom_incidents", "min_magnitude"): {
"default": 4,
"type": "int",
"description": "Minimum TomTom magnitude_of_delay to broadcast (1=minor, 2=moderate, 3=major, 4=severe). Anything below this is silently dropped.",
},
# =================================================================
# STATE_511_ATIS -- 1 setting (states to skip in favor of itd_511)
# =================================================================
("state_511_atis", "skipped_states"): {
"default": ["ID"], # incident_handler.py:459-470 (v0.5.9 GAMMA)
"type": "json",
"description": "States whose state_511_atis envelopes are silently skipped (handled by itd_511 instead).",
},
# =================================================================
# ITD_511 -- 3 settings (severity gate, category filter, sub-type filter)
# =================================================================
("itd_511", "min_severity"): {
"default": "None",
"type": "str",
"description": "Minimum itd_511 severity to broadcast. Options: None, Minor, Major. Events below this are dropped.",
},
("itd_511", "enabled_categories"): {
"default": ["incident", "closure"],
"type": "json",
"description": "Which event categories to broadcast: incident, closure, special_event.",
},
("itd_511", "enabled_sub_types"): {
"default": ["accident", "road_closed", "closure", "lane_closed", "vehicle_on_fire", "flooding", "debris"],
"type": "json",
"description": "Which sub_types to broadcast. Empty list = all.",
},
# =================================================================
# WZDX -- 3 settings (broadcast gate, severity gate, sub-type filter)
# =================================================================
("wzdx", "broadcast"): {
"default": False,
"type": "bool",
"description": "Broadcast work zone events (road construction, lane closures). Off by default.",
},
("wzdx", "min_severity"): {
"default": "Minor",
"type": "str",
"description": "Minimum severity to broadcast work zones: None, Minor, Major.",
},
("wzdx", "sub_types"): {
"default": ["road_works", "lane_closed", "road_closed"],
"type": "json",
"description": "Work zone sub-types to broadcast. Empty = all.",
},
# =================================================================
# CENTRAL consumer -- 1 setting (severity-int bucket boundaries)
# =================================================================
("central", "severity_thresholds"): {
"default": {"routine_max": 1, "priority_max": 2, "immediate_min": 3},
"type": "json",
"description": "Central int severity buckets: 0..routine_max -> routine, priority_max -> priority, >= immediate_min -> immediate.",
},
# =================================================================
# DISPATCHER -- 4 settings (LRU cap + cooldown prune params + retention)
# =================================================================
("dispatcher", "dedup_lru_max"): {
"default": 10000, # pipeline/dispatcher.py:28
"type": "int",
"description": "In-memory dedup OrderedDict cap. Disk has a 7-day window which may exceed this.",
},
("dispatcher", "cooldown_prune_size"): {
"default": 1024, # _COOLDOWN_INMEM_PRUNE_THRESHOLD
"type": "int",
"description": "In-memory cooldown map size that triggers a 2*cooldown_s prune.",
},
("dispatcher", "cooldown_prune_multiplier"): {
"default": 2, # pipeline/dispatcher.py:184 (2*cooldown_s)
"type": "int",
"description": "Cooldown-prune cutoff multiplier (rows older than N*cooldown_s deleted).",
},
("dispatcher", "dedup_db_retention_days"): {
"default": 7, # _DEDUP_DB_RETENTION_S
"type": "int",
"description": "Days a (source, event_id) dedup row stays on disk before the on-insert cleanup deletes it.",
},
# =================================================================
# BAND_CONDITIONS -- 3 settings (SWPC freshness + HamQSL endpoint config)
# (schedule, tz, enabled stay in YAML config.notifications.band_conditions_*)
# =================================================================
("band_conditions", "swpc_freshness_seconds"): {
"default": 21600, # band_conditions.py:45
"type": "int",
"description": "If swpc_events readings older than this, fall through to HamQSL.",
},
("band_conditions", "hamqsl_url"): {
"default": "https://www.hamqsl.com/solarxml.php",
"type": "str",
"description": "HamQSL solarxml fallback URL.",
},
("band_conditions", "hamqsl_timeout_s"): {
"default": 5,
"type": "int",
"description": "HamQSL fetch timeout.",
},
# =================================================================
# GEOCODER -- 6 settings (Photon endpoint + curation + cache size)
# =================================================================
("geocoder", "photon_url"): {
"default": "http://100.64.0.24:2322",
"type": "str",
"description": "Photon base URL (Tailscale-internal Echo6 instance).",
},
("geocoder", "photon_timeout_s"): {
"default": 2.0,
"type": "float",
"description": "Photon HTTP timeout.",
},
("geocoder", "photon_radius_km"): {
"default": 80,
"type": "int",
"description": "Photon /reverse search radius (~50 mi default).",
},
("geocoder", "photon_limit"): {
"default": 10,
"type": "int",
"description": "Photon /reverse max features per call.",
},
("geocoder", "town_osm_values"): {
"default": ["city", "town", "village", "hamlet", "suburb", "locality"],
"type": "json",
"description": "OSM place classes that count as a town for the nearest_town anchor.",
},
("geocoder", "h3_cache_max"): {
"default": 10000, # central_normalizer.py:297
"type": "int",
"description": "Max H3 cache entries before LRU eviction.",
},
# =================================================================
# FIRES -- 10 settings (P1 radius + P2 growth/halt + P3 spotting + P4 digest)
# =================================================================
# Per-fire spread radius override lives in fires.spread_radius_mi;
# the value below is the fallback. v0.7-fire-1 shipped 5 mi based on
# design doc open question #1 ("Spread radius default. Start with
# 5 mi per fire?"). Tune once we have a week of observed attribution
# rates.
("fires", "spread_radius_mi_default"): {
"default": 5.0,
"type": "float",
"description": "Default attribution radius for FIRMS hotspot -> fire matching, miles. Per-fire override in fires.spread_radius_mi.",
},
# v0.7-fire-2 -- growth + halt detection thresholds.
# growth_drift_threshold_mi: a per-pass centroid drift of at least
# this many miles fires wildfire_growth. 0.5 mi matches the design
# doc (Phase 2 spec: "Centroid drift > 0.5 mi/pass") and is roughly
# the noise floor of a single VIIRS pixel centroid (375 m ~ 0.23 mi).
("fires", "growth_drift_threshold_mi"): {
"default": 0.5,
"type": "float",
"description": "Centroid drift between consecutive satellite passes (miles) that fires the wildfire_growth broadcast.",
},
# halt_passes_threshold: number of consecutive satellite passes with
# no new pixels before the fire is considered halted. Default 2 ~
# 12h in Idaho (VIIRS gives 4 passes/day). Combined with the
# halt_minimum_seconds time gate below; both must be met.
("fires", "halt_passes_threshold"): {
"default": 2,
"type": "int",
"description": "Consecutive empty satellite passes before wildfire_halted (combined with the halt_minimum_seconds time gate).",
},
# halt_minimum_seconds: minimum wall-clock idle time before halt
# can fire. 12h handles the gap where 2 N20 + 2 N passes would have
# crossed the fire's location. We rely on this time gate as the
# operational halt rule -- pass-count enforcement would require
# tracking the global VIIRS schedule per satellite; the time gate
# subsumes that.
("fires", "halt_minimum_seconds"): {
"default": 43200,
"type": "int",
"description": "Minimum elapsed seconds since the most recent attributed pixel before wildfire_halted can fire.",
},
# v0.7-fire-3 -- spotting detection.
# spotting_distance_threshold_mi: an attributed pixel this far or
# more from the previous-pass perimeter (convex hull, vertex-
# distance approximation) fires wildfire_spotting. 1.5 mi matches
# the design doc Phase 3 spec ("Hotspot >=1.5 mi from perimeter").
# Treat as an initial-guess default -- the design doc lists this
# as an open question pending real spotting-fire observation data.
("fires", "spotting_distance_threshold_mi"): {
"default": 1.5,
"type": "float",
"description": "Distance (miles) from previous-pass perimeter that fires wildfire_spotting. Tune from observed spotting events; design doc open question #6 marks this as TBD.",
},
# spotting_cooldown_seconds: per-fire latch so a burst of pixels
# in the same general spotting area doesn't spam the mesh. 1h is
# short enough that real follow-on spotting (different ember,
# different sector) re-fires, long enough that a single satellite
# pass with N nearby ember hits broadcasts at most once.
("fires", "spotting_cooldown_seconds"): {
"default": 3600,
"type": "int",
"description": "Minimum seconds between consecutive wildfire_spotting broadcasts for the same fire; suppresses rapid-ember spam.",
},
# v0.7-fire-4 -- daily fire digest scheduled broadcaster.
# digest_enabled: master switch. Off by default for prod safety;
# flip via GUI once the digest wording is dialed in.
("fires", "digest_enabled"): {
"default": True,
"type": "bool",
"description": "Whether the fire-digest scheduler broadcasts at the configured slots. Off => no broadcasts even if all other config is valid.",
},
# digest_schedule: list of HH:MM strings, local-time per digest_timezone.
# Mirrors band_conditions_schedule shape so operators can reason
# about the two side-by-side.
("fires", "digest_schedule"): {
"default": ["06:00", "18:00"],
"type": "json",
"description": "Local-time HH:MM slots for the fire-digest broadcast (list of strings). Honor digest_timezone for wall-clock semantics.",
},
("fires", "digest_timezone"): {
"default": "America/Boise",
"type": "str",
"description": "IANA tz used to interpret digest_schedule.",
},
# digest_max_chars: mesh wire cap. The LLM is told to fit under this.
# Reuses the response.max_length chunking if the LLM ignores the cap.
("fires", "digest_max_chars"): {
"default": 200,
"type": "int",
"description": "Hard cap on the digest wire string length (chars). The LLM prompt asks to fit; the chunker enforces.",
},
# =================================================================
# FIRMS -- 7 settings (storage floors + dedup + 3 v0.7 cluster knobs)
# =================================================================
("firms", "confidence_floor"): {
"default": "low", # firms_handler.py FIRMS_CONFIDENCE_FLOOR
"type": "str",
"description": "Min FIRMS confidence to store ('low' = store all).",
},
("firms", "frp_floor"): {
"default": 0.0, # firms_handler.py FIRMS_FRP_FLOOR
"type": "float",
"description": "Min FRP (MW) to store; 0 = store every detection.",
},
("firms", "bbox"): {
"default": None, # firms_handler.py FIRMS_BBOX_OPTIONAL
"type": "json",
"description": "Optional [min_lat, min_lon, max_lat, max_lon] spatial filter (null = no filter).",
},
("firms", "dedup_distance_m"): {
# v0.6-3a.1 (Matt's call): user-facing unit is METERS, not decimal
# places. firms_handler internally translates this to a lat/lon
# quantization step (1 deg ~ 111 km so step_deg = m / 111_000).
# Default 5m is slightly coarser than the v0.6-1 implementation's
# 1.1m (round(.,5)) -- the actual wire-up + index update lands in
# v0.6-3b (firms handler wiring step).
"default": 5,
"type": "int",
"description": "Distance in meters within which two FIRMS pixel observations from the same satellite + acquisition time are considered duplicates.",
},
# ---- v0.7-fire-tracker-1 unattributed-cluster knobs ----
# On every FIRMS pixel that fails attribution to any known fire, the
# handler asks: "are there enough other unattributed pixels nearby
# right now to suggest a new ignition?" The three knobs below define
# "enough", "nearby", and "right now". Defaults match design doc
# open question #6 ("3 pixels within 1 mi") -- tune from ops once we
# have false-positive data.
("firms", "cluster_min_pixels"): {
"default": 3,
"type": "int",
"description": "Minimum unattributed pixels within cluster_max_radius_mi over cluster_time_window_minutes to fire an unattributed_hotspot_cluster broadcast.",
},
("firms", "cluster_max_radius_mi"): {
"default": 1.0,
"type": "float",
"description": "Spatial radius (miles) defining a candidate hotspot cluster.",
},
("firms", "cluster_time_window_minutes"): {
"default": 60,
"type": "int",
"description": "Temporal window (minutes); unattributed pixels older than this don't count toward a new cluster.",
},
# =================================================================
# PIPELINE (Inhibitor + Grouper) -- 2 settings
# =================================================================
("pipeline", "inhibitor_ttl_seconds"): {
"default": 1800, # pipeline/inhibitor.py:27 default
"type": "int",
"description": "How long an inhibit_key remains active after the originating event.",
},
("pipeline", "grouper_window_seconds"): {
"default": 60, # pipeline/grouper.py:27 default
"type": "int",
"description": "How long to hold a group_key before emitting downstream.",
},
("pipeline", "env_reporter_block_chars"): {
"default": 3000,
"type": "int",
"description": "Max chars per env_reporter block injected into the LLM system prompt.",
},
# =================================================================
# v0.6-phase3 reminders: per-adapter clock-driven re-broadcast config.
# =================================================================
("reminders_wfigs", "enabled"): {
"default": False,
"type": "bool",
"description": "Enable Active: reminder broadcasts for ongoing fires. Disabled by default — use the digest instead.",
},
("reminders_wfigs", "cadence_kind"): {
"default": "interval",
"type": "str",
"description": "Reminder cadence kind (interval | clock).",
},
("reminders_wfigs", "cadence_value"): {
"default": 28800, # 8h
"type": "json",
"description": "Cadence value: int seconds for interval, list of HH:MM strings for clock.",
},
("reminders_wfigs", "channels"): {
"default": ["mesh_broadcast"],
"type": "json",
"description": "Channel types for the reminder broadcast.",
},
("reminders_wfigs", "terminate_when"): {
"default": ["tombstone", "containment_100", "last_event_age_24h"],
"type": "json",
"description": "Stop reminding when any of these conditions is true.",
},
("reminders_swpc", "cadence_kind"): {
"default": "interval",
"type": "str",
"description": "Reminder cadence kind (interval | clock).",
},
("reminders_swpc", "cadence_value"): {
"default": 28800, # 8h
"type": "json",
"description": "Cadence value: int seconds for interval, list of HH:MM strings for clock.",
},
("reminders_swpc", "channels"): {
"default": ["mesh_broadcast"],
"type": "json",
"description": "Channel types for the reminder broadcast.",
},
("reminders_swpc", "terminate_when"): {
"default": ["tombstone", "end_date_passed"],
"type": "json",
"description": "Stop reminding when any of these conditions is true.",
},
("reminders_itd_511_work_zone", "cadence_kind"): {
"default": "clock",
"type": "str",
"description": "Reminder cadence kind (interval | clock).",
},
("reminders_itd_511_work_zone", "cadence_value"): {
"default": ["08:00"],
"type": "json",
"description": "List of HH:MM clock slots (local timezone) when reminders fire.",
},
("reminders_itd_511_work_zone", "channels"): {
"default": ["mesh_broadcast"],
"type": "json",
"description": "Channel types for the reminder broadcast.",
},
("reminders_itd_511_work_zone", "dow_mask"): {
"default": [True, True, True, True, True, True, True],
"type": "json",
"description": "Day-of-week enable mask (Mon..Sun).",
},
("reminders_itd_511_work_zone", "timezone"): {
"default": "America/Boise",
"type": "str",
"description": "Timezone for the clock slots.",
},
("reminders_itd_511_work_zone", "terminate_when"): {
"default": ["tombstone", "end_date_passed"],
"type": "json",
"description": "Stop reminding when any of these conditions is true.",
},
# NWS dedup-window relaxation (separate from reminders by design).
("nws", "duplicate_allowed_after_seconds"): {
"default": 10800, # 3h
"type": "int",
"description": "Allow re-broadcast of the same CAP id after this many seconds (the nws_handler relaxes its dedup gate past this point and uses an Active: prefix).",
},
("nws", "locations_max_chars"): {
"default": 120,
"type": "int",
"description": "Maximum characters for the locations field on line 4 of NWS wire. Truncates at word boundary.",
},
("nws", "area_max_chars"): {
"default": 80,
"type": "int",
"description": "Maximum characters for the area field on line 2 of NWS wire. Truncates at last word boundary.",
},
# =================================================================
# AVALANCHE -- 1 setting (min danger level broadcast floor)
# =================================================================
("avalanche", "min_danger_level"): {
"default": 3,
"type": "int",
"description": "Minimum danger level to broadcast (3=Considerable, 4=High, 5=Extreme).",
},
# =================================================================
# DASHBOARD -- UI-only settings persisted for the operator
# =================================================================
("dashboard", "tropo_region"): {
"default": "wam",
"type": "str",
"description": "Hepburn tropo forecast region code displayed on dashboard.",
},
}
# -------- ADAPTER_META ----------------------------------------------------
#
# Per-adapter metadata. One row per adapter the GUI surfaces; the row
# survives even when an adapter has zero config keys, because the
# include_in_llm_context toggle is still meaningful (the user wants the
# LLM to be able to see traffic_events from itd_511 even though all of
# its render-side stuff is now CODE).
ADAPTER_META: dict[str, dict[str, Any]] = {
"wfigs": {
"display_name": "WFIGS wildfire incidents",
"include_in_llm_context": True,
"reminder_enabled": True,
"description": "NIFC-authoritative wildfire registry (named incidents, acres, containment).",
},
# v0.7-fire-tracker-1: "fires" is not a feed; it's the registry table
# populated by WFIGS first-sight + FIRMS attribution. Surfacing it as
# an adapter_meta family lets the GUI show "spread radius default"
# alongside the per-feed knobs.
"fires": {
"display_name": "Fire registry",
"include_in_llm_context": True,
"description": "Cross-feed fire registry: WFIGS declares them; FIRMS pixels grow them. spread_radius_mi_default tunes the attribution gate.",
},
"firms": {
"display_name": "FIRMS satellite hotspots",
"include_in_llm_context": True,
"description": "NASA VIIRS/MODIS heat-pixel feed. Storage-only (no broadcast).",
},
"nws": {
"display_name": "NWS weather alerts",
"include_in_llm_context": True,
"description": "CAP-formatted severe-weather warnings/watches/advisories.",
},
"usgs_quake": {
"display_name": "USGS earthquakes",
"include_in_llm_context": True,
"description": "Real-time earthquake feed with Idaho-regional + global tiers.",
},
"swpc": {
"display_name": "SWPC space weather",
"include_in_llm_context": True,
"reminder_enabled": True,
"description": "Geomagnetic / flare / proton storm alerts (G/R/S scale).",
},
"usgs_nwis": {
"display_name": "USGS NWIS stream gauges",
"include_in_llm_context": True,
"description": "Real-time stream-gauge readings (Idaho curated sites).",
},
"tomtom_incidents": {
"display_name": "TomTom traffic incidents",
"include_in_llm_context": True,
"description": "Real-time crashes/jams/closures (TomTom feed).",
},
"state_511_atis": {
"display_name": "Castle Rock state 511 ATIS",
"include_in_llm_context": True,
"description": "Multi-state ATIS feed (Idaho cutover to itd_511 in v0.5.9 GAMMA).",
},
"itd_511": {
"display_name": "ITD 511 (Idaho)",
"include_in_llm_context": True,
"description": "Idaho Transportation Department incident/closure/work-zone feed.",
},
"wzdx": {
"display_name": "WZDx work zones",
"include_in_llm_context": True,
"description": "Work zone broadcast gate and sub-type/severity filters.",
},
"band_conditions": {
"display_name": "Band conditions (HF propagation)",
"include_in_llm_context": True,
"description": "3x/day scheduled broadcast of HF band ratings (SWPC-local + HamQSL fallback).",
},
"central": {
"display_name": "Central consumer routing",
"include_in_llm_context": False,
"description": "Adapter <-> source remap + severity buckets. Operational, not LLM-relevant.",
},
"dispatcher": {
"display_name": "Dispatcher state",
"include_in_llm_context": True,
"description": "Cold-start anchor, cumulative drop counters, cooldown + dedup state. Useful for 'why did we drop X?' answers.",
},
"geocoder": {
"display_name": "Geocoder (Photon)",
"include_in_llm_context": False,
"description": "Photon-reverse settings + town-class curation. Operational, not LLM-relevant.",
},
"incident": {
"display_name": "Incident pipeline (shared settings)",
"include_in_llm_context": True,
"description": "Settings shared across tomtom_incidents / state_511_atis / itd_511.",
},
"pipeline": {
"display_name": "Notification pipeline (Inhibitor + Grouper)",
"include_in_llm_context": True,
"description": "TTL + window tunables for the Inhibitor and Grouper stages.",
},
# v0.6-phase3 reminder pseudo-adapters: each carries the per-adapter
# ReminderScheduler config. Their adapter_meta rows exist so the GUI
# surfaces them; include_in_llm_context is True so the LLM can answer
# "are reminders firing for fires right now?".
"reminders_wfigs": {
"display_name": "Reminders (WFIGS fires)",
"include_in_llm_context": True,
"description": "Per-fire Active: reminders. 8h interval by default.",
},
"reminders_swpc": {
"display_name": "Reminders (SWPC space weather)",
"include_in_llm_context": True,
"description": "Active: reminders for ongoing G-storm / R-flare / S-radiation events. 8h interval.",
},
"reminders_itd_511_work_zone": {
"display_name": "Reminders (ITD 511 work zones)",
"include_in_llm_context": True,
"description": "Clock-driven daily reminders for active road-works zones (default 08:00 Mountain).",
},
"itd_511_work_zone": {
"display_name": "ITD 511 (work zones, reminder-eligible)",
"include_in_llm_context": True,
"reminder_enabled": True,
"description": "Subset of itd_511 traffic_events filtered to work-zone sub_type, used as the reminder target.",
},
"dashboard": {
"display_name": "Dashboard UI settings",
"include_in_llm_context": False,
"description": "Operator UI preferences persisted to adapter_config (region selectors, display options).",
},
}
# Convenience views.
def all_adapters() -> set[str]:
"""Set of every adapter name referenced by REGISTRY or ADAPTER_META."""
return {adapter for adapter, _ in REGISTRY} | set(ADAPTER_META)
def registry_for(adapter: str) -> dict[str, dict[str, Any]]:
"""Subset of REGISTRY for one adapter, keyed by key only."""
return {k: v for (a, k), v in REGISTRY.items() if a == adapter}