fix: WZDx registry nested-url crash + composer "None" leak (dry-run findings) (#42)

Two bugs found running native adapters against real upstreams:

- env/wzdx.py: _select_feeds() called .strip() on the registry url field,
  but Socrata "URL"-column values arrive as {"url": "..."} — crashed ALL
  native WZDx discovery with AttributeError. Added _unwrap_url() (dict/str/
  None-robust), applied to url/apiurl/feed_url.
- composer._context_segment: appended optional fields by key presence, so
  cause: None (set by native road adapters) leaked literal "None" onto the
  wire. Guard on value (cause/expires_at truthiness; containment_pct is-not-
  None so 0% still renders). Legacy Mode-B path — golden tests unchanged.

+3 regression tests; golden/composer suites pass; full suite 10-failure
baseline (1685 passed).

Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
malice 2026-07-05 10:10:09 -06:00 committed by GitHub
commit 63245b8fba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 71 additions and 4 deletions

View file

@ -122,6 +122,33 @@ def test_select_feeds_handles_garbage(adapter):
assert adapter._select_feeds([None, 3, {"state": "ID"}]) == [] # no url
def test_select_feeds_unwraps_socrata_url_object(adapter):
"""Live FHWA registry serializes Idaho's ``url`` as a Socrata "URL" column
object (``{"url": ""}``), not a bare string. Selection must unwrap it and
never raise ``AttributeError: 'dict' object has no attribute 'strip'``."""
rows = [
{"state": "Idaho", "format": "geojson",
"url": {"url": "https://511.idaho.gov/api/wzdx"}},
]
feeds = adapter._select_feeds(rows)
assert feeds == ["https://511.idaho.gov/api/wzdx"]
def test_tick_survives_socrata_url_object(adapter, monkeypatch):
"""End-to-end discovery path tolerates the nested-object ``url`` shape."""
registry = [{"state": "Idaho", "format": "geojson",
"url": {"url": "https://511.idaho.gov/api/wzdx"}}]
fc = make_feature_collection(make_wzdx_feature(feat_id="A"))
def fake_get(url, timeout=30):
return registry if "datahub" in url else fc
monkeypatch.setattr(adapter, "_http_get_json", fake_get)
# Must not raise; the unwrapped feed URL is discovered and fetched.
assert adapter.tick() is True
assert {e["external_id"] for e in adapter.get_events()} == {"idot-1:A"}
# ============================================================
# CATEGORY + CANONICAL DATA
# ============================================================