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:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user