fix(skills): TG poll 5xx triggers network backoff — HTTPError >=500 in poll_updates raises _NetworkPollError instead of rapid-fire retry; 4xx unchanged. 3 new tests (502/503 backoff, 429 excluded). Medic loop: detected by @trigger (ERROR ae5ddbd4), fixed autonomously by @skills, verified by devpulse (1080 tests green, seedgo 100%)

This commit is contained in:
AIOSAI
2026-07-19 21:20:10 -07:00
parent 0529a4e7c4
commit d1facd8bdc
3 changed files with 36 additions and 1 deletions
+5
View File
@@ -27,6 +27,11 @@ PyPI version — not the changelog header.
was already covered via the shared dispatch_monitor wrapper. @daemon's
scheduled wakes import `wake_branch` directly and were covered from the start.
**fix(skills)** — Telegram poll 5xx now triggers network backoff (medic loop,
autonomous @skills fix): `HTTPError` ≥500 in `poll_updates` raises
`_NetworkPollError` instead of falling through to rapid-fire retry; 4xx still
logs and returns. Three new tests (502/503 backoff, 429 stays out).
**fix(spawn, commons, prax, hooks)** — S304 audit fix campaign, Track A
(DPLAN-0250, four owner dispatches verified + committed by devpulse):
@@ -468,6 +468,8 @@ class BaseBot:
return []
if _is_network_error(e):
raise _NetworkPollError(str(e)) from e
if isinstance(e, HTTPError) and e.code >= 500:
raise _NetworkPollError(str(e)) from e
logger.error("Poll error: %s", e)
return []
except (ConnectionError, OSError) as e:
@@ -14,8 +14,9 @@ Tests cover:
- _is_routine_read_timeout classification
"""
from http.client import HTTPMessage
from unittest.mock import patch
from urllib.error import URLError
from urllib.error import HTTPError, URLError
import pytest
@@ -206,6 +207,33 @@ class TestPollUpdatesErrorClassification:
mock_logger.error.assert_called_once()
assert "Poll error" in str(mock_logger.error.call_args)
def test_http_502_raises_network_poll_error(self, tmp_path, _patch_base_bot_deps):
"""HTTP 502 Bad Gateway should trigger network backoff, not rapid-fire retry."""
bot = _make_bot(tmp_path, _patch_base_bot_deps)
exc = HTTPError("https://api.telegram.org/...", 502, "Bad Gateway", HTTPMessage(), None)
with patch("aipass.skills.lib.telegram.apps.handlers.base_bot.urlopen", side_effect=exc):
with pytest.raises(_NetworkPollError):
bot.poll_updates(0)
def test_http_503_raises_network_poll_error(self, tmp_path, _patch_base_bot_deps):
bot = _make_bot(tmp_path, _patch_base_bot_deps)
exc = HTTPError("https://api.telegram.org/...", 503, "Service Unavailable", HTTPMessage(), None)
with patch("aipass.skills.lib.telegram.apps.handlers.base_bot.urlopen", side_effect=exc):
with pytest.raises(_NetworkPollError):
bot.poll_updates(0)
def test_http_429_not_network_error(self, tmp_path, _patch_base_bot_deps):
"""Client-side HTTP errors (4xx) should NOT trigger network backoff."""
bot = _make_bot(tmp_path, _patch_base_bot_deps)
exc = HTTPError("https://api.telegram.org/...", 429, "Too Many Requests", HTTPMessage(), None)
with (
patch("aipass.skills.lib.telegram.apps.handlers.base_bot.urlopen", side_effect=exc),
patch("aipass.skills.lib.telegram.apps.handlers.base_bot.logger") as mock_logger,
):
result = bot.poll_updates(0)
assert result == []
mock_logger.error.assert_called_once()
def test_unexpected_exception_logs_error(self, tmp_path, _patch_base_bot_deps):
bot = _make_bot(tmp_path, _patch_base_bot_deps)
exc = ValueError("something weird")