meshai/tests
Matt Johnson (via Claude) 566b06de06 feat(v0.6-tail): close 5 v0.6-phase1-complete.md follow-ups
(1) Auto-call refresh-toggles on PUT /api/config/notifications
    meshai/dashboard/api/config_routes.py adds register_config_routes_hooks(app)
    which registers a FastAPI HTTP middleware: on any 2xx PUT whose path
    matches /api/config/notifications or /api/config, the middleware
    invokes _refresh_toggle_filter(app) which reaches into app.state.bus._
    pipeline_components["toggle_filter"] and calls .refresh(app.state.config).
    The dashboard no longer has to remember to ping POST /api/notifications/
    refresh-toggles after a toggle change. The explicit endpoint stays for
    backwards-compat.

(2) env_reporter block-size cap moved to adapter_config
    New registry row pipeline.env_reporter_block_chars (int, default 3000).
    meshai/notifications/env_reporter.py replaces the hardcoded
    _BLOCK_MAX_CHARS = 3000 with _DEFAULT_BLOCK_MAX_CHARS (the fallback) +
    a _block_cap() helper that reads from adapter_config on every slice.
    Mutating the row via PUT /api/adapter-config takes effect on the next
    env_reporter call -- no restart.

(3) Bulk-import endpoint for gauge_sites
    meshai/dashboard/api/gauge_sites_import.py adds
    POST /api/gauge-sites/import with two paths:
      format=csv      -- expects "data" (CSV text with header row matching
                          gauge_sites columns: site_id, gauge_name, lat, lon,
                          and optionally action_ft/flood_minor_ft/
                          flood_moderate_ft/flood_major_ft/enabled). UPSERT
                          via ON CONFLICT(site_id) DO UPDATE. Returns
                          {inserted, updated, skipped}.
      format=nws-ahps -- expects "wfo" (list of WFO codes). Fetches
                          water.weather.gov/ahps2/index.php?wfo=<WFO> for each,
                          regex-parses gauge links, then fetches up to 50
                          gauge detail pages per request and regex-parses
                          lat/lon + four threshold values. Best-effort; rows
                          stored under "AHPS-<gauge_id>" so they dont collide
                          with USGS-* ids. Returns the same shape plus
                          detail_fetched + errors list.
    Frontend (dashboard-frontend/src/pages/GaugeSites.tsx) gains a
    Import button + modal with two tabs (Paste CSV / Scrape NWS-AHPS)
    rendered via an ImportModal component. CSV tab has a 48-row textarea
    with the column-header hint inline; AHPS tab has a comma-separated WFO
    input defaulting to BOI. Both submit via fetch() and show the JSON
    response inline. Invalidates the curation cache server-side on any
    successful insert/update so nwis_handler sees the new gauges on its
    next call.

(4) WFIGS tombstone column -- CORRECTNESS
    v12.sql adds fires.tombstoned_at REAL (nullable) + idx_fires_tombstoned_at.
    meshai/central/wfigs_handler.py: the tombstone branch
    (kind=="wfigs_tombstone") UPDATE fires SET tombstoned_at=COALESCE(
    tombstoned_at, ?) so the first tombstone-time wins (idempotent against
    repeated tombstone envelopes).
    meshai/notifications/reminders/__init__.py: the wfigs tombstone
    termination condition now checks row["tombstoned_at"] IS NOT NULL.
    Reminders correctly STOP for closed fires -- before this change the
    8h cadence would have kept Active: broadcasts going indefinitely past
    a WFIGS removal.
    SCHEMA_VERSION 11 -> 12.

(5) Delete INCIDENT_BROADCAST_HEARTBEAT_S
    meshai/central/incident_handler.py: removed the dead constant
    (v0.5.9 REVISED dropped the heartbeat path but left the constant
    imported-but-never-read).
    tests/test_incident_handler.py: removed the orphan
    test_i_8h_heartbeat_triggers_update test (asserted None, used the
    deleted constant for time arithmetic) and the stray import line.

Tests (tests/test_tail_followups.py, 16 cases):
  - middleware fires refresh on PUT /api/config/notifications (200), does
    NOT fire on PUT /api/config/llm
  - env_reporter _block_cap() default 3000; mutate via PUT, invalidate,
    next read returns the new cap
  - CSV import inserts new rows, updates existing, skips bad rows,
    rejects missing required columns, rejects bad format
  - AHPS index parser extracts (gauge_id, name) from realistic HTML
  - AHPS detail parser extracts lat/lon + four thresholds from realistic
    HTML
  - fires has tombstoned_at column after migrations
  - wfigs tombstone branch stamps tombstoned_at
  - ReminderScheduler skips a fire whose tombstoned_at is NOT NULL
  - ReminderScheduler still fires for a fire whose tombstoned_at IS NULL
  - INCIDENT_BROADCAST_HEARTBEAT_S no longer importable

Foundation/API test counts bumped:
  REGISTRY 58 -> 59 (+ env_reporter_block_chars)
  schema_meta v11 -> v12

Test count: 844 -> 859 (+16 new, -1 deleted dead test). 0 regressions.
2026-06-05 21:37:05 +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_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_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_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