WEB-381 · Задача · — · web
P1 [UX/доверие]: любая деградация биллинга объясняется пользователю как «достигнут лимит безопасности» — ложная причина
Закрыт
P1 · важно
ведёт: —
Суть
chat-global/route.ts:1208-1212 превращает ЛЮБОЙ billing.status==='degraded' в единый пользовательский текст (константа src/lib/ai/providers/base.ts:10-11):
'AI generation is temporarily unavailable because the billing safety limit was reached.'
Фактическая причина в разобранном случае — внутренний конфликт идемпотентности кошелька, а НЕ достигнутый лимит: баланс -0.205977 при лимите овердрафта -5, запас около $4.79.
ПОЧЕМУ ВАЖНО: пользователю называется ложная причина, он идёт пополнять баланс и это не помогает; поддержка и мы сами диагностируем не туда — я сам сначала принял это за нехватку денег и чуть не пополнил кошелёк вместо починки дефекта. Плюс маскируется настоящий класс отказов.
ЧТО НУЖНО: различать причины деградации и говорить правду — исчерпан лимит / временный внутренний сбой учёта (с повтором) / отказ провайдера. Отдельно: код уже умеет различать transport rejection с HTTP-статусом (route.ts:1188-1206), но здесь ответ шёл in-band HTTP 200 — стоит решить, корректно ли отдавать деградацию под 200.
Источник: разбор батареи WEB-293, отчёт WEB293DIAG-REPORT.md на M4.
Доказательства
[2026-08-27 19:20Z] ПРИНЯТ acc381c (3 цикла): биллинговая семантика settleActual восстановлена бит-в-бит (unknown model НЕ в debit), 2 условия отчёта закрыты, все классы текстов + нейтральный fallback для нового reason, ru+en, без утечек, негатив ловит, скоуп чистый. -> done, ветка fix381msgs в набор посадки.
Починено в
fbdb90b
Воркер
не привязан — привязать:
curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \
-d '{"issueId":"WEB-381","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-08-26T21:48:27.254Z