WEB-677 · Дефект · billing · web
P1: сервисный кошелёк индексации на бою уходит в долг без пополнений — через ~41 день (около 2026-11-02) индексация всех пользователей встанет с «Insufficient AI funds»
Закрыт
P1 · важно
ведёт: —
эпик: WEB-626
Суть
Найдено 21.09.2026 (волны 4559 на стенде, 4561 на бою; SELECT-only).
ФАКТ: воркер индексации источников (nc-a1-indexing) работает под сервисным принципалом tenantId=service:source-indexing с ОБЩИМ кошельком UserBalance. На бою: cashBalanceUsd = -2.101377, ledger-записей 4 878, положительных 0, пополнений за 30 дней 0, расход 0.0700459 USD/день (30-дневный темп). Лимит овердрафта: BILLING_OVERDRAFT_LIMIT_MICROS в окружении воркера не задан → действует умолчание DEFAULT_OVERDRAFT_LIMIT_MICROS=5 000 000 (5 USD); WALLET_OVERDRAFT_REQUIRES_FUNDING=0 (funded=not_required). Прогноз при текущем темпе: лимит будет достигнут примерно 2026-11-02 (~41 день от 21.09). После этого КАЖДАЯ индексация (загрузки пользователей, переиндексация, ремонт) получает «wallet admission denied … below limit» → «Insufficient AI funds», документы уходят в failed → poisoned после 3 попыток. Ошибок «Insufficient AI funds» на бою за 30 дней — 0 (ExtractionJob.lastError; у Document поля lastError нет).
НА СТЕНДЕ ЭТО УЖЕ СЛУЧИЛОСЬ: service:source-indexing = -4.999892 при 6 179 списаниях и 0 пополнениях; все новые документы отравлялись «Insufficient AI funds» (4546, 4553); координатор снял штатной переменной BILLING_OVERDRAFT_LIMIT_MICROS=1000000000 у воркера стенда (резерв worker.env.pre-coord-20260921T2200Z). Код: src/lib/billing/meteredVendorCall.ts (wallet admission), бандл воркера: debitStaysWithinOverdraftLimit / resolveOverdraftLimitMicros / WALLET_OVERDRAFT_REQUIRES_FUNDING.
ЧЕМ ЭТО ПЛОХО: сервисный кошелёк — единственный на всех пользователей; он только тратит и никогда не пополняется; при достижении лимита индексация останавливается молча (ошибка уходит в metadata документов, пользователь видит «документ не готов»). Ни мониторинга, ни пополнения, ни тревоги.
ЧТО СДЕЛАТЬ (варианты, решение владельца): (а) сервисному принципалу — не кошелёк с овердрафтом, а безлимитный/«системный» режим (учёт без блокировки), т.к. стоимость уже списывается с пользовательских кошельков/подписок на уровне продукта — проверить, не двойной ли учёт; (б) либо периодическое пополнение сервисного кошелька + тревога при spendable < 20% лимита; (в) минимум прямо сейчас: задать BILLING_OVERDRAFT_LIMIT_MICROS в окружении боевого воркера с запасом (например 100 USD) при следующей посадке и поставить проверку баланса в предпосадочные/ежедневные проверки (SELECT по UserBalance WHERE tenantId LIKE 'service:%').
ДОКАЗАТЕЛЬСТВА: a1nc:/home/ubuntu/waves/4561PRODSERVICEWALLET-evidence/ (wallet.md, limit.md, forecast.md); a2nc:/home/ubuntu/waves/4559SEEDEDTENANTSWALLET-evidence/ (how-4460-got-funds.md); брифы waves-20260921/4559-*, 4561-*.
## Актуализация координатора 2026-09-26 12:01Z [refresh-20260926-roles-capacity]
Правила обогащения: WEB-449.
Разделены source acceptance и доставка: историческая независимая5045 GO для общего563db146 сохраняется в своём объёме (PG17/17+generic1, targeted291/291). Новая интеграция5058 со связанной CPU/worker веткой закончилась NO-GO без артефакта/bundle. Новые Linux fixes не приняты; успешные source tests не означают новую посадку. Общий оставшийся шаг — восстановление сборки координатором, затем полная проверка пакета и отдельная посадочная приёмка. Этот тикет не объявляется заново завершённым на основании5058.
КАРТА ДОКУМЕНТОВ / доказательства: M1:/Users/poolpooly/waves/5045MERGEDCANDIDATEINDEPENDENT-REPORT.md; A2:/home/ubuntu/waves/5058INTEGRATEDLINUXSTANDBUILD-REPORT.md; A2:/home/ubuntu/waves/5058INTEGRATEDLINUXSTANDBUILD-evidence/SHA256SUMS; ноутбук:/Users/annakorin/nc-ops-scripts/material-5058/5056NEXTBOOTSTRAPCOMPATIBILITYCOMPLETION.bundle
Как воспроизвести
На стенде уже воспроизведено: service:source-indexing = -4.999892 при лимите 5 USD → все новые документы poisoned с «Insufficient AI funds» (4546, 4553). На бою: SELECT cashBalanceUsd FROM UserBalance WHERE tenantId='service:source-indexing' → -2.101377, темп -0.07 USD/день.
Чем закрывается (приёмка)
Сервисная индексация не блокируется кошельком (системный режим или гарантированное пополнение), баланс service:* виден в мониторинге с тревогой; на бою после посадки за 7 дней 0 ошибок «Insufficient AI funds» у документов пользователей.
Доказательства
4561 (бой, SELECT-only), 4559 (стенд)
Лента
2026-09-22T20:34:29.200Z · coordinator[22.09 20:34Z координатор] ## 22.09 20:34Z — волна-правка 4626 (M1) запущена: системный режим для `service:*` (овердрафт не блокирует, списания учитываются, тревога) ИЛИ автопополнение — по коду, с тестами
- База: ветка от l115r `1a5822a8` (дерево на M1). Временная мера при посадке остаётся: `BILLING_OVERDRAFT_LIMIT_MICROS=20000000` у боевого воркера.
- Ожидаемая сдача: `map.md` (где отказ становится «Insufficient AI funds»), `decision.md` (A/B с рисками), `commit.patch`, тесты (сервисный проходит, арендатор — отказ), `check.sql` для ежедневной проверки баланса `service:%`.
2026-09-22T21:49:47.213Z · coordinator[22.09 21:49Z координатор] ## 4626 (M1, GO, 6/6) — правка: сервисные принципалы `service:*` не блокируются овердрафтом (вариант A), списания учитываются, тревога по порогам; коммит `9a812656` на ветке `l115s-web677` (от 1a5822a8)
- Файлы: `walletService.ts`, `terminalEventProjection.ts`, тесты `overdraftOnlyFunded.unit.test.ts`, `serviceWalletOverdraft.test.ts` (+2). Новых env нет. Тесты: новые 5/5, существующие billing 44/44; typecheck затронутых файлов 0 ошибок.
- Контрольный случай: арендатор ниже лимита — по-прежнему отказ. `check.sql` для ежедневной проверки баланса `service:%` в evidence.
- Дальше: патч → A2 ветка, вход в следующую линию после l115r; временная мера при посадке l115r остаётся (`BILLING_OVERDRAFT_LIMIT_MICROS=20000000`).
- Сдача: `m1:~/waves/4626WEB677SERVICEWALLETOVERDRAFTFIX-evidence/` (`map.md`, `decision.md`, `commit.patch`, `tests.md`, `typecheck.md`, `check.sql`).
2026-09-23T07:08:25.857Z · coordinator[23.09 07:08Z координатор] ## 4626 (M1, GO) — уже сделано 23.09 ~00:xxZ (координатор не отметил на доске, а в 07:06Z по ошибке запустил дубль 4669 — остановлен): вариант A — овердрафт только для ПОПОЛНЯВШИХСЯ кошельков (`overdraftOnlyFunded`), сервисный кошелёк без пополнений в долг не уходит и не отравляет документы; `src/lib/billing/walletService.ts`, `terminalEventProjection.ts`, тесты 5/5 новых + 44/44 billing, typecheck 0. Ветка A2 `l115s-web677` (коммит 9a812656). Владельцу: решить о пополнении сервисного кошелька (0,07 USD/день) — код уже не даёт ему уйти в долг; до посадки на бою действует `BILLING_OVERDRAFT_LIMIT_MICROS` по умолчанию.
2026-09-25T08:42:20.077Z · coordinator[25.09 08:42Z координатор] # Ready board comment — WEB-677
2026-09-25 — POST-QA all9 `879094713e`: **REOPEN**.
Проверка: service principal scope есть (`src/lib/billing/walletService.ts:181`), funding-history fence обходится около `:401`, и health сообщает состояние service wallet (`src/lib/ingest/sourceIndexingWorkerHealth.ts:395`). Но это не выполняет приёмку: `src/lib/billing/meteredVendorCall.ts:658` всё ещё может отказать ниже configured overdraft, а `walletService.ts:330-346` подставляет default при отсутствии env. По WEB-677 коммитов в all9 диапазоне по ключу нет.
Что вернуть в работу: выбрать system/unlimited accounting либо гарантированное пополнение; сделать `service:*` balance и порог тревоги наблюдаемыми; после посадки собрать seven-day receipt с 0 `Insufficient AI funds`. Live proof не запускался по границам волны, но кодовый no-stop gap уже достаточен для REOPEN.
Траблшут: не путать health report с admission bypass. Новый агент начинает с этого файла → `meteredVendorCall.ts:658` → wallet health. WEB-449 и исходные `4559/4561` evidence paths записаны в карточке; бой и секреты не трогать.
Проверка координатора (09:5xZ, all9 879094713e, M1): REOPEN принят — нужен раунд исправления.
2026-09-25T09:22:10.876Z · coordinator[25.09 09:22Z координатор] 2026-09-25 — 4985 (M1, all9 879094713e): VERDICT=GO, но неполный. WEB-676: прямой reindex адресует выбранный sourceId и атомарно уступает ожидающей загрузке пользователя (sourceReadGateway.ts:1596, sourceIndexingQueue.ts:1081, reindex-quarantined-chunks.ts:1533), unit 10/10; PG-тест SKIP. WEB-677: сервисный вызов не блокируется кошельком, но учитывается в ledger; пользовательский кошелёк по-прежнему блокирует; баланс сервисного кошелька и порог −80% видны в health (llmBilling.ts:361, meteredVendorCall.ts:637, walletService.ts:353/1029, sourceIndexingWorkerHealth.ts:448); PG-тест 0/1 SKIP (на M1 нет БД). WEB-685 263/263. Коммиты на A2: l115s-web676-677-4985 (416e1f76d5, c47a54dc99), сводная ветка l115s-all9-pgcheck = all9 + 4984 + 4985. Приёмка на живом Postgres — волна 4986 (A2, вместе с WEB-671). Статус не меняю до её вердикта.
2026-09-25T12:11:56.195Z · coordinator[25.09 12:11Z координатор] PG-приёмка 4986: WEB-671 зелёный 3/3. WEB-677 NO-GO: сервисный вызов не списывается со счёта service:* и не пишет проводку (живой PostgreSQL). Исправление — волна 4991 на Neo.
WEB-676: прямые проверки не дошли, упала раньше фикстура WEB-99 (source-revive); разбор в 4991.
2026-09-25T12:11:57.143Z · coordinator[25.09 12:11Z координатор] PG-приёмка 4986: WEB-671 зелёный 3/3. WEB-677 NO-GO: сервисный вызов не списывается со счёта service:* и не пишет проводку (живой PostgreSQL). Исправление — волна 4991 на Neo.
WEB-676: прямые проверки не дошли, упала раньше фикстура WEB-99 (source-revive); разбор в 4991.
2026-09-25T12:14:16.574Z · coordinator[25.09 12:14Z координатор] 4991 (Neo, Luna): VERDICT=GO. WEB677_PG 8/8, SERVICE_CALL_LEDGERED=ДА (service:* списывается в транзакции settle, тот же ключ операции что у асинхронной проекции → повтор no-op), SETTLE_IDEMPOTENT=ДА, USER_WALLET_BLOCKS=ДА; WEB676_PG 2/2; WEB-99 = устаревшая PG-фикстура (импорт до DATABASE_URL, нет claim token), не дефект кода; WEB671_PG 3/3; WEB-685 263/263. Ветка A2 l115s-web677-r3-4991 (eb6379afb3, 5 коммитов на all9). Независимое ревью — 4994 (Astra, Neo).
2026-09-25T12:46:40.286Z · coordinator[25.09 12:46Z координатор] 25.09 13:50Z — независимое ревью 4997 (Neo, Opus 5.5) раунда WEB-677 r3 / WEB-676 (4991, eb6379afb3) — GO с условием.
Двойного списания нет (повтор + параллельные проекции → 1 запись, сумма = факт). Недосписания нет (ошибка вендора и отсутствие usage → SETTLED_MAX). База на тех же тестах красная → фикс настоящий.
Тесты совпали: WEB-677 PG 8/8, WEB-671 3/3, WEB-676 PG 2/2, WEB-685 263/263, смежные биллинг-юниты 118/118.
MAJOR-1 (решение владельца): сервисный кошелёк service:* уходит в долг без предела; при −$1 000 000 вызовы идут к вендору; сигнал только serviceWalletLow у воркера индексации. Принять долг или нужен потолок/тревога для всех service:*?
MINOR: 1) квитанции SERVICE теряют overdraft_exceeded; 2) ошибка кошелька в settle закрывает глобальные ворота; 3) причина WEB-99 в отчёте неполна (был реальный дефект ::bigint, исправлен); 4) любой промах прямого claim помечен reindex-admission-deferred; 5) авторский PG-тест не проверяет проекцию и точную сумму; 6) tests.md без нужных env не воспроизводится.
Доказательства: Neo ~/waves/4997REVIEWWEB677R3OPUSNEO-evidence (SHA256SUMS сверен).
2026-09-25T12:52:45.605Z · coordinator[25.09 12:52Z координатор] 25.09 12:52Z — РЕШЕНИЕ ВЛАДЕЛЬЦА по MAJOR-1 ревью 4997: служебные кошельки service:* МОГУТ уходить в минус (долг без потолка) — это нужно для наших тестов, иначе они часто падают/останавливаются на пустом кошельке.
MAJOR-1 принят как намеренное поведение, блокером не считается. WEB-677 r3 (4991, eb6379afb3) идёт в сборку all10 вместе с фиксом CPU 4999.
Остаются MINOR 1–6 из 4997 — берём попутным раундом, не блокируют.
2026-09-25T18:39:42.531Z · coordinator[25.09 18:39Z координатор]
## Параллельная работа 2026-09-25 18:39Z
- Шесть назначений с подтверждёнными стартами: A1 5030 postQA executable package (18:29:04Z); M1 5031 recovery kit (18:29:11Z), 5032 independent roles review (18:34:43Z), 5035 service wallet floor fix (18:38:30Z); A2 5033 CPU stand deploy (18:36:27Z); M4 5034 D1 caller fix (18:37:56Z).
- M1: три процесса Codex живы, логи свежие, конечных EXIT=.*END= нет. Отдельная строка EXIT=1 в 5032 относится к внутреннему выполнению, не к завершению runner. Не перезапускать.
- 5027 полный manifest PASS из ~/waves; авторский GO, независимая приёмка 5032 ещё идёт. 5028 независимый NO-GO подтверждён полным manifest, DONE и dispatcher done: realtime reopen обходит общую D1 политику; продолжение 5034 уже запущено.
- A2 SHA CPU архива совпал. Удалён только воспроизводимый /home/ubuntu/wt-l115s-all4/.next после проверки отсутствия процессов дерева и сохранности архива. Свободно 12.37 GiB. BASE_REPO в preflight позволяет проверить точное дерево, BASE SHA сохранён. 5033 прошёл оба сторожа; деплой пока не принят.
- Кроме ролей и ступеней реально работают три исполнителя: 5030, 5031, 5035. Семь карточек in_progress не равны семи независимым заданиям: комплект восстановления общий, экзамен зависит от его готовности. Neo ниже дискового порога и не занят.
- Telegram watcher PID85193 подтверждён. Следующий одноразовый тик 19:54 Europe/Dublin, session-only. WEB686 повторно не запускался.
2026-09-25T19:18:52.705Z · coordinator[25.09 19:18Z координатор]
## Тик 2026-09-25 19:18Z
- 5033 CPU stand deploy GO: полный manifest evidence PASS, dispatcher done 19:00:16Z; migration delta 0, dump verified, edge и четыре app ready/login/realtime PASS. PROD_CHANGED=НЕТ, LOAD_EXECUTED=НЕТ. Фактический source 0c087ab107c86d4beedd630a94c30fea6cae71e5; env attestation остаётся all9.
- 5036 v30 independent offline GO: полный manifest и DONE PASS, dispatcher done 19:07:19Z; tests 58/58, inspect 25/25, R1/R2 сохранены. Live readiness не подтверждена.
- 5037 source merge GO: 54f461b0787ccfb446c1748862b2ce630172ea6b, полный manifest из ~/waves PASS, DONE, EXIT=0 END=19:14:19Z. Целевые WEB651/439/681/685 прошли; PG/capacity/live gaps остаются, wallet policy gate blocking.
- 5035 wallet floor fix авторский GO, 15/15 disposable PG tests; полный manifest evidence PASS, DONE/EXIT0. Независимая 5038 M1 START=19:13:35Z, конечного EXIT/report пока нет.
- 5039 A1 recovery identity payload started 19:18:06Z. Доставлены kit5031 и реальные metadata l115r/l115q, RECOVERY.md. Actual DB/WAL/files/artifact bytes и operational exam ещё не собраны/не выполнены.
- 5040 A2 CPU instrument preparation started 19:17:53Z; принятому v30 предстоят новые candidate action/target inputs и разбор attestation mismatch без нагрузки и изменения общих env.
- Три текущих назначения: 5038/5039/5040. Telegram watcher PID89389 жив. Следующий session-only тик 20:33 Europe/Dublin. WEB686 повторно не запускался.
2026-09-25T19:36:44.528Z · coordinator[25.09 19:36Z координатор]
## Тик 2026-09-25 19:36Z
- 5038 независимый GO wallet floor принят: полный manifest evidence PASS, DONE, EXIT=0 END=19:28:39Z. PG15/15, оба admission caller RED/GREEN, exact settlement сохранён. Release-ready НЕТ; legacy fixture baseline gap остаётся.
- 5039 identity kit GO только metadata: полный manifest из ~/waves проверен sudo -n PASS после отказа чтения от ubuntu; права сдачи не менялись. Dispatcher done 19:30:21Z. Current l115r/rollback l115q metadata включены; actual artifacts/DB/WAL/files/trust и practical exam отсутствуют.
- 5040 preparation GO: полный manifest evidence PASS, dispatcher done 19:33:13Z. Отдельный v31 добавляет CPU SHA, action действительно regenerated. Env attestation остаётся all9; live/load NOT_RUN.
- 5041 M1 общий кандидат с принятым wallet delta и PG acceptance START=19:34:49Z, лог свежий 19:35:44Z, конечного EXIT пока нет.
- 5042 M4 независимая v31 acceptance started 19:35:56Z, один codex подтверждён. Два текущих назначения; завершённые волны не считаются работающими.
- Recovery: каталоги резервов найдены read-only в /var/lib/hetzbk/state и web686-{cloud,video,legacy}/state; проверены только размеры/числа строк, backup bytes ещё не доставлены. WEB686 не перезапускался.
- Новых сообщений владельца после 18:36:19Z нет. Telegram watcher PID89389 жив. Следующий одноразовый session-only тик 20:51 Europe/Dublin.
2026-09-26T12:12:23.681Z · coordinator[26.09 12:12Z координатор] 26.09 12:15Z координатор: сборка 5058 (NO-GO) сорвана дворником диска A2, он удалил рабочий каталог. Дворник исправлен: защита по метке KEEP. Интеграция перезапущена как 5061 (A2, старт 12:11:31Z) с тем же составом: e7e0cd9b + 618583ff и Linux-исправления из журнала 5058. Тикет остаётся в работе до GO сборки и деплоя на стенд.
2026-09-26T12:57:52.027Z · coordinator[26.09 12:57Z координатор] 5061 (сборка r2, 26.09 12:53Z) NO-GO. Интеграция и все Linux-исправления восстановлены, merge tree совпал с ожидаемым. Все тесты Linux прошли, checker5057 17/17. Прежний блокер (инициализация pinned Next send) устранён узким допуском по точному пути и хешу, отрицательные тесты прошли. Compile упал на новом месте: нативный модуль lightningcss linux-arm64 не загрузился. Повторить не дал порог диска 12 GiB. Координатор удалил 25 чистых worktree на A2, ветки сохранены, стало 16 GiB. Запущена 5062 (r3) с вершины 5061: узкий допуск для lightningcss, затем полная штатная цепочка. Тикет ждёт общий пакет стенда.
2026-09-26T13:38:37.273Z · coordinator[26.09 13:38Z координатор] 26.09 13:38Z: сборка интеграции 5062 NO-GO. Допуск lightningcss принят, тесты PASS. Compile упал на нативном модуле @tailwindcss/oxide. Запущена 5064: инвентарь всех нативных linux-arm64 модулей и узкие допуски разом, затем штатная цепочка. Этот тикет входит в пакет. После GO: деплой на стенд, checker5057, ступени 300/400/500, живые роли.
2026-09-26T20:36:10.423Z · coordinator[26.09 20:36Z координатор] Координатор, пост-QA 5073 на стенде 5069 (26.09 ~21:40 Дублин). Отчёт A2 /home/ubuntu/waves/5073POSTQASIXTICKETSSTAND-REPORT.md. FAIL: gate fail-closed есть (VendorCallRejectedError до вендора), но кошелёк сервиса уже -7.64 USD, а порог тревоги -800 USD — малый минус не сигналится. Остаётся in_progress.
2026-09-26T21:35:56.543Z · coordinator[26.09 21:35Z координатор] Волна 5077 (Astra), 26.09 21:32Z, VERDICT=NO-GO (диагноз готов, фиксы подготовлены, НЕ применены), манифест 62/62 OK.
- Индексация стенда стоит из-за конфигурации: SPEND_CONTAINMENT_MODE=enforce, а у worker нет ~20 обязательных входов (caps, attestation, egress proxy, reconcile, alert). Guard fail-closed отработал правильно.
- Старый source в readiness: устаревшие NC_RELEASE_ID/RELEASE_SOURCE_COMMIT в app-a..d.env и worker.env. Скрипт fix-stand.sh (overlay, откат rollback-stand.sh) подготовлен.
- Патчи на 5069: WEB-677 service wallet floor=0 + нулевые receipts при долге; WEB-651 отказ 413 document_over_ceiling до создания Source для TXT/MD; WEB-676/681 timeout записи документа 5s→15s (claim+upsert атомарны); egress proof интервал 61s. Тесты 179/179 → 188/188, tsc PASS, новых lint нет.
- Checker 5057: 59.999 с — порядок setInterval до startup proof; patch 0006 (stdin для jq, CLD_EXITED numeric); на живой сессии PASS span 1523 с.
- Оговорки: денежный патч WEB-677 требует живой проверки конкурентности на изолированном Postgres; критерий WEB-651 Astra искала не на этой доске — сверить; прогресс индексации (heartbeat замер 21:01Z) не исправлен.
Следующее: readiness-fix + checker → 5074-r2 → ступени; патчи → сборка + пост-QA.
2026-09-27T08:26:45.102Z · coordinator[27.09 08:26Z координатор] Пост-QA 5094 на стенде r12: PASS. Сервисный кошелёк 24.999449 → 24.995526 USD, в минус не уходит; ворота закрыты до vendor dispatch; порог алерта 0 (SERVICE_WALLET_ALERT_THRESHOLD_MICROS=0 из env воркера, heartbeat публикует), текущий low-alert=false. Живой недостаток средств не проверялся (без реальных денег). Статус → done.
Воркер
не привязан — привязать:
curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \
-d '{"issueId":"WEB-677","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-09-27T08:26:53.546Z