Write down what three independent readings found about the spend ceiling: the shape is wrong rather than the rate, a paid call can vanish from the ledger on the happy path, and the fork is the owner's
This commit is contained in:
parent
1b8aa86cce
commit
0fafdd4bee
1 changed files with 116 additions and 0 deletions
|
|
@ -69,3 +69,119 @@
|
||||||
| Бэклог-строки | `docs/PROGRESS.md` строки 78 · 136 · 137 · 166 (135 и 165 закрыты D39.131) |
|
| Бэклог-строки | `docs/PROGRESS.md` строки 78 · 136 · 137 · 166 (135 и 165 закрыты D39.131) |
|
||||||
| Контракт наружу | `14-api-contract/openapi.yaml` (`CeilingBounds`, `Usage`); ПТ-35 |
|
| Контракт наружу | `14-api-contract/openapi.yaml` (`CeilingBounds`, `Usage`); ПТ-35 |
|
||||||
| Запрет денег на экране | D39.84; D39.100/К-8; ПТ-35 |
|
| Запрет денег на экране | D39.84; D39.100/К-8; ПТ-35 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠ ОТКРЫТАЯ РАЗВИЛКА 04.09: КНИГУ НЕЛЬЗЯ ДОЧИТАТЬ — разбор трёх независимых чтений, решение за владельцем
|
||||||
|
|
||||||
|
> **Статус: НЕ РАТИФИЦИРОВАНО.** Это разбор, а не контракт: ниже нет ни одного решения, только сходящаяся
|
||||||
|
> фактура и названная развилка. Носитель дефекта — `PD-440`/`PD-441` в регистре платформы. Собрано по
|
||||||
|
> прямому указанию владельца «посоветуйся с зонами и со старшей моделью»: читали независимо зона движка,
|
||||||
|
> зона платформы и внешний рецензент другой модели; расхождения между ними названы, а не сглажены.
|
||||||
|
|
||||||
|
**ЧТО НАБЛЮДАЛОСЬ.** Первый живой ПЛАТНЫЙ прогон книги через API (04.09) остановился, не продвинув книгу
|
||||||
|
ни на юнит, и воспроизвёлся дважды. Прогон умирает за 10–15 секунд, списание не двигается.
|
||||||
|
|
||||||
|
**ПОЧЕМУ — цепь, проверенная тремя чтениями независимо.** Запас нового прогона на НОВЫЕ траты равен
|
||||||
|
`chaptersLeft × ставка` (`platform/internal/runs/spawn.go`, греп `func (m meter) bookCap`; ставка
|
||||||
|
`DefaultPerChapter = 30_000` микро-USD). Резерв ОДНОГО редакторского вызова — worst case по `maxTokens`
|
||||||
|
(`backend/internal/pipeline/stagerun.go`, греп `func (r *Runner) callEstimateUSD`), замеренный отказ в
|
||||||
|
ряду `PD-440` — `denied estimate=$0.069828`. Отказ резервации трактуется как **авария всей книги**:
|
||||||
|
`runWave` зовёт `cancel()` производного контекста на ПЕРВОЙ ошибке любого рода, и уже допущенные
|
||||||
|
параллельные вызовы гасятся.
|
||||||
|
|
||||||
|
**ТРИ УТВЕРЖДЕНИЯ, СОШЕДШИЕСЯ У ВСЕХ ТРЁХ ЧТЕНИЙ:**
|
||||||
|
|
||||||
|
1. **Форма потолка неверна, а не только его размер.** Запас сжимается вместе с остатком книги, стоимость
|
||||||
|
неделимого шага — нет. Ставку можно поднять, стену это отодвинет, но не уберёт. Правильная форма —
|
||||||
|
`max(главы × ставка, шаг)`, а не `главы × ставка`.
|
||||||
|
2. **Резервацию убирать нельзя.** Она — единственный сериализованный контроль и единственное, что держит
|
||||||
|
обещание «не потратить больше, чем дано». Отраслевой стандарт тот же (см. прайор-арт ниже).
|
||||||
|
3. **Менять надо ТРАКТОВКУ ОТКАЗА**, а не наличие резервации: «не начинаем новое» вместо «гасим всё».
|
||||||
|
|
||||||
|
**ЧИСЛА, В КОТОРЫХ ЧТЕНИЯ РАСХОДЯТСЯ — и оба верны на своём числе воркеров.** Зона платформы: стена
|
||||||
|
стоит везде, где `chaptersLeft × ставка < workers × шаг`, при боевых четырёх воркерах это
|
||||||
|
`chaptersLeft ≤ 9` — недостижим не хвост, а **последние девять глав любой книги**. Внешний рецензент:
|
||||||
|
даже при ОДНОМ воркере `2 × $0.03 = $0.06 < $0.07` одного вызова, то есть **последние две главы
|
||||||
|
недостижимы в принципе**, независимо от параллельности. Второе — инвариантный пол, первое — сегодняшняя
|
||||||
|
конфигурация.
|
||||||
|
⚠ **Предсказание зоны платформы, ЗАМЕР ЗАКАЗАН, на момент записи НЕ подтверждён:** книга из ≤9 глав может
|
||||||
|
не переводиться вообще никогда. Проверяется за $0 на пятиглавой книге. До подтверждения — предсказание.
|
||||||
|
|
||||||
|
**ЧЕТВЁРТОЕ, ЧЕГО НЕ БЫЛО В ИСХОДНОМ ДИАГНОЗЕ (зона движка).** Резерв завышен ПО ПОСТРОЕНИЮ: оценка
|
||||||
|
считается по потолку выдачи. Под нынешним поведением он никогда не превращается в факт — его отпускают,
|
||||||
|
и следующее решение о допуске принимается против тех же завышенных чисел. Под «не начинаем новое»
|
||||||
|
соседи доседают по ФАКТИЧЕСКОЙ цене и освобождают разницу. Это само по себе может быть разницей между
|
||||||
|
«встала» и «дошла».
|
||||||
|
|
||||||
|
**ПЯТОЕ — ПРЕЦЕДЕНТ ВНУТРИ ЭТОГО ЖЕ ПАКЕТА, и он решает спор о направлении.** Объёмный потолок уже
|
||||||
|
построен с нужной семантикой и САМ противопоставляет себя денежному:
|
||||||
|
`backend/internal/pipeline/volume.go`, греп `THE STOP IS A COMPLETION, NOT A HALT` — «денежный потолок
|
||||||
|
останавливает прогон ПОСРЕДИ работы, которую он собирался сделать». Там же названа причина, по которой
|
||||||
|
допуск не сделан счётчиком у воркеров: «воркер, которому отказали в слоте, был бы вынужден бросить свой
|
||||||
|
элемент навсегда» — то есть ровно тот дефект, который денежный путь и имеет. Плюс три места уже
|
||||||
|
деградируют по `errReserveCeiling` вместо аборта (`escalation.go`, `repair.go`, `terminologist.go`);
|
||||||
|
не деградирует только главная волна.
|
||||||
|
|
||||||
|
**ШЕСТОЕ — ДЕФЕКТ, ПЕРЕЖИВАЮЩИЙ ЛЮБУЮ ПОЧИНКУ РАЗМЕРА И ФОРМЫ (зона платформы).** Стена МОЛЧАЛИВА:
|
||||||
|
прогон, вставший мгновенно, неотличим на всех поверхностях от работавшего — одинаковый статус, одинаковая
|
||||||
|
причина паузы, одинаковая полоса (наблюдение H16 зонного журнала, два прогона: $0.081 и $0). Недобрать
|
||||||
|
можно при любом потолке; сказать об этом сегодня нечем.
|
||||||
|
|
||||||
|
**ВЕС — ЖИВУЧЕСТЬ, НЕ ДЕНЬГИ.** Мёртвые прогоны рассчитались в ноль, леджер сходится тремя источниками
|
||||||
|
до микродоллара. Пользователь теряет ВРЕМЯ. ⚠ Отдельно и с другим весом — `PD-441`: на пути отмены есть
|
||||||
|
расход, который, ЕСЛИ он был, невидим для леджера по построению. Доказуемая форма именно такая; «деньги
|
||||||
|
потрачены» НЕ измерено. Одна движковая попытка — до трёх запросов к провайдеру (`backend/internal/llm/httpllm.go`,
|
||||||
|
греп `for att := 0; att < profile.MaxAttempts`, дефолт 3) под ОДНИМ резервом и ОДНОЙ строкой `request_log`:
|
||||||
|
след не просто беден, он агрегирован и не различает «не ушло ничего» от «ушло трижды».
|
||||||
|
|
||||||
|
**ПРАЙОР-АРТ (внешний рецензент, ссылки — в отчёте сессии).** LiteLLM делает буквально наше:
|
||||||
|
worst-case-резерв → отказ до отправки → замена фактической ценой; их известные баги — про ОБХОД бюджета
|
||||||
|
при параллельных запросах, то есть отраслевая беда противоположна нашей. Ближайший по смыслу стандарт —
|
||||||
|
Diameter Credit-Control (RFC 4006/8506) с `Final-Unit-Indication`: «это последний грант, доработай его и
|
||||||
|
не начинай нового» — ровно та семантика, которой нам не хватает. Kubernetes `ResourceQuota`: отказ — это
|
||||||
|
недопуск НОВОГО, уже созданное квота не трогает. Slurm `GraceTime`: слив вместо убийства. Карточная
|
||||||
|
пре-авторизация: холд с запасом, списание по факту. ⚠ Про биллинг при обрыве: OpenRouter документирует,
|
||||||
|
что для непотоковых запросов отмена клиентом биллинг НЕ останавливает — это факт о ЕГО платформе, для
|
||||||
|
наших провайдеров вопрос обязан быть закрыт вендор-докой по правилу `experiments/00-provider-quirks.md`,
|
||||||
|
а не рассуждением.
|
||||||
|
|
||||||
|
**РАЗВИЛКА ВЛАДЕЛЬЦА — ОДНА, И ЕГО ПРЕДЛОЖЕНИЕ ЕЁ РЕШАЕТ, А НЕ ОБХОДИТ.** Предложение владельца
|
||||||
|
(«называть примерную цену и останавливаться, когда деньги кончились») означает, что потолком становится
|
||||||
|
БАЛАНС. Тогда холд берёт весь баланс вперёд, и вторая книга не стартует, пока не рассчитается первая.
|
||||||
|
Это ровно та развилка, которую код уже держит открытой и помечает вопросом к владельцу:
|
||||||
|
`platform/internal/pricing/pricing.go`, греп `which fraction is a product question`. ⚠ Отдельный выбор
|
||||||
|
того же разговора: платят вызовом за ЮНИТ, а человек видит и выбирает ГЛАВЫ, и ставка за главу сама
|
||||||
|
признаёт слабость (греп `chapters differ in length`); `units_total` известен платформе до всякой оплаты.
|
||||||
|
|
||||||
|
**ЧТО СЧИТАЕТСЯ ЗАКРЫТЫМ И БОЛЬШЕ НЕ ОБСУЖДАЕТСЯ:** уже проданные прогоны смену ставки переживают без
|
||||||
|
миграции — продолжение оценивается по тому, за что прогон был ПРОДАН, бюджет читается обратно из холда
|
||||||
|
первой попытки, пин `TestARestartHoldsWhatTheRunWasSoldForWhenTheRateHasMovedSince`.
|
||||||
|
|
||||||
|
**СЕДЬМОЕ — ЕДИНИЦА УЧЁТА НЕ СОВПАДАЕТ С ЕДИНИЦЕЙ БИЛЛИНГА, и это бьёт не в отчётность, а в ЦЕЛОСТНОСТЬ
|
||||||
|
потолка** (найдено зоной движка чтением под вопрос, проверено оркестратором по строкам). Класс
|
||||||
|
`BilledDecodeError` заведён ровно для того, чтобы оплаченный-но-нечитаемый вызов стал ВИДЕН: рантайм
|
||||||
|
консервативно доседает его по оценке. Комментарий рядом сам называет цену ретрая —
|
||||||
|
`backend/internal/llm/httpllm.go`, греп `each retry is a new billed`, — и по этой причине УСЕЧЁННЫЙ ответ
|
||||||
|
сделан терминальным. Но битое тело осталось ретраябельным, а `retryLoop` при успешном ретрае возвращает
|
||||||
|
ответ и предыдущую ошибку ВЫБРАСЫВАЕТ (греп `if err == nil {` в `retryLoop`). Тогда рантайм видит один
|
||||||
|
успешный ответ, доседает его `Usage`, и оплаченный 2xx перед ним не попадает НИКУДА — ни в списание, ни
|
||||||
|
отдельной строкой лога. **Механизм, построенный чтобы сделать оплаченный вызов видимым, обходится ровно
|
||||||
|
на том пути, где всё прошло хорошо.** Следствие для потолка: допуск выдан один раз под одну оценку; если
|
||||||
|
под ней прошло два оплаченных ответа, `Reserve` об этом не узнает никогда — он сравнивает с потолком
|
||||||
|
сумму, в которой невидимого запроса нет. Потолок не «пробивается громко», он считает не то.
|
||||||
|
⚠ **Границы:** структурность доказана чтением; ЧАСТОТА пути НЕ измерена и, вероятно, мала — владельцу
|
||||||
|
эти две вещи давать раздельно. Более слабый родственник — сетевой обрыв/таймаут (там же комментарий про
|
||||||
|
`mid-generation RST that re-bills the call`): вход тот же, но «оборвалось на середине ⇒ оплачено» уже
|
||||||
|
вывод о провайдере, а не утверждение кода.
|
||||||
|
|
||||||
|
**ВЕНДОРСКИЙ ВОПРОС — ДВОЙНОЙ, и вторая половина конкретнее первой:** (1) платит ли провайдер за запрос,
|
||||||
|
оборванный КЛИЕНТОМ после начала генерации; (2) сколько раз он берёт деньги, когда мы ретраим ПОСЛЕ
|
||||||
|
оплаченного 2xx. Второй случай не гипотетический — он уже назван оплаченным в нашем собственном коде.
|
||||||
|
Оба закрываются вендор-докой по правилу `experiments/00-provider-quirks.md`, а не рассуждением.
|
||||||
|
|
||||||
|
**ГРАНИЦА ИНСТРУМЕНТА, ЗАМЕРЕННАЯ ЭТИМ ЖЕ ЗАХОДОМ.** Каталог мутаций (141 запись, 136 красных, ноль
|
||||||
|
переживших) доказывает ПОВЕДЕНИЕ и молчит о том, что код УТВЕРЖДАЕТ о себе. Круг 3 нашёл четыре
|
||||||
|
сверх-утверждения — и **ни одно не нашла посадка**; обе сегодняшние денежные находки получены чтением под
|
||||||
|
вопрос. Рабочая форма вопроса, выведенная зоной движка: не «правда ли то, что здесь написано», а **«что
|
||||||
|
должно было бы сломаться, если это правда, и ломается ли оно»**.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue