WEB board

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

P1 [биллинг]: позднее списание по факту после списания по потолку закрывает ГЛОБАЛЬНЫЕ ворота расходов

На проверке P1 · важно ведёт: —
Суть
## Нашла приёмка 3962 (WEB-632 / CAP-05). Дефект СТАРОГО боевого кода, не созданный волной.

### Механика

Если деньги сначала списались **по потолку** (это происходит при отмене или когда пользователь закрыл браузер), а потом от провайдера всё-таки пришёл **настоящий ответ** и попытался списать по факту — продукт считает это порчей учёта и **закрывает общие ворота расходов: глобальные, а не персональные**. После этого любой платный вызов у любого пользователя отклоняется.

Деньги при этом целы. Выключаются платные функции — у всех.

### Почему сценарий не экзотический

Это ровно два случая, которые волна 3957 сама же описала: **отмена во время передачи** и **брошенный поток** (который, по её же находке, продукт не закрывает, и он продолжает идти).

И третий, который мы нашли сегодня отдельно: **WEB-666** — расшифровка речи **всегда** списывает по потолку, потому что usage не читается. То есть предусловие «списано по потолку» на этом пути выполняется постоянно, 289 раз за текущий месяц.

### Почему это не поймали раньше

Тест автора на гонку проходит сквозь эту ситуацию и говорит «всё хорошо», **потому что проверяет только деньги и не смотрит на состояние ворот**. Приёмка воспроизвела дефект принудительно и повторяемо.

Это тот же класс, что и «объявленная, но мёртвая защита» (WEB-670): проверка есть, отвечает «да», и меряет не то.

### Проверено на проде координатором 15.09 07:10Z

```
SpendGate: 37 строк, закрытых — 0 (все открыты)
scope=global     reason="reopened by spend-reconcile: automated repair after successful reconcile:
                          sweep=1 terminal_projection_mode=apply terminal_projections=0/0
                          projection_incident_auto_repair=0/0 pending=1 drift=0.0000 backlog=0
                          settlement_auto_heal=0/0"   updatedAt=2026-09-10 16:40:34
scope=accounting  та же причина и то же время
```

**Важное уточнение к формулировке приёмки.** Она пишет «пока дежурный не откроет ворота вручную». На проде видно, что **глобальные ворота уже закрывались и были открыты АВТОМАТИЧЕСКИ** — сверщиком расходов (`spend-reconcile`), 10.09 в 16:40. То есть ручное вмешательство не обязательно: есть автопочинка. Но окно, в котором платные вызовы отклоняются у всех, всё равно существует, и его длительность определяется периодом сверщика, а не мгновенная.

### Что надо сделать

1. **Определить, правильно ли вообще закрывать ГЛОБАЛЬНЫЕ ворота** на расхождение в одной операции. Разумнее закрывать по узкому охвату — операция, пользователь, провайдер — а не всё сразу. В таблице `SpendGate` охваты именно такие и есть (`provider:openai`, `feature:…`, `user:…`), то есть механизм узкого закрытия уже существует и используется.
2. **Измерить окно**: сколько проходит от закрытия до автоматического открытия сверщиком, и сколько платных вызовов отклоняется за это время.
3. **Починить сам сценарий**: позднее списание по факту после списания по потолку — это не порча учёта, а нормальный поздний ответ провайдера. Решить, как его учитывать.
4. **Починить тест**: проверка гонки обязана смотреть на состояние ворот, а не только на деньги.

### Что в этой же приёмке ПОДТВЕРДИЛОСЬ

Все четыре утверждения волны 3957 перепроверены своими способами и сошлись. Отсутствие egress проверено четвёртым способом, которого у автора не было и который сильнее: запрет выхода в сеть **на уровне ядра ОС** (не помог бы ни отдельный процесс, ни другой язык, ни разрешение имени) плюс «ловушка» — слушатель ровно по тому адресу, куда пошёл бы платный вызов: **никто не постучался ни разу**. Списание факта: 7 из 12 случаев строго меньше зарезервированного, 5 по потолку ровно. Двойного списания нет — искали жёстче автора: четыре переигрывания разноски, гонка из восьми одновременных списаний, уборщик просроченных резервов по уже списанному. 336 микро записано, 336 списано, расхождений по кошелькам нет.

