Summary
The proxy-summary collection is designed so "a bad poll leaves the last good summary in place" — but that only holds if get_summary raises. If it returns a non-dict / list / falsy body, _parse_proxy_summary returns {} and overwrites the last-good value, blanking the pool-wide share-health panel.
Evidence
service/data_service.py (~lines 346-353): proxy_summary = self.latest_data.get("proxy_summary", {}), then proxy_summary = _parse_proxy_summary(summary_data) inside try — overwrites with {} on a non-raising malformed response.
_parse_proxy_summary (~line 111) returns {} for any non-dict input.
Impact
Intermittent malformed (non-exception) responses cause the accepted/rejected/invalid/best-difficulty panel to flicker to empty, contradicting the stated "last good value persists" design.
Suggested fix
Only assign when the parse yields a usable dict: parsed = _parse_proxy_summary(summary_data); if parsed: proxy_summary = parsed.
Summary
The proxy-summary collection is designed so "a bad poll leaves the last good summary in place" — but that only holds if
get_summaryraises. If it returns a non-dict / list / falsy body,_parse_proxy_summaryreturns{}and overwrites the last-good value, blanking the pool-wide share-health panel.Evidence
service/data_service.py(~lines 346-353):proxy_summary = self.latest_data.get("proxy_summary", {}), thenproxy_summary = _parse_proxy_summary(summary_data)insidetry— overwrites with{}on a non-raising malformed response._parse_proxy_summary(~line 111) returns{}for any non-dict input.Impact
Intermittent malformed (non-exception) responses cause the accepted/rejected/invalid/best-difficulty panel to flicker to empty, contradicting the stated "last good value persists" design.
Suggested fix
Only assign when the parse yields a usable dict:
parsed = _parse_proxy_summary(summary_data); if parsed: proxy_summary = parsed.