From 567887fb60e1bc3ee8d9355d39dd5b73c2ffe458 Mon Sep 17 00:00:00 2001 From: jakeross Date: Mon, 29 Jun 2026 19:20:12 -0600 Subject: [PATCH] Derive PARAMETER_SOURCE_MAP waterlevels list from the SOURCES registry (3.3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The waterlevels agency list duplicated what the registry already encodes — the sources with a waterlevel class. It is now derived (`[s.key for s in SOURCES if s.waterlevel]`); PARAMETER_SOURCE_MAP moved below the registry so it can reference SOURCES. Analyte entries stay authored (they encode which analytes each agency reports, not inferable from class wiring). Derived list is identical (incl. order) to the previous hardcoded one; the test_source_registry consistency test still guards the relationship. Full suite (311) + dg check defs clean. Co-Authored-By: Claude Opus 4.8 --- backend/config.py | 53 ++++++++++++++++++++++---------------------- docs/cleanup-todo.md | 7 +++--- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/backend/config.py b/backend/config.py index 7ca139a..3830ec8 100644 --- a/backend/config.py +++ b/backend/config.py @@ -76,32 +76,6 @@ from backend.logger import make_logger -# Which sources report each parameter (empirical availability). A plain -# parameter -> [source_key, ...] map; the waterlevels list mirrors the sources -# with a waterlevel class in the SOURCES registry (asserted by -# tests/test_source_registry.py), while the analyte lists are authored because -# they encode which analytes each agency actually reports. -PARAMETER_SOURCE_MAP = { - WATERLEVELS: ["bernco", "cabq", "ebid", "nmbgmr_amp", "nmose_isc_seven_rivers", "nmose_roswell", "nwis", "pvacd", "wqp"], - CARBONATE: ["nmbgmr_amp", "wqp"], - ARSENIC: ["bor", "nmbgmr_amp", "nmed_dwb", "wqp"], - URANIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "wqp"], - SPECIFIC_CONDUCTANCE: ["nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - CONDUCTIVITY: ["bor", "nmose_isc_seven_rivers", "wqp"], - BICARBONATE: ["nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - CALCIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - CHLORIDE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - FLUORIDE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - MAGNESIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - NITRATE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - PH: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - POTASSIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - SILICA: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - SODIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - SULFATE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], - TDS: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], -} - @dataclass(frozen=True) class SourceDef: """One data source's class wiring, declared in a single place. @@ -160,6 +134,33 @@ class SourceDef: s.key: (s.site, s.waterlevel) for s in SOURCES if s.waterlevel is not None } +# Which sources report each parameter (empirical availability), parameter -> +# [source_key, ...]. The waterlevels list is DERIVED from the registry (every +# source with a waterlevel class). The analyte lists are authored because they +# encode which analytes each agency actually reports — which can't be inferred +# from the class wiring. tests/test_source_registry.py guards both against the +# registry. +PARAMETER_SOURCE_MAP = { + WATERLEVELS: [s.key for s in SOURCES if s.waterlevel is not None], + CARBONATE: ["nmbgmr_amp", "wqp"], + ARSENIC: ["bor", "nmbgmr_amp", "nmed_dwb", "wqp"], + URANIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "wqp"], + SPECIFIC_CONDUCTANCE: ["nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + CONDUCTIVITY: ["bor", "nmose_isc_seven_rivers", "wqp"], + BICARBONATE: ["nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + CALCIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + CHLORIDE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + FLUORIDE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + MAGNESIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + NITRATE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + PH: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + POTASSIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + SILICA: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + SODIUM: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + SULFATE: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], + TDS: ["bor", "nmbgmr_amp", "nmed_dwb", "nmose_isc_seven_rivers", "wqp"], +} + def get_source(source): try: diff --git a/docs/cleanup-todo.md b/docs/cleanup-todo.md index 01f1853..01c5716 100644 --- a/docs/cleanup-todo.md +++ b/docs/cleanup-todo.md @@ -1,7 +1,8 @@ # DIE Cleanup TODO -> **Status:** Tier 1 (all) and **all of Tier 2 except 2.6** are **DONE**. 2.6 is -> **deferred** (see note below). Remaining: 2.6, all of Tier 3, all of Tier 4. +> **Status:** Tier 1 (all), all of Tier 2 except 2.6, and Tier 3 item 3.3 are +> **DONE**. 2.6 is **deferred** (see note). Remaining: 2.6, Tier 3 items 3.1/3.2, +> all of Tier 4. Prioritized cleanup backlog from a code-analysis sweep (backend + frontend + orchestration). Each item: location, effort (S/M/L), risk, and whether it @@ -50,7 +51,7 @@ registry). Tiers are ordered by safety — Tier 1 is batchable into one no-risk |---|----------|--------|--------|---| | 3.1 | `frontend/cli.py:36-121` (`--no-X` flags) + `cli.py:385-398` (hardcoded agency list in `sites()`) | Derive from `backend.config.SOURCE_KEYS` — the remaining hardcoded source list after #101/#102. Click flags are harder to generate dynamically; at minimum dedup the `sites()` list. | M | ✓ | | 3.2 | `orchestration/definitions.py:60-68` (`_SUPPORTED_OUTPUT_TYPES`) vs `products.py` combine `if/elif` chain | Single registry mapping `output_type → (dumper, is_summary)`; both the supported-set and the dispatch derive from it. Adding an output type → one entry. | M | | -| 3.3 | `backend/config.py:79` `PARAMETER_SOURCE_MAP[WATERLEVELS]` | Derive the waterlevels agency list from the `SOURCES` registry (== sources with a waterlevel class; the desync test already asserts equality). Keep analyte entries authored. | S | ✓ | +| 3.3 ✅ | `backend/config.py` `PARAMETER_SOURCE_MAP[WATERLEVELS]` | Derived from the `SOURCES` registry (`[s.key for s in SOURCES if s.waterlevel]`). Analyte entries stay authored. Map moved below the registry so it can reference `SOURCES`. | S | ✓ | ---