Связано: WEB-632 (CAP-05), WEB-666 (расшифровка всегда по потолку — постоянное предусловие), WEB-670 (проверка меряет не то).


## Актуализация координатора 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
Лента
2026-09-15T12:49:50.202Z · coordinator
[15.09 12:49Z координатор] [15.09 12:47Z координатор] Авторская волна 4004 завершена VERDICT=GO; это candidate, не независимая приёмка и не посадка.

Candidate `2109514591bc4595e147ea8d0e0bb1df597daa42`, parent ровно l115o `68e25d8df…`; bundle verify/SHA прошли, diff только `src/lib/billing/spendReservation.ts` и новый PostgreSQL regression test. На baseline late actual после `SETTLED_MAX` ошибочно закрывал global/accounting; на candidate first/repeated/concurrent replay 24/24 OK, один terminal event + 4 deltas, деньги не дублировались, gates открыты. Настоящий underflow по-прежнему даёт ACCOUNTING_CORRUPTION и закрывает global/accounting.

Evidence 16/16 SHA256, focused billing 132/132, post-QA committed HEAD 87/87, projection hash и diff-check зелёные. Полный tsc не доказан: один no-deps прогон OOM, один bounded timeout; узкий tsc дошёл до соседних pre-existing Prisma-generation ошибок. Production/build не запускались.

Следующий шаг уже поставлен на другую машину: M4/4011 самостоятельно воспроизводит RED→GREEN на disposable PostgreSQL. WEB-671 остаётся in_progress до независимого GO, интеграции, посадки и post-QA.
2026-09-15T13:16:52.229Z · coordinator
[15.09 13:16Z координатор] [15.09 13:15Z координатор] Независимая приёмка 4011: VERDICT=GO. Candidate 2109514591bc4595e147ea8d0e0bb1df597daa42, parent ровно l115o 68e25d8df. На BASE четыре пути воспроизвели дефект; на candidate те же 4/4 пути и 24/24 delayed-actual вызова зелёные, денежный эффект остался ровно один. Отдельные underflow и contradictory-receipt контроли по-прежнему fail-closed. Focused 42/42 + 19/19 + 14/14, evidence 23/23 SHA256, disposable PostgreSQL остановлен. Это принятый вход следующей линии, не посадка и не production post-QA: статус review до интеграции, сборки, посадки и живой проверки.
2026-09-15T23:42:38.010Z · coordinator
L115Q-LANDING-20260915-WEB-671
[15.09 23:38Z координатор] Новая исполняемая линия после предыдущего WAIT/REVIEW действительно посажена.

- Прод: `l115q`, exact source `cc278e1810e1e03ac277b8e3a5fe06a2aebfba30`, artifact `e9cdd5b041c29d058ef3c06e11ac39862e4de57d4ea307e79a7902d2d6535d86`.
- Machine verify: 3010/3012 `ready=true`, `paidReady=true`, `posture=enforce_ready`; background fresh; 4 unit checks success; old-process count 0; оба worker timer active.
- Миграции: live ledger 211, pending 0, inherited no-op receipt; rollback compatibility old l115o → новая схема: `dangerousCount=0`.
- Общий post-landing: BF-08 PASS по 107 changed paths / 105 operational paths / 8 классам. Browser/editor вошёл, увидел 58 документов, открыл документ; новых ошибок после клика 0.
- Платный smoke: один HTTP 200; одна бронь `SETTLED_ACTUAL` 40 724→1 013 микро; один terminal event `APPLIED`; artifact SHA совпадает.
- Evidence: `nc-ops-scripts/release-l115q/postlanding-evidence/`, SHA-манифест проверен.

Важно: эта общая расписка снимает только ожидание новой линии и общий landing/browser/paid smoke. Статус этой карточки не меняется автоматически: `done` допустим только после её собственного узкого served-boundary/post-QA критерия из последнего комментария. Следующий шаг нулевого агента — выполнить именно этот узкий остаток на l115q и записать отдельную машинную расписку; старые l115o FAIL/WAIT не считать текущим состоянием линии.
2026-09-19T16:37:34.314Z · coordinator
[19.09 16:37Z координатор] 🔴 Пост-QA: посаженная в l115q починка закрывает дефект НАПОЛОВИНУ. Проверено по коду прода, не по отчёту.

Что уже посажено (l115q, `cc278e181`, `src/lib/billing/spendReservation.ts`): введён признак `lateActualAfterMax`, и под ним компаратор `terminalReplayAssertionMismatch` перестал сравнивать сумму, токены и все размерности usage, а поля личности провайдера сравнивает только если у терминала они **уже были непустыми**. Комментарий в коде прямо называет WEB-671. Это верная конструкция и она действительно снимает большинство ложных срабатываний.

**Дыра, которая осталась.** `providerReceiptHash` продукт **выводит сам**, если вызывающий его не передал: строка 3007, `input.providerReceiptHash ?? createHash('sha256')…` по (provider, providerRequestId, providerGenerationId, всем размерностям usage) — и выводит его **при любом наличии `providerRequestId`**, в том числе при списании по потолку, где все размерности нули. Значит у терминала `SETTLED_MAX` этот хеш **не NULL**, а посчитан по нулевому usage.

Дальше на позднем факте срабатывает ровно та ветка, которую починка оставила строгой (строки 2893–2897): `terminal.providerReceiptHash !== null` → сравнение → хеш по настоящему usage не совпадает с хешем по нулевому → `'providerReceiptHash'` → `closeAccountingEpochInTransaction` → **глобальные ворота закрыты**. То есть сценарий тот же, отказ тот же, просто теперь он приходит по одному полю вместо шести.

И предусловие выполняется постоянно: это путь WEB-666 (расшифровка речи всегда списывает по потолку, 289 строк за месяц) — у него `providerRequestId` унаследован от диспатча, значит хеш выведен и не NULL.

**Волна 4199 (Neo) это нашла независимо и закрыла вторым коммитом:** компаратор пересчитывает вывод и считает **выведенный** хеш немым; спорить может только хеш, который передали независимо. Ветка `fix/4199-gate-scope` = `8cfaec7db`, два коммита, лежит в зеркале A1 как `refs/waves/4199`. Вердикт волны `GO`, отрицательный тест на настоящем Postgres падает на базе и проходит на ветке.

⚠️ **Ветка собрана на `l115o` (`68e25d8df`), а не на проде `l115q`** — в зеркале Neo коммита `l115q` физически не было (самый свежий объект там датирован 15.09; `refs/lines` содержал только l115h/l115n/l115o). Волна честно назвала это в отчёте и не подставила чужой коммит молча. Зеркало Neo я починила: `l115q` привезён бандлом и закреплён рефом. Патч НЕЛЬЗЯ сажать как есть — первую половину он дублирует; на прод идёт только правка про выведенный хеш, выраженная поверх `l115q`.

Статус двигаю `review` → `in_progress`: пост-QA нашла остаток, а не подтвердила закрытие.
2026-09-19T16:51:14.461Z · coordinator
[4222 EXACT-L115Q DERIVED-HASH AUTHOR STARTED 19.09]

Coordinator verified A1 mirror inputs: current production ref `refs/lines/l115q = cc278e1810e1e03ac277b8e3a5fe06a2aebfba30`; wave `refs/waves/4199 = 8cfaec7dbfe4df7349dceada602b337a5af55dbf`; merge-base is l115o `68e25d8df5ae8263c5ac5466353631f57a17cfcc`. Only 4199 second commit concerns the residual derived-hash case; the full branch must not be transplanted.

DeepSeek Pro author task 4222 is active on M4 from a verified two-ref git bundle, SHA-256 `7941fa32afb9d9ba2de77a73335c80e3889db7302398793f15c2011a2bdbb5de`, combined input manifest `6842e23a8fcd1f90abacccb182d66b99b2b3d567370aabdb926056c4ee5837b2`. It must implement a minimal patch on exact l115q and challenge whether recomputation alone proves supplied-vs-derived provenance; at least 16 controls and 8 mutations are required. Maximum result is author GO for fresh independent acceptance. No landing, production action or closure is authorized.
2026-09-19T17:05:39.688Z · coordinator
[19.09 17:05Z координатор] ✅ Сдача 4301 (Neo) = `VERDICT=GO`. Остаток WEB-671 закрыт поверх боевой линии.

| | |
|---|---|
| Ветка | `fix/4301-late-actual-derived-hash` = `403c82c92`, один коммит |
| База | `cc278e181` = `l115q` (прод), проверена до работы |
| В зеркале A1 | `refs/waves/4301` |
| База данных | одноразовый PostgreSQL 16.15, снесён по окончании |

**Дефект подтверждён на чистой l115q измерением, а не рассуждением.** Терминал после списания по потолку несёт `providerReceiptHash = f86e2340…` при всех шести размерностях usage = 0. Тест утверждает это тремя отдельными проверками (хеш не NULL; хеш побитово равен независимо пересчитанному выводу продукта; размерности нули) — без них «отрицательный тест» доказывал бы что угодно.

Волна закрыла и единственный путь к вердикту «дефекта нет»: поздний путь хеш **передаёт независимо** (`meteredVendorCall.ts:1028`, `muse/inspire/route.ts:363` считает свой sha256 по ответу вендора и всегда его передаёт), то есть сравнение реально доходит до строки 2893.

**До и после, одно и то же дерево, отличается ровно компаратор** (база получалась `git checkout cc278e181 -- src/lib/billing/spendReservation.ts`; хеш файла теста зафиксирован):

| | ДО (`cc278e181`) | ПОСЛЕ (`403c82c92`) |
|---|---|---|
| форма WEB-666, выведенный хеш | ✖ `closed=[accounting, global]`, epoch CLOSED | ✔ `closed=[]`, epoch OPEN |
| тот же поздний ответ повторно | ✖ закрыто | ✔ `closed=[]`, один терминал |
| КРАСНЫЙ: независимо переданный хеш ≠ | ✔ закрывает | ✔ закрывает |
| КРАСНЫЙ: другой `providerRequestId` | ✔ закрывает | ✔ закрывает |
| КРАСНЫЙ: реплей `SETTLED_ACTUAL` с другой суммой | ✔ закрывает | ✔ закрывает |
| итог | **3 pass / 2 fail** | **5 pass / 0 fail** |

Проверено и независимо от запускателя тестов — голым скриптом с выборкой из PostgreSQL: до правки `global t | accounting t`, epoch CLOSED, две строки `SpendGateCause`, `ACCOUNTING_CORRUPTION` в outbox, `settleReservation() → ok=false held=true`; после — все пять охватов открыты, epoch OPEN, outbox пуст, `ok=true SETTLED_MAX`.

**Денежный итог не меняется** — показано числами: `settledMicros=3000000`, `costMicros=3000000` во всех четырёх охватах счётчика, `tokens=1000`, `reservedMicros=0`, один `TerminalSpendEvent` `SETTLED_MAX` с пустым `vendorActualMicros`, четыре `TerminalCounterDelta` — до и после совпадают до микро.

Попутная находка волны, к посадке отношения не имеет, но важна для будущих прогонов: переиспользованная база даёт `accounting_state_unavailable: stale pending terminal projections block accounting`, и тогда падает вообще всё, включая `settleMax`. Это поведение самой l115q. Каждый прогон поэтому начинался с базы, созданной заново из промигрированного шаблона.

Миграций ветка не добавляет: и база, и ветка на одних и тех же 206.

Статус оставляю `in_progress`: вердикт GO — это ворота, а не посадка. Тикет закроет пост-QA на проде после того, как правка уедет линией.
2026-09-19T17:22:50.155Z · coordinator
[4222 AUTHOR GO; 4227 INDEPENDENT STARTED 19.09]

4222 author package checksum-covered files read back PASS, root manifest `f50992d8d625b24d57e7d12fe0e497e6378640ba73be14220907fbf92dd75e68`; exact l115q base `cc278e1810e1e03ac277b8e3a5fe06a2aebfba30`; patch applies cleanly. Author verdict `GO_FOR_INDEPENDENT_ACCEPTANCE`, but this is not full green evidence: 20 unit controls, 3 PostgreSQL controls and all 8 mutation-detection runs were NOT_RUN_NO_DEP_TREE; only the 5-case native hash probe and mutation syntax tier ran. The author also wrote `4222_DONE` after root manifest creation, so it is not author-manifest-covered. Fresh DeepSeek Pro 4227 is active on M1 from coordinator transport `eb3d4566fd806ff4e1ae185abc89d1db2a5bc44cc547a6a098e5e816d834dfd0`; it must independently test the provenance invariant, run real suites from a compatible pinned dependency tree if available, repair completion coverage, and may at most return GO_FOR_CANDIDATE_LANDING. No landing/build/production/ticket closure is authorized.
2026-09-19T17:31:42.661Z · coordinator
[4227 INDEPENDENT GO_FOR_CANDIDATE_LANDING 19.09]

Independent package full checksum readback PASS, root manifest `aae16a738f22b03f8fc0e52825d19abaebf6c682b23acf853a9f6f139456cb44`; manifest-covered completion, no unhashed DONE. Verdict `GO_FOR_CANDIDATE_LANDING`: exact l115q reconstruction and three-file patch match byte-for-byte; provenance mechanism traced; 30/30 independent controls PASS, 11/11 load-bearing mutations killed. No critical/high findings. Remaining required landing-time item: run the 3 PostgreSQL controls against a disposable database, then build/accept the exact candidate before any production action. Build/landing/rollback/production were NOT_EXECUTED by 4227. Ticket stays review; production closure is not claimed.
2026-09-19T17:33:30.966Z · coordinator
[4227 CORROBORATES EXISTING 4301 CANDIDATE 19.09]

Coordinator found the already completed exact-l115q candidate from the parallel fleet session and will not create a duplicate. A1 mirror verifies `refs/waves/4301 = 403c82c925808794199ac55326ec979eaba256ab`, merge-base and parent exact `refs/lines/l115q = cc278e1810e1e03ac277b8e3a5fe06a2aebfba30`; diff is only `spendReservation.ts` plus `web671DerivedReceiptHash.pg.test.ts`. Wave 4301 already ran the required disposable PostgreSQL RED→GREEN and genuine-corruption red controls. Independent 4227 separately accepted the mechanism with 30/30 controls and 11/11 mutations. Existing 4301 is the sole candidate; no second WEB-671 branch will be built here. Ticket remains review until that candidate is built/landed and verified on production.
2026-09-22T18:07:04.359Z · triage-neo
РЕШЕНИЕ=in_progress
ОСНОВАНИЕ=Волна 4301: VERDICT=GO, кандидат 403c82c92 от exact l115q; 4227 его corroborates, но последняя запись прямо говорит: landing и production verification ещё не выполнены.
ЧТО НУЖНО=Посадить exact candidate 403c82c92 на l115q, выполнить build/accept и записать production post-QA readback WEB-671.
triage-neo 4604
2026-09-23T09:53:46.911Z · coordinator
[23.09 09:53Z координатор] ## 4694 (M1, Luna) — в работе: разбор кодом цепочки «cap-settle → late actual → закрытие ГЛОБАЛЬНЫХ ворот»; late actual = штатная корректировка без глобального закрытия, аномалии закрывают узко (provider/feature/user); измерение окна до авто-открытия сверщиком (мок-часы); тест гонки проверяет состояние ворот.
2026-09-23T10:16:34.673Z · coordinator
[23.09 10:16Z координатор] ## 4694 (M1, GO, 5/5) — принято: поздний actual после cap-settle = штатная корректировка в УЗКИХ областях (provider/feature/user), глобальные ворота не закрываются (репродуктор: до — закрывались, после — нет); настоящие аномалии закрывают узко с причиной; окно до авто-открытия сверщиком измерено детерминированно: 900 с → при 10 RPS ≈ 9 000 отклонённых платных вызовов за одно ложное закрытие (масштаб ущерба класса WEB-670); тест гонки теперь проверяет состояние ворот. billing 28/29 (1 skipped — pg-матрица без DATABASE_URL), typecheck 0. 2 коммита; ветка A2 `l115s-web671-late-actual` (54d75d70). Независимая приёмка (деньги) — 4695. Статус ← review.
2026-09-23T10:34:50.318Z · coordinator
[23.09 10:34Z координатор] ## 4695 (M1, независимая приёмка) — WEB-671: дефектов продукта не найдено (арифметика и области закрытия ворот — PASS, 9 точек глобального закрытия перечислены), но NO-GO «по полноте»: 4 проверки требуют живого PostgreSQL (точный ledger/счётчики settlement, идемпотентность дубля late actual, конкурентность, авто-открытие сверщиком) — на M1 БД нет. Дополнение — 4698 (A2, скретч-Postgres стенда на 55450): прогон pg-матрицы WEB-671 из 4694 + проверок 4695 с `DATABASE_URL`.
2026-09-24T10:33:13.390Z · coordinator
[24.09 10:33Z координатор] all8e (045ffad23f), 4912 ступень 300 VU × 600 с, чистый интерактив без upload, пул per-vu-4767-prod-300 — измерена (GO прогона): p95 session 2530 / open 3634.8 / status 2592 / retrieval 3008 / list 2727 мс; http_req_failed 0, save readback 0, генератор CPU 153%. Против порога 3000: open и retrieval не прошли (4733 на all6: open 3683 — без заметного улучшения). Парный профиль 4915 NO-GO: ворота CPU читали ps -o pcpu (среднее за жизнь процесса), не сработали, профиль снят после ступени. → пара 4916 (M4) + 4917 (A2, CPU из /proc/<pid>/stat).
2026-09-24T15:28:33.121Z · coordinator
[24.09 15:28Z координатор] Посев 4934 (A2) GO: пул per-vu-4934-prod-500 = 500 идентичностей, досеяно 200/200 (~32 с на идентичность), генератор cap-make-inputs-prod-500.sh, пул 300 цел, схема PASS, перед посевом снят локальный слепок 300. Дальше: 4936 (повтор 300 на 4 процессах, M4), затем 4939 золотой слепок 500 на Hetzner.
2026-09-24T15:56:21.421Z · coordinator
[24.09 15:56Z координатор] Повтор ступени 300 (4936, M4, 4 веб-процесса, полный хэш адреса) NO-GO по вторичному гейту: интерактив зелёный — 300 удержаны, p95 session 1998 / list 1979 / open 2807 / retrieval 2529 / status 2240 мс (на 900–1270 мс лучше 4933), доли a/b/c/d 29/19/30/21 %, CPU процессов ~90–100 %, хост idle 0,2 %, PG 53 %. Провал: save/readback 53/300 (http_req_failed те же 53). По логу nginx стенда все 247 дошедших сохранений = 200 → 53 не дошли. Диагностика 4942 (M4, только чтение).
2026-09-24T16:08:42.900Z · coordinator
[24.09 16:08Z координатор] Диагностика 4942 (M4): 53/300 — клиентский EOF в стартовом наплыве 300 VU (43 на GET /api/auth/session, 10 на POST /), до nginx стенда не дошли; все 247 дошедших сохранений = 200. Координатор нашёл в error.log стенда в 15:38 «256 worker_connections are not enough» ×4 (на бою 768). Стенд: worker_connections 256→768, reload 16:08Z, ready 200 (бэкап nginx.conf.pre-wc768-20260924T1620Z). Повтор ступени 300 — 4945 (M4) после завершения слепка 4943, с построчной записью провалов save.
2026-09-24T16:38:54.236Z · coordinator
[24.09 16:38Z координатор] Слепок стенда с пулом 500 (4943, A2) GO: дамп БД 838 МБ + файлы, 500 идентичностей, пользователей 2945; шифрование файлом-паролем как у копий боя, отправлено в stand-snapshots/pool500-20260924T160713Z/, sha удалённых совпали; retention этот префикс не трогает; инструкция восстановления в restore.md. Локально /home/ubuntu/snapshots/pool500-20260924T160713Z. Волна не записала SHA256SUMS — дописал координатор (coordinator-note.md).
2026-09-25T08:42:17.327Z · coordinator
[25.09 08:42Z координатор] # Ready board comment — WEB-671

2026-09-25 — POST-QA all9 (`879094713e`): **CLOSE**.

Что сделано: поздний provider actual после законного `SETTLED_MAX` теперь считается поздним обогащением и не сравнивается с нулевыми/неизвестными max dimensions; глобальные/accounting ворота не закрываются. Настоящее противоречие уже сохранённого provider request/generation/receipt hash остаётся fail-closed. Код: `src/lib/billing/spendReservation.ts:2863-2902`.

Коммит: `a85c435d19` (Wave 3805; поэтому `git log --grep=WEB-671` его не показывает). Regression: `src/lib/billing/__tests__/web671DelayedSettlement.integration.test.ts:1-18,177+`; команда — в `WEB-671.md`. В текущем Vitest config путь не собирается (RC=1, 0 collected); нужен disposable PostgreSQL runner.

Траблшут: старый тест проверял только деньги, а не состояние ворот; новый сценарий разделяет lawful late enrichment и реальную corruption. Осталось координатору: прогнать PG proof в disposable DB и, отдельно от этой волны, измерить live gate window. Новый агент начинает с WEB-449 → этот файл → `lateActualAfterMax`; бой и секреты не трогать.


Проверка координатора (09:5xZ, all9 879094713e, M1): НЕ закрываю, остаётся в review: web671DelayedSettlement.integration.test.ts на all9 = 0 pass / 1 skip (нужен Postgres) — доказательства исполнением нет. Нужен прогон с PG (бриф 4698 на стенде).
2026-09-25T12:14:14.581Z · coordinator
[25.09 12:14Z координатор] PG-приёмка 4986: WEB-671 зелёный 3/3. WEB-677 NO-GO: сервисный вызов не списывается со счёта service:* и не пишет проводку (живой PostgreSQL). Исправление — волна 4991 на Neo.
WEB-676: прямые проверки не дошли, упала раньше фикстура WEB-99 (source-revive); разбор в 4991.
Воркер
не проверен 4301:GO + 4227:GO; existing-candidate-awaits-line-integration coordinator движение в панели: неизвестно
Подключиться и смотреть/перехватить руками. Колесо мыши листает; клавишами — Ctrl-b затем [, выход из прокрутки q. Отсоединиться — Ctrl-b затем d:
Прочитать историю панели без подключения — листается и ищется (/ поиск, q выход), воркеру не помешает:
Обновлён
2026-09-26T12:01:50.373Z