WEB board

всеканоны и докиворкеры↗ iOS↗ Легаси
WEB-468 · Дефект · — · web

Учёт: отказ по лимиту перерасхода кошелька (OverdraftLimitError) одного пользователя превращается в ACCOUNTING_CORRUPTION и закрывает платный контур ВСЕМ (paid 503) — прод l89 02.09 07:17Z, QA-учётка батареи

Закрыт P1 · важно ведёт: Fable
Суть
Факт (прод l89, 02.09 07:17Z): QA-учётка батареи r8.fixture.synthetic@example.invalid дошла до лимита перерасхода (cash −4.952413, limit −5). Терминальное событие tse_5375410831b950647bd1548a5140 → проекция упала OverdraftLimitError: wallet: overdraft limit reached (debit 0.048455) → TerminalProjectionIncident tpi_328cc3a1c98fae725259f3de OPEN (errorCode terminal_projection_failed) → SpendSettlementOutbox ACCOUNTING_CORRUPTION OPEN → accountingGate закрыт → /api/ready/paid 503 для всех, чат 500 (VendorCallRejectedError). Батарея ролей l89 посыпалась с C2-05.

Класс дефекта: тот же, что WEB-461/WEB-467 — одно событие одного плательщика закрывает платный контур всем. Отказ по лимиту — бизнес-условие (нет денег у пользователя), не порча учёта: событие должно резолвиться как «отказ по лимиту/долг» для ЭТОГО пользователя (блокировать только его платные вызовы), без инцидента порчи и без закрытия общего гейта.

Восстановление (ручное): пополнить кошелёк QA (админ /api/admin/wallet-grant — только сессия admin/owner; или DB с GO owner-а) → /api/cron/spend-reconcile → APPLIED → scripts/acctfix-repair-incidents.ts --apply → reconcile → paid 200.

Связь: WEB-461 (SERVICE payer), WEB-467 (transient timeout, l89), WEB-466 (billing UI). Память: service-payer-projection-gap-paid-503.
Починено в
l91-9ad68bc2
Лента
2026-09-02T11:10:35.744Z · Fable
[A1 ~11:25 Фабл] Волна 1191-web468overdraft2 сдана на M4: коммит 8d24fffc038baa67e3687870886d5e48ce776c01 (ветка web468overdraft2-1191, база l90 26da36faba). Суть: при OverdraftLimitError проекция идёт по projection-only debt path (полный ownerChargedMicros в LedgerEntry, bucket-инвариант wallet↔ledger проверяется, событие APPLIED, overdraft_exceeded:true в receipt) — овердрафт одного плательщика больше не создаёт TerminalProjectionIncident/ACCOUNTING_CORRUPTION и не закрывает общий accountingGate; admission считает integer micros и отдаёт 402 insufficient_funds ниже floor (BYOK не блокируется). Новый projection hash ab10332c250ef49a2fea89bf20d431c8095358c1c6c56765addf93328f408a4c с прежним в superseded chain. Проверки автора: web468Overdraft.integration.test.ts на real PG17+pgvector 0.8.6 PASS; terminalEventProjection 29/29; spendContainmentGatewayV2 26/26; scoped tsc PASS. Отчёт /Users/milamarty/waves/WEB468OVERDRAFT2-REPORT.md (M4). Приёмка 1195-accweb468overdraft2 на M4 (другой verifier; негатив: сломать bucket-инвариант, 402 ниже floor, BYOK). После GO → l91-candidate; при посадке l91 добавить ab10332c… в PROJECTION_LIVE_IMPLEMENTATION_HASHES, иначе stale pending. Предыстория: 1161 (A1) отвергнута — работала через sudo в боевой БД (WEB-472).
2026-09-02T11:29:08.547Z · Fable
[A1 11:28 Фабл] Приёмка 1195-accweb468overdraft2 (M4, другой verifier, дерево от коммита автора 8d24fffc, real PostgreSQL одноразовый): **GO**. Подтверждено: овердрафт одного плательщика не закрывает общий accountingGate/paid; admission ниже floor блокирует только owner-paid dispatch (402), BYOK не задет; негатив на bucket-инвариант ловится; rule10 — новые catch либо пробрасывают после diagnostic, либо отдают машиночитаемую деградацию. Находки вне скоупа (baseline, в WEB-473): projection-hash-chain unit «more than ten» ждёт 11 при MAX_LIVE_PROJECTION_HASHES=14 (4/5); check-ai-import-boundary 6 offenders + 4 stale allowlist; wallet unit 10/12 (старые тесты с raw identity); web374Replay.integration на старом harness; интеграционный тест WEB-468 без cleanup (повтор в той же БД падает на openCount=1); verify:projection-hash-chain не переносит URL с ?schema=public; две миграции 20260831011000/20260831021000 с CREATE INDEX CONCURRENTLY внутри транзакции не деплоятся обычным prisma migrate deploy (см. prod-db-migration-ledger). Линия перенесена: A2 nc-build ветка web468overdraft2-1191, A1 mirrors/lines/web468overdraft2-1191-8d24fffc03.bundle → l91-candidate. При посадке l91: добавить hash ab10332c25… в PROJECTION_LIVE_IMPLEMENTATION_HASHES.
2026-09-02T14:12:25.938Z · Fable
[A1 14:12 Фабл] ПОСАЖЕНО l91 на прод A1: release arm64-l91-20260902T140416Z, run l91-9ad68bc2, sourceCommit 9ad68bc261c833e792bc17523245975e15f48612, артефакт sha 96b3466b…dc3f; ready TRUE (boot/database/release/drain ok), paid TRUE enforce_ready, public 200, live-sha 9ad68bc2; SIP-стек перезапущен (readiness 200/200, монитор аренды пережил рестарт: 2 poll-failed, LOST=0). Откат: land-l90 run/l90-26da36fa (nc-a1.service.bak-l90). Фикс овердрафта (8d24fffc → fcf5d933) в serving; новый projection hash ab10332c25… включён в PROJECTION_LIVE_IMPLEMENTATION_HASHES сборки (14). Проверка: батарея r31 + отсутствие ACCOUNTING_CORRUPTION при овердрафте QA-плательщика.
2026-09-02T16:10:12.376Z · Fable
[A1 16:20 Фабл] Закрываю: фикс 1191-web468overdraft2 (8d24fffc, новый projection hash ab10332c) принят 1195 (M4) и посажен в l91 (9ad68bc2, 14:10 A1); овердрафт одного пользователя больше не роняет /api/ready/paid всем; QA-кошелёк пополняется через admin wallet-grant (не raw SQL), рецепт в памяти qa-wallet-refill-recipe-and-owner-go. Прод-проверка: paid 200 с 14:10 под батареей r31c (46/50) и Playwright-приёмками.
2026-09-03T02:01:38.477Z · Fable
[A1 Фабл] При чистке диска A1 (03.09) worktree волны 1161-web468overdraft содержал НЕЗАКОММИЧЕННУЮ работу (11 файлов, +219/-18: walletService.ts, chatFailureMessage.ts, messagePersistence.ts …), маркера WEB468OVERDRAFT_DONE нет — волна не завершилась. Сохранено как `git -C /home/ubuntu/nc stash` «cleanup-wt-1161-web468overdraft» (ветка web468overdraft-1161, keep/1161-web468overdraft на HEAD). Следующая волна по WEB-468 стартует с этого stash.
Воркер
не привязан — привязать: curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \ -d '{"issueId":"WEB-468","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-09-02T16:10:12.267Z