mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 17:31:34 +00:00
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:
parent
6595b10bdd
commit
63245b8fba
4 changed files with 71 additions and 4 deletions
|
|
@ -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
|
||||
# ============================================================
|
||||
|
|
|
|||
|
|
@ -232,6 +232,27 @@ def test_renderer_byte_budget_drops_optional_segments():
|
|||
assert "lightning" not in s
|
||||
|
||||
|
||||
def test_renderer_omits_none_context_fields():
|
||||
"""Regression — native road adapters set optional context keys present but
|
||||
None (``cause``/``expires_at``/``containment_pct``). The composer must
|
||||
guard on value, not key presence, so the literal string 'None' never leaks
|
||||
onto the wire."""
|
||||
e = make_event(
|
||||
source="wzdx", category="wildfire_incident", severity="immediate",
|
||||
title="Test Fire", region="Boise", timestamp=time.time(),
|
||||
data={"cause": None, "expires_at": None, "containment_pct": None},
|
||||
)
|
||||
s = compose_mesh_message(e)
|
||||
assert "None" not in s
|
||||
# A real value on the same field still renders (guard doesn't over-suppress).
|
||||
e2 = make_event(
|
||||
source="wzdx", category="wildfire_incident", severity="immediate",
|
||||
title="Test Fire", region="Boise", timestamp=time.time(),
|
||||
data={"cause": "lightning", "expires_at": None, "containment_pct": None},
|
||||
)
|
||||
assert "lightning" in compose_mesh_message(e2)
|
||||
|
||||
|
||||
def test_renderer_never_mid_character_truncation():
|
||||
"""The composer must never emit a UTF-8 byte sequence that splits a
|
||||
codepoint. Even with required-only over budget, we drop wholesale or
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue