35 KiB
Путь денег — от гранта до settle (топикальный вход, строка 167)
Статус: топикальный ВХОД, НЕ источник истины. Док собирает денежную тему, размазанную по D-нотам, реестру дефектов платформы, глоссарию и бэклогу, в один маршрут чтения. При конфликте с чем угодно побеждает
docs/architecture/05-decisions-log.md(правило чтения — диета D39.125: живой файл + слайсы). Каждое утверждение здесь снабжено указателем на первичный носитель; формулы — дословно оттуда. Словарь терминов (холд · прирост · аргумент потолка · baseline · settle · leftover-reserved · SpendBound) —docs/glossary.md§«Деньги платформы» (docs/glossary.md:55=**Деньги платформы:**).⚠ Форма указателей — норма этого дока (31.08, пере-проверены ВСЕ указатели: 34 уехали, 1 мёртв, 16 верны). Стабильна не ЗОНА, а ЧИСТЫЙ ФАЙЛ. Номер строки ставится только туда, где
git status <цель>показывает файл чистым; файл с незакоммиченной правкой — чей угодно, включаяdocs/— получает греп-указатель без номера. Ось именно такая — ратифицировано D39.179 п.4, который уточняет D39.177 §2в и прямо объявляет зонную ось НЕВЕРНОЙ (там же: «Носитель нормы — шапка 15-money-path.md»), и зонная ось её НЕ заменяет:docs/architecture/14-api-contract/openapi.yamlЛЕЖАЛ в «своей» зоне и при этом ДВИГАЛСЯ паком контракта 0.9.0 (заленджен 31.08,0a680a3, D39.180). Токен-форма —`путь:N`=`ожидаемая подстрока`; её гейтdocs/scripts/counts.py --lintсверяет ПО СОДЕРЖИМОМУ и краснеет, когда цель уезжает. ⚠ Что гейт берёт с якоря БЕЗ токена: существование файла и что номер не больше длины файла; у голого имени журнала решений — ещё и структуру (владелец строки обязан совпасть с названной рядом нотой). НЕ проверяется только СОДЕРЖИМОЕ — вот почему 34 якоря уехали молча. Голое имя без «/» не судится вовсе. ⚠ Греп-форма не проверяется гейтом никак (регексп якоря требует:номер) — осознанный размен: переживает чужой WIP, но молчит. ⚠ Токен НЕ должен содержать бэктик: регексп берёт токен как «всё до следующего бэктика» и обрезает хвост, а необрезанная часть не проверяется вовсе.
1. Канон одним абзацем
Деньги видимы с первого вызова: телеметрия, потолки, явное согласие на пере-оплату (CLAUDE.md, цель 5). Леджер без потолка запрещён — Р7: книга обязана нести хотя бы один из book_usd/day_usd (backend/internal/config/book.go:321=a ledger with no ceiling is forbidden, текст валидатора: «a ledger with no ceiling is forbidden, Р7»). Суммы на пользовательский экран НЕ выходят — запрет D39.84, подтверждён D39.100/К-8 (дословно: «страница лимитов/использования в настройках (СТАТУС, не суммы — запрет денег на экране D39.84 в силе и НЕ superseded)» — docs/architecture/05-decisions-log.md, греп ^## D39.100 → пункт К-8, дословная подстрока СТАТУС, не суммы — запрет денег на экране; ⚠ адресуем НОМЕРОМ: прежний голый :232 убила эррата 02.09 в шапке, ровно как предсказывает строка бэклога 219) и держится в контракте (docs/architecture/14-api-contract/openapi.yaml, греп State of the credit balance. No window — ⚠ номер не ставим: контракт переверстывается минорами, греп-форма дешевле поддержки (прежнее обоснование «файл двигает пак 0.9.0» протухло — пак заленджен 31.08)). Защита от перерасхода двойная и не зависит от событий: холд платформы делает кредит недоступным следующему прогону, а движок сам останавливается на потолке — «an overspend is impossible even while the platform is blind. The event stream is freshness only» (док-коммент Hold — platform/internal/pgstore/credits.go, греп an overspend is impossible even).
2. Деньги ДВИЖКА (зона backend/)
-
Леджер SQLite. Таблица
spend, две фигуры:committed_usd(потрачено, с сырым ответом провайдера) иreserved_usd(зарезервировано под летящий вызов).Reserveперед каждым платным вызовом сверяетSUM(committed_usd + reserved_usd)книги и дня с потолками (backend/internal/store/ledger.go:44,58,63=func (s *Store) Reserve(; Р7 — комментbackend/internal/store/ledger.go:12=per-day (Р7); checked against);SettleWithCheckpointодной транзакцией конвертирует резервацию в committed и персистит ответ (backend/internal/store/ledger.go:178=func (s *Store) SettleWithCheckpoint(). ⚠ У ДВИЖКОВОГОstore.StoreметодаSettleнет — он называетсяSettleWithCheckpoint(словарь кода:backend/internal/store/ledger.go:11=Reserve/Settle/ReleaseReservation semantics). ⚠ Не спутать с ПЛАТФОРМЕННЫМcredits.Settle(§3 п.8) — это другойStore. Суммарно по книге —SpentUSD(backend/internal/store/ledger.go:381=SpentUSD reports (committed, reserved)). -
Гейт потолков — ПЕР-ВЫЗОВНЫЙ (
Reserveна каждый свежий attempt). На границе юнита сидел РЕПЭЙР-суб-бюджет — ужесточён до пер-вызовного с ценой вызова (строка 135 закрыта D39.131); эскалационный кап хоп НЕ прицениваает — перелёт ≤1 хопа, задокументирован и запинен (диспозиция D39.131 п.2д, реопен — живой инцидент). ⚠ ТРЕТЬЕ семейство, которого перечень не знал (доп. ревизией 02.09): банк-роли несут СОБСТВЕННЫЕ КНИГО-ШИРОКИЕ бюджеты —gates.terminology.budget_usdиgates.terminology.classify_budget_usd. Именно оно резало ОПЛАЧЕННУЮ работу на холодном прогоне 31.08 (D39.182 §4: инцидент был на классификаторе). С 31.08 (D39.182) план прохода режется ценой партии ДО первого вызова, а не обрывается посередине; усечение ВИДНО в отчёте — поляBatchesDroppedиClassifyBatchesDropped(backend/internal/pipeline/terminologist.go, грепBatchesDropped). ⚠⚠ И сами цифры этих суб-бюджетов в книжных конфигах КАЛИБРОВАНЫ ПОД ИЮЛЬСКИЕ ЦЕНЫ (тот же множитель ×4.47, D39.179 п.1): на холодном прогоне 31.08classify_budget_usd0.02 оборвал классификатор дважды, а поднятый до 0.08escalation.budget_usdбыл пробит фактом до 0.103305. То есть суб-бюджеты режут ОПЛАЧЕННУЮ работу не по замыслу, а по протухшей калибровке. -
leftover-reserved зануляется write-open.
store.Open(путь записи, каждыйtranslate) выполняетrecoverReservations(backend/internal/store/store.go:110=s.recoverReservations(ctx); сама функция —backend/internal/store/store.go:278-279=UPDATE spend SET reserved_usd = 0) — файл владеется одним процессом, значит любой reserved на открытии принадлежит несеттлённому прогону.OpenReadOnlyэтого прохода намеренно НЕ делает (backend/internal/store/store.go:124=does not run that pass) ⇒ reserved, увиденный read-onlystatusВ МОМЕНТ СПАВНА, — остаток мёртвого процесса (несущий факт формулы PD-158, см. §3). ⚠ Но НЕ «всегда»:OpenReadOnlyпостроен ровно затем, чтобыstatusработал ВО ВРЕМЯ живого прогона (backend/internal/store/store.go:122=allows concurrent readers while a writer is live), и конкурентныйstatusпокажет ЖИВУЮ резервацию междуReserveи settle. Узко формулирует и сам код: «after a run crashes, reserved_usd stays non-zero until the next WRITE command» (backend/internal/store/store.go:130=after a run crashes, reserved_usd stays non-zero), и платформа — «at spawn there is no other writer … so anything reserved is by construction a leftover, never a live promise» (platform/internal/runs/spawn.go, грепnever a live promise). -
--max-units— ОБЪЁМНЫЙ потолок прогона, ортогональный денежному (D39.165 §1б, принят D39.170). Ограничивает не деньги, а РАБОТУ: не больше N выходных ЮНИТОВ (гранулярностьunits_totalманифеста — та же, в которой платформа продаёт главы) будет ОПЛАЧЕНО этим прогоном; юниты, отданные за $0 (резюм, ре-пин), ретраи и эскалации внутри юнита потолок не тратят. Принимает толькоtranslate. Остановка по объёму — ЗАВЕРШЕНИЕ (exit 0), не пауза: словарь кодов выхода не расширялся и нового значенияFinished.Outcomeтоже нет — ⚠ но с 31.08 признак едет ЧИСЛАМИ в кадреfinishedшва, а не только прозой (D39.181 п.2, закон раскрытия: прозаическая строка отчёта до потребителя потока не доезжала): носитель —Finished.Volume, леджер доставки. Различение при этом живёт и в отчёте прогона, и в логе; отчёт разводит ДОСТАВКУ и ПЕРЕ-ДЕЛКУ. Носитель —backend/internal/pipeline/volume.go:13=the VOLUME ceiling — the run's second stop; словарь флага дословно —backend/cmd/tmctl/invocation.go:143=Stopping on it is a COMPLETION (exit 0), not a pause. ⚠ Проводка в платформу ГЕЙЧЕНА (PD-422): единственный писатель признака движения банка — дверь правок, рост АВТО-банка от майнинга флага не ставит. -
--ceiling-usd— КНИЖНЫЙ потолок, не бюджет прогона. Дословно из флага: «the book USD ceiling in force for THIS RUN ONLY — it OVERRIDES book.yamlceilings.book_usdand is never written back. It caps the book's CUMULATIVE committed+reserved spend, not this run's increment…» (backend/cmd/tmctl/invocation.go:142=the book USD ceiling in force for THIS RUN ONLY; ⚠-комментbackend/cmd/tmctl/main.go:260=--ceiling-usd is NOT a per-run budget; многоточие закрывает обрыв цитаты — во флаге дальше стоит «, and must be > 0»). Ратификация — D39.122 п.2(в): пересчёт «пользовательский прирост → абсолют» — обязанность ПЛАТФОРМЫ, вторая денежная ось не заводится. День-потолок флаг НЕ перекрывает (PD-157). Проводка внутри:Ceilings.BookUSDвReserveи именование сработавшего потолка в ошибке —backend/internal/pipeline/stagerun.go:496=BookUSD: r.bookCeilingUSD()иbackend/internal/pipeline/stagerun.go:525=overrides the book's ceilings.book_usd(стоп =errReserveCeiling,backend/internal/pipeline/escalation.go:49=var errReserveCeiling). -
Потолки — wiring, не семантика:
Ceilingsнамеренно исключены изBriefHash(«Wiring fields (paths, ceilings, db) deliberately excluded»,backend/internal/config/book.go:334=Wiring fields (paths, ceilings, db) deliberately excluded; канон —backend/internal/config/book.go:350=canon := struct {) ⇒ смена ДЕНЕЖНОГО потолка не двигает ни снапшот, ни ре-билл (D39.110 п.2б). ⚠ Верно ровно про ДЕНЬГИ: потолок СЕГМЕНТАЦИИedit_ceiling_outв снапшот ВХОДИТ и меняет границы чанков (backend/internal/pipeline/snapshot.go:34=EditCeilingOut int). -
status --jsonотдаёт фигуры платформе:committed_usd,reserved_usd,book_ceiling_usd,ceiling_pct= 100·(committed+reserved)/book_ceiling (backend/internal/pipeline/status.go:290=book_ceiling_usd,omitempty; арифметикаceiling_pct—backend/internal/pipeline/status.go:788=100 * (committed + reserved)). Дневной фигуры в status нет (PD-157 —platform/docs/DEFECT_REGISTER.md, грепPD-157). -
Леджер = НИЖНЯЯ граница (строка 78 бэклога,
docs/PROGRESS.md:65=Леджер денег = НИЖНЯЯ граница): «2xx body decode failed (call IS billed)» — провайдер списал, попытка вrequest_logне попадает; живой замер D39.86 — 3 вызова из 14, неизвестность $0.015111 при леджере $0.114378; движок сеттлит оценку и печатаетestimated-cost rows: 3. Канал виден, фикс — money-паком (дизайн GENERALITY_PHASE2 §5.6). -
Согласие на пере-оплату — ДВИЖКОВЫЙ гейт. Прогон, который пере-покупает уже оплаченные юниты дороже порога, ОСТАНАВЛИВАЕТСЯ и требует явного согласия. Порог по умолчанию ратифицирован D20.2-Q2:
min($0.50, 5% × ProjectedBookUSD). Носитель —backend/internal/pipeline/rebill.go, грепrebillConsentThreshold; единственная ручка книги —rebill_consent_usd(валидаторbackend/internal/config/book.go, грепrebill_consent_usd; 0 = ратифицированный дефолт). ⚠ Порог считается БЕЗ контура банк-ролей (D39.182 §3), то есть срабатывает позже, чем подсказывает полная проекция.
3. Деньги ПЛАТФОРМЫ по шагам (зона platform/)
-
Грант.
Grant— строка леджераkind='grant', идемпотентная по(аккаунт, source, source_id):on conflict (user_id, source, source_id) do nothing(platform/internal/pgstore/credits.go, грепfunc (s *Store) Grant(; сама идемпотентность после пака sqlc уехала В ЗАПРОС —platform/internal/pgstore/queries/credits.sql, грепon conflict (user_id, source, source_id) do nothing). Фри-тир — тот же механизм в ТОЙ ЖЕ транзакции, что создание аккаунта (platform/internal/pgstore/identity.go, грепappendLedger(ctx, tx, userID, "grant"; ⚠ дефолтSignupGrantMicroUSD— НОЛЬ (platform/internal/config/config.go, грепSignupGrantMicroUSD:), а НЕ «5 × 1_000_000» — эта сумма ходила по докам и ложна: предложение «на бете дефолт в НОЛЬ» (D39.110 п.3) ИСПОЛНЕНО,PD-104в регистре стоитfixed(P7, дерево сессии)). -
Выбор потолка — шкала в ГЛАВАХ (D39.110: от 1 до максимума, ноль не выбираем; потолок принадлежит ПРОГОНУ, в
book.yamlне пишется). Максимум = Balance КАК ЕСТЬ (D39.115 п.2а; эррата в шапке D-лога —docs/architecture/05-decisions-log.md:4=Balance КАК ЕСТЬ):Hold— дебет в момент взятия, баланс уже не содержит открытых холдов, повторное вычитание вдвое укорачивает шкалу. Реализация:pricing.Model.Scale—affordable = balance / PerChapter, кламп по остатку глав, дефолт = верх шкалы (ратифицировано D39.123 п.2е; компромисс «весь баланс под одну книгу» принят осознанно) —platform/internal/pricing/pricing.go, грепfunc (m Model) Scale(. -
Ставка $0.03/глава — конфиг-константа платформы:
DefaultPerChapter = 30_000micro-USD (platform/internal/pricing/pricing.go, грепDefaultPerChapter), переопределяетсяPerChapterMicroUSD(platform/internal/config/config.go, грепPerChapterMicroUSD). ⚠⚠ ЧИСЛА НИЖЕ — ИЮЛЬСКИЕ ДЕНЬГИ И С 16.08 НЕ ДЕЙСТВУЮТ (испр. ревизией 02.09). D39.179 п.1 ратифицировал: DeepSeek пере-пинен под цены, вступившие 16.08 16:00 UTC, множитель к июльским деньгам ×4.47. ⇒ по действующему прайсу та же выборка даёт среднюю главу ≈$0.051–$0.085 и максимум ≈$0.168, то есть константа $0.03 не завышена, а ЗАНИЖЕНА, и знак вывода перевернулся. ⚠ Иллюстрация живыми деньгами (НЕ калибровка): холодный прогон 31.08 дал полную цепь главы $0.093 и $0.151 приprojected_book_usd = 1.1377277707— но это n=2 главы из десяти, прогон остановлен снапшот-гардом, промпт черновика был банкнотным вместо конвенционного, и сам отчёт запрещает такое употребление дословно (archive/reports/COLDRUN_V16_REPORT_2026-08-31.md, грепкалибровать ставку платформы). Провенанс ниже — ИСТОРИЯ (D39.165 §1, 28.08): средняя $0.0115–$0.0190, максимум одной главы $0.0375, «завышена в 1.6–2.6×» — ⚠ но НЕ покрывает максимум: источник (D39.165 §1) добавляет «и отдельные главы её уже пробивают» ($0.0375 против $0.03 = ×1.25), и «купить 10 глав» отдаёт движку $0.30, покупающий ~16–26 глав («денежная ручка с подписью „главы"»,PD-410). РЕШЕНО: цена — от ОБЪЁМА ИСХОДНИКА (носительchapters.units_total, пишется интейком за $0), настоящий стоп — объёмный потолок В ДВИЖКЕ (см. §2). ⛔ Константу по сегодняшним числам НЕ калибровать (D39.165 ⛔г) — гейт строка 202 бэклога (docs/PROGRESS.md:162=Живой перевод книги НАСКВОЗЬ через API платформы). Исторический провенанс: exp08 v2 $0.0219/глава → ревизия D30.4 +15–25% → округление ВВЕРХ (низкая ставка опаснее высокой — прогон встанет на потолке посреди книги;platform/internal/pricing/pricing.go, грепProvenance, so the number is auditable). Временная мера беты — честная оценка движковая (строка 166 бэклога,docs/PROGRESS.md:135=Движковая поверхность оценки). -
Холд прироста ДО спавна.
holdTxпишет отрицательную строку('hold', -amount)и тем же знаком двигает кэш баланса (platform/internal/pgstore/credits.go, грепfunc holdTx(— строку леджера пишетappendLedger(… "hold", -amount …), кэш баланса двигаетMoveBalanceвнутри неё); нехватка —ErrInsufficientCredit. Холд + прогон + попытка + очередь — одна транзакция (platform/internal/pgstore/runs.go, грепfunc (s *Store) StartRun(; рестарт — грепfunc (s *Store) RestartRun(; форма D39.123 п.2д). -
Аргумент движку:
bookCap = committed + прирост×ставка, БЕЗ reserved — PD-158, дословно из кода:return m.committed + increment(platform/internal/runs/spawn.go, грепreturn m.committed + increment). Обе фигуры читаются ОДНИМ вызовомstatus --jsonперед стартом (bookMeter—platform/internal/runs/spawn.go, грепfunc (s *Service) bookMeter(; отказы — грепAbsent is not zero); отсутствие любой из них = отказ спавна («absent is not zero», PD-40). Почему без reserved: write-open движка занулит leftover до первой резервации, значит цифра из read-only status к моменту сравнения уже мертва; ратифицированная ранее формула с reserved переплачивала запасом ровно на leftover сверх холда — исполнено обеими формулами против гейта (D39.123 п.2б, поправка к D39.122(в)). Аргумент ≠ холд: он больше холда на committed (docs/glossary.md:55=ЭТО НЕ ХОЛД). Фактически ушедшее значение хранится вrun_attempts.ceiling_arg_micro_usd(PD-144, миграция 00011); потолок уходит argv-шаблоном{{usd}}(шаблон —platform/internal/config/config.go, грепCeilingArg; подстановку делаетplatform/internal/runner/engine.go, греп{{usd}}; подстановку и рендер argv делаетplatform/internal/runner/engine.go, грепfunc (t CeilingTemplate) Args(;platform/internal/runs/runs.go, грепfunc (s *Service) ceilingFor(— однострочная делегация к нему;spawn.goпотолок только передаёт); строка 145 закрыта D39.122. -
Baseline и списание.
baseline = committedкниги на старте попытки (platform/internal/runs/spawn.go, грепbaseline, bookCap := m.committed); списание попытки = разница счётчика с baseline; счётчик ниже baseline = подменённая БД, сеттлится в ноль с WARN — сами цифры в лог не идут (D39.84;platform/internal/runs/reconcile.go, грепthe book's meter reads below). -
⚠ Терминальный вердикт ОПЕРАТОРА — путь холда мимо settle (добавлено 22.08, P8-FIX/D39.154). Прогон, чей движок не ответит уже никогда, закрывает человек:
tmplatformctl run abandon --run <id> --reason <текст> [--release-hold]. Команда ОТКАЗЫВАЕТ, если попытка ещё называет юнит или несёт базовую линию траты — над живым движком прогон не закрывают. Холд возвращается ЦЕЛИКОМ в обоих случаях (к abandon допускается только попытка, не дошедшая до движка, значит она ничего не потратила), а флаг решает лишь КОГДА — сразу или на ближайшем свипе. ⚠ С пака P11 (PD-385) ВЕТВЕЙ ДВЕ, и абзац выше — только ЖИВАЯ (испр. ревизией 02.09; образец — секция «Строка PHASE = settling» вplatform/deploy/README.md). У прогона, чья попытка уже КОНЧИЛАСЬ, команда идёт второй ветвью: отказ «юнит/базовая линия» к ней НЕ применяется, к abandon допускается попытка, которая ДОШЛА до движка и ПОТРАТИЛА, холд всё равно возвращается ЦЕЛИКОМ по каждой осиротевшей попытке, а флаг--release-holdтам ИГНОРИРУЕТСЯ; единственная защита — порогabandonAfterнеудач расчёта (отказErrSettlementNotStuck). ⚠ Ветвление идёт поruns.finished_at, а НЕ по наличию осиротевшей попытки — ратифицированная оговоркаPD-418. ⚠ И вторая ветвь НЕ лечит живую: прогон с намертво заблокированной расплатой уходит в ЖИВУЮ ветвь и закрыт отказом по юниту до сих пор —PD-424стоитopenименно на этой половине. -
Settle по фигуре движка.
reconcile.settle(platform/internal/runs/reconcile.go, грепfunc (s *Service) settle(— ⚠ номера строк в файлы живой зоны не ставим, пока её сессия работает) читает committed из status;credits.Settleодной транзакцией закрывает резервацию, возвращает холд и списывает spent; spent > холда — капится холдом с явной пометкой «capped at the hold; the engine reported …» (platform/internal/pgstore/credits.go, грепcapped at the hold; the engine reported), перерасход движка счётом не абсорбируется. -
SpendBound (PD-159). Отложенный settle читает пожизненный счётчик КНИГИ и без границы оплатил бы работу прогона-преемника (замер: $2.10 за прогон ценой $0.10, и преемник платил снова). Граница = наименьший baseline попыток той же книги, стартовавших ПОЗЖЕ:
committed = min(счётчик сейчас, SpendBound)(platform/internal/runs/reconcile.go, грепbound != nil;platform/internal/pgstore/runs.go, грепfunc (s *Store) SpendBound(). -
Открытое — эскроу/intent (строка 136 бэклога,
docs/PROGRESS.md:108=Write-ahead intent): write-ahead intent + состояниеuncertain-эскроу +closing; холд НЕ освобождается по выходу юнита (сигнал обгоняет денежные события); spend не постится без свидетельства провайдера; расход сверх холда — полной суммой, превышение явной строкой убытка. Стройка по research/25, «скоро». ⚠ «Строка 103» — ФАНТОМ, снят 31.08: такой строки в бэклоге нет (закрыта D39.131), а эмиттер шва ПОСТРОЕН с обеих сторон — платформа тейлитevents.jsonlи принимает кадрspend(platform/internal/ingest/events.go, грепTypeSpend Type). Денежной слепоты это НЕ снимает по построению: поток событий — только свежесть. Платформа между спавном и settle слепа — защита держится холдом и потолком движка (§1).
4. Фронт (зона frontend/)
Максимум шкалы — Balance КАК ЕСТЬ (D39.115 п.2а); Reserved — справочная величина, ReadAccount отдаёт обе раздельно (platform/internal/pgstore/credits.go, греп func (s *Store) ReadAccount(). Шкала — в ГЛАВАХ: CeilingBounds — «in CHAPTERS. The conversion to money lives on the platform and is not exposed here in any form» (docs/architecture/14-api-contract/openapi.yaml, греп The conversion to money lives on the platform); клиенту запрещено клампить повторно; max_chapters: 0 = состояние «исчерпано» вместо шкалы. Суммы на экран не идут: Usage несёт ТРИ обязательных члена — state (ok/low/exhausted), remaining_percent и halt_reason — и ни окон, ни сумм (docs/architecture/14-api-contract/openapi.yaml, греп required: [state, remaining_percent, halt_reason]); продуктовый носитель — ПТ-35 (docs/product-requirements.md:63=ПТ-35): стоп по потолку = paused + оповещение «перевод остановлен: лимиты исчерпаны»; остаток — страница лимитов (S4+), слово владельца В-3. ⚠ К-13 ЗАКРЫТ (D39.132 п.2а: null на проводе; пере-суждён ревью 28 §4 №9 и НЕ опрокинут — с уходом дневной оси различие «свой потолок / нет кредита» перестало быть продуктовым).
5. Открытые дыры и их носители
| Дыра | Носитель |
|---|---|
| Строка 166 — движковая поверхность оценки $/глава; $0.03 — временная мера беты (П-10 зоны) | docs/PROGRESS.md:135=Движковая поверхность оценки |
| Строка 78 — леджер = нижняя граница (биллящийся decode-fail мимо request_log, ≤13% захода на ре-пробе) | docs/PROGRESS.md:65=Леджер денег = НИЖНЯЯ граница |
| Строка 136 — эскроу/intent (см. §3 п.10) | docs/PROGRESS.md:108=Write-ahead intent |
(добавка сборщика) PD-157 (minor) — day_usd книги флагом не перекрывается, платформой не виден и не задаётся; в status --json дневной фигуры нет |
platform/docs/DEFECT_REGISTER.md, греп PD-157 |
6. Карта носителей темы
| Вопрос | Где живёт |
|---|---|
| Словарь терминов | docs/glossary.md:55=**Деньги платформы:** |
| Управляемый потолок: решение и форма | D39.110 (+поправка D39.112 п.3: п.1 — пересказ, не цитата) |
| Максимум шкалы = Balance как есть | D39.115 п.2а; эррата — шапка D-лога, docs/architecture/05-decisions-log.md:4=Balance КАК ЕСТЬ |
Семантика --ceiling-usd |
D39.122 п.2в; backend/cmd/tmctl/invocation.go:142=the book USD ceiling in force for THIS RUN ONLY, backend/cmd/tmctl/main.go:260=--ceiling-usd is NOT a per-run budget |
| Формула аргумента потолка (без reserved) · ставка · settle-формы | D39.123 п.2б/г/д; PD-158/PD-159/PD-144 в реестре |
| Код денег платформы | platform/internal/pgstore/credits.go · pgstore/runs.go · runs/spawn.go · runs/reconcile.go · pricing/pricing.go |
| Ратификации, на которых стоит этот док | D39.179 (пере-пин цен 16.08, ×4.47; норма «стабилен чистый ФАЙЛ» — п.4) · D39.181 (закон раскрытия: признак объёмного стопа едет числом) · D39.182 (пак «деньги и честность»: план банк-ролей режется до первого вызова; порог согласия без контура банк-ролей) |
| Код денег движка | backend/internal/store/ledger.go · store/store.go · pipeline/stagerun.go · pipeline/status.go · config/book.go · pipeline/rebill.go (согласие на пере-оплату) · pipeline/terminologist.go (книго-широкие бюджеты банк-ролей) · pipeline/volume.go (объёмный потолок) |
| Дефекты денег | platform/docs/DEFECT_REGISTER.md (PD-104·113·144·157·158·159) |
| Бэклог-строки | docs/PROGRESS.md строки 78 · 136 · 137 · 166 (135 и 165 закрыты D39.131) |
| Контракт наружу | 14-api-contract/openapi.yaml (CeilingBounds, Usage); ПТ-35 |
| Запрет денег на экране | D39.84; D39.100/К-8; ПТ-35 |