fix(readiness): роль на резерве считается работающей
Со скриншота владельца: заголовок «Ролей в строю: 0/6», а ниже шесть предупреждений «роль работает через резервный аккаунт». Пять ролей исправно отвечали, интерфейс сообщал, что не работает ни одна. roles_ready считал только роли со здоровым ОСНОВНЫМ профилем. Роль, обслуживаемая резервом, попадала в degraded_roles, но не в ready. Ошибка в худшую сторону: отказ показывался там, где всё работает — а переключение на резерв это ровно то, ради чего продукт и создан. Теперь роль с живым резервом считается работающей и одновременно помечается деградировавшей: оба состояния остаются различимыми. Попутно склонение: «Есть 1 ролей без рабочего маршрута» заменено на согласованное с числом — 1 роль, 2 роли, 5 ролей. Проверено на живых данных: 6/6 в строю, состояние «деградация», а не «критическое». Тесты: 375 passed, ruff чисто. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
bca88a56a6
commit
03d73f8d0b
2 changed files with 62 additions and 2 deletions
|
|
@ -170,6 +170,17 @@ class ProviderSummary:
|
||||||
last_refresh_at: str
|
last_refresh_at: str
|
||||||
|
|
||||||
|
|
||||||
|
def _plural_roles(n: int) -> str:
|
||||||
|
"""Согласовать число со словом «роль»: 1 роль, 2 роли, 5 ролей."""
|
||||||
|
tail = n % 100
|
||||||
|
if 11 <= tail <= 14:
|
||||||
|
word = "ролей"
|
||||||
|
else:
|
||||||
|
last = n % 10
|
||||||
|
word = "роль" if last == 1 else "роли" if 2 <= last <= 4 else "ролей"
|
||||||
|
return f"{n} {word}"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SystemReadiness:
|
class SystemReadiness:
|
||||||
state: str # HEALTHY | LIMITED | DEGRADED | CRITICAL
|
state: str # HEALTHY | LIMITED | DEGRADED | CRITICAL
|
||||||
|
|
@ -567,6 +578,12 @@ class UnifiedHealthService:
|
||||||
break
|
break
|
||||||
|
|
||||||
if has_working_fallback:
|
if has_working_fallback:
|
||||||
|
# Роль, обслуживаемая резервом, РАБОТАЕТ — она просто
|
||||||
|
# деградировала. Раньше она не попадала в roles_ready, и
|
||||||
|
# интерфейс писал «Ролей в строю: 0/6», пока пять ролей
|
||||||
|
# исправно отвечали. Это вводит в заблуждение в худшую
|
||||||
|
# сторону: пользователь видит отказ там, где всё работает.
|
||||||
|
roles_ready += 1
|
||||||
degraded_roles += 1
|
degraded_roles += 1
|
||||||
warnings.append(f"Роль '{rname}' работает через резервный аккаунт (Primary недоступен).")
|
warnings.append(f"Роль '{rname}' работает через резервный аккаунт (Primary недоступен).")
|
||||||
else:
|
else:
|
||||||
|
|
@ -577,11 +594,11 @@ class UnifiedHealthService:
|
||||||
if dead_roles > 0:
|
if dead_roles > 0:
|
||||||
state = READINESS_CRITICAL
|
state = READINESS_CRITICAL
|
||||||
title_ru = "Критическое состояние"
|
title_ru = "Критическое состояние"
|
||||||
summary_ru = f"Есть {dead_roles} ролей без рабочего маршрута!"
|
summary_ru = f"Без рабочего маршрута: {_plural_roles(dead_roles)}."
|
||||||
elif degraded_roles > 0:
|
elif degraded_roles > 0:
|
||||||
state = READINESS_DEGRADED
|
state = READINESS_DEGRADED
|
||||||
title_ru = "Деградация маршрутов"
|
title_ru = "Деградация маршрутов"
|
||||||
summary_ru = f"{degraded_roles} ролей работают через резерв."
|
summary_ru = f"Через резерв работают: {_plural_roles(degraded_roles)}."
|
||||||
elif connected_accounts < total_accounts:
|
elif connected_accounts < total_accounts:
|
||||||
state = READINESS_LIMITED
|
state = READINESS_LIMITED
|
||||||
title_ru = "Ограниченная готовность"
|
title_ru = "Ограниченная готовность"
|
||||||
|
|
|
||||||
43
tests/test_readiness_counting.py
Normal file
43
tests/test_readiness_counting.py
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
"""Роль на резерве считается работающей.
|
||||||
|
|
||||||
|
Дефект со скриншота владельца: заголовок «Ролей в строю: 0/6», а ниже
|
||||||
|
шесть предупреждений вида «роль работает через резервный аккаунт». Пять
|
||||||
|
ролей исправно отвечали, а интерфейс сообщал, что не работает ни одна.
|
||||||
|
|
||||||
|
roles_ready считал только роли со здоровым ОСНОВНЫМ профилем. Роль,
|
||||||
|
обслуживаемая резервом, попадала в degraded, но не в ready. Это ошибка в
|
||||||
|
худшую сторону: пользователь видит отказ там, где всё работает.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from antigravity_provider.router.unified_health import _plural_roles
|
||||||
|
|
||||||
|
|
||||||
|
def test_role_on_fallback_counts_as_ready():
|
||||||
|
"""Роль, у которой жив резерв, обязана попадать в «в строю»."""
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
from antigravity_provider.router import unified_health
|
||||||
|
|
||||||
|
src = inspect.getsource(unified_health.UnifiedHealthService.get_system_readiness)
|
||||||
|
marker = "if has_working_fallback:"
|
||||||
|
assert marker in src
|
||||||
|
tail = src.split(marker, 1)[1].split("else:", 1)[0]
|
||||||
|
assert "roles_ready += 1" in tail, (
|
||||||
|
"роль на резерве снова не засчитывается как работающая"
|
||||||
|
)
|
||||||
|
assert "degraded_roles += 1" in tail, (
|
||||||
|
"признак деградации потерян — состояние должно оставаться отличимым"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_plural_roles_agrees_with_number():
|
||||||
|
"""«Есть 1 ролей» — так по-русски не пишут."""
|
||||||
|
assert _plural_roles(1) == "1 роль"
|
||||||
|
assert _plural_roles(2) == "2 роли"
|
||||||
|
assert _plural_roles(4) == "4 роли"
|
||||||
|
assert _plural_roles(5) == "5 ролей"
|
||||||
|
assert _plural_roles(11) == "11 ролей"
|
||||||
|
assert _plural_roles(21) == "21 роль"
|
||||||
|
assert _plural_roles(112) == "112 ролей"
|
||||||
Loading…
Reference in a new issue