WEB-461 · Дефект · billing · web
P0 ПРОД: проекция терминального события SERVICE-плательщика (воркер индексации под enforce) падает wallet_debit mismatch → инцидент учёта → /api/ready/paid 503
Закрыт
P0 · горит
ведёт: —
Суть
02.09 ~23:52Z: первый в истории платный вызов service principal source-indexing под enforce (embeddings, 457 микро-USD) → tse_867a4a70bcf04dea55a92826b696 FAILED_OPEN (TerminalProjectionEffectMismatchError wallet_debit) → TerminalProjectionIncident tpi_08fe6234e22774f231e23e1d OPEN + SpendSettlementOutbox sob_f3ed925e ACCOUNTING_CORRUPTION OPEN + sob_0d95f0bf SETTLEMENT_FAILED → accountingGateClosed → paidReady 503 для всех. Корень: terminalEventProjection.ts applyAndVerifyTerminalProjectionEffectsTx — SERVICE-ветка недописана (пустой if), else-ветка ищет UserBalance по userId=NULL. Реконсилер падает так же каждые 5 мин; acctfix-repair блокирован (event не APPLIED, 0/5 receipts). Триггер: координатор перевёл nc-a1-indexing из DRY-RUN в --apply через enforce-обёртку (на малинке воркер никогда не работал под enforce — неметрированный спенд). Таймер воркера остановлен; источник cmrts7ntw удержан (poisoned REQUEUE-AFTER-WORKER-ENFORCE-FIX). Волна 1091-svcpayer в очереди A1 (база l86-candidate). Восстановление прода: посадка фикса → cron reconcile → acctfix-repair --apply --limit 1. Правка денежных таблиц вручную — только с owner-GO.
Лента
2026-09-02T00:15:02.557Z · Fable[02.09 00:20Z Фабл] Ручной ускоренный путь (owner GO в TG 00:04Z) ЗАКРЫТ самой базой: (1) пометка события APPLIED без квитанций не помогает — pending-CTE считает события без receipts независимо от projectionState (stalePendingProjections → paid 503); (2) переклассификация SERVICE→NON_USER отклонена триггером forbid_terminal_spend_event_witness_mutation (ACCOUNTING_CORRUPTION: witness immutable from INSERT) — транзакция откатилась, данные не изменены; бэкап строк /home/ubuntu/ops-backups/web461-rows-20260902T000721Z.sql. Остаётся код: волна 1091-svcpayer; план — горячий фикс l85b = l85 + svcpayer (A2 l85bchain.sh, ветка l85b-candidate), проверка проекции на копии прод-БД (noteclone_web461copy на A1, восстанавливается), посадка, reconcile, acctfix-repair.
2026-09-02T00:40:01.962Z · Fable[02.09 00:55Z Фабл] Фикс e56c5518 (волна 1091-svcpayer): SERVICE = pooled UserBalance (tenantId=service:<id>, userId NULL); корень — SQL `userId = NULL` в проверке кошелька → заменено на IS NOT DISTINCT FROM; repair-путь принимает SERVICE только при канонических tenant/user/team. Независимая приёмка 1098-accsvcpayer: ACCEPT (реальный Postgres, 5 receipts/1 debit, идемпотентный повтор, PERSONAL/NON_USER без изменений, мусорные scope fail-closed, прежний живой хеш 0f1683d5 сохранён в SUPERSEDED; hash-chain 16/17 = pre-existing на базе). Моя проверка на КОПИИ прод-БД (noteclone_web461copy): событие APPLIED, acctfix-repair закрыл инцидент и строку порчи; остаток — протухшая резервация + SETTLEMENT_FAILED под реконсилер. Сборка l85b (l85 + фикс) на A2 — второй прогон (первый упал на webpack, лог был обрезан). Отчёты: A1 /home/ubuntu/waves/SVCPAYER-REPORT.md, ACCSVCPAYER-REPORT.md.
2026-09-02T00:54:17.072Z · Fable[02.09 01:00Z Фабл] ЗАКРЫТ. Посадка горячего фикса l85b на A1: артефакт me2-standalone-linux-arm64-dd54145f9-20260902T004900Z (sha 17fe3a0b…), commit dd54145f = l85 + e56c5518; аттестация подписана owner-ключом на ноуте (builderIdentity fable-a2-l85b, PIN da2e5642), сухой прогон :3011 → posture enforce_ready, флип nc-a1 + nc-a1-indexing (drop-in NC_RELEASE_ID + enforce-worker-l85b.sh). Восстановление: reconcile #1 → событие tse_867a4a70 APPLIED (5 receipts, hash 7b9cb0f2, старый 0f1683d5 в superseded) → acctfix-repair --apply --limit 1 (tpi_08fe6234 REPAIRED, sob_f3ed925e RESOLVED) → reconcile #2 (резервация resv_214b SETTLED_MAX) → resolveBacklogEntry (sob_0d95f0bf RESOLVED, resolvedBy fable-coordinator-20260902-web461) → reconcile #3 durable openCount=0 → /api/ready/paid 200 paidReady=true. Простой платного контура 23:52Z–00:57Z. Скрипт посадки: A1 /home/ubuntu/land-l85b.sh; sign-kit: ноут ~/nc-ops-scripts/signkits/. Урок в память: service-payer-projection-gap-paid-503.
Воркер
не привязан — привязать:
curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \
-d '{"issueId":"WEB-461","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-09-02T00:54:17.091Z