Take the wait ceiling from the whole catalogue rather than a key five providers do not set, and pin that the two channels quoting the estimate agree.

This commit is contained in:
heaven 2026-09-10 22:17:01 +03:00
parent 96e14513d6
commit 186e229333
2 changed files with 32 additions and 3 deletions

View file

@ -263,6 +263,14 @@ and sum of estimated-price rows beside committed_usd, which is what would let th
Форма — та же `D39.235` п.1, что в §4.7: `estimated{rows, micro_usd}` на `spend` И в `Money`. Ничего не
согласовывай отдельно: это один шов, и он уже описан нотой.
**ОДНО ОПРЕДЕЛЕНИЕ, ДВА ЧИТАТЕЛЯ — ЗАПИНЬ ИХ РАВЕНСТВО.** Величина «сколько из списанного — оценка»
поедет двумя каналами: кадром (эмиттер копит на лету) и `status --json`, который считает её ИЗ СТРОК
`request_log` (`backend/internal/pipeline/status.go`, греп `estimatedSpend`). Платформа по `D39.235` п.1(г)
обязана читать ОБА — и если на одном сторе они разойдутся, пользователю скажут два разных «не больше Y».
⇒ тест: на одном и том же сторе `Money.estimated` терминального кадра РАВЕН паре `estimated_rows`/
`estimated_usd` из `status --json`. Это ровно та дисциплина «одно определение», которой §4.9 требует от
`memberDrops`; здесь она нужна не меньше.
### 4.12 Строка **379**(а) — пин, решаемый окном стенных часов — **бери, раз всё равно трогаешь**
`backend/internal/pipeline/cutcall_test.go:402` — две строки таблицы девяти («after 2xx · cancelled by
@ -364,6 +372,11 @@ provider on a call in flight» (`stagerun.go:990`) уже знает и числ
## 7. Записка-план ДО первой правки
Напиши в свою секцию `docs/PROGRESS.md` порядок работы и почему он такой, ДО того как тронешь код.
**И размети КАЖДЫЙ подпункт §4 одним из трёх слов: МЕХАНИЗМ · ПИН · ВТОРОЙ ЛЕНДИНГ.** Подпунктов
пятнадцать, но работ там не пятнадцать: часть — однострочники и пины. Разметка нужна не для порядка, а
чтобы ОТЧЁТ первого лендинга сверялся со СПИСКОМ, а не с памятью. В прошлом паке этой серии ровно такая
разметка наряда дала «36 позиций, исходов не из трёх — 0»; без неё сессия сдаёт то, что помнит.
Рекомендованный: §4.1 сентинел (без него ни один другой пункт не проверяется) → §4.3 источник → §4.2
точка отказа → §4.4/§4.5 пост-обработка → §4.6 эскалация → §4.7 кадр → дальше строки.

View file

@ -71,9 +71,25 @@ so it can finish the chunk it is paying for». Сегодня это ЛОЖНО,
оставляет ни пометки `cancelled`, ни сеттла оценки: деньги у провайдера списаны, следа в леджере нет —
то есть ровно та потеря, ради устранения которой пак и делается.
**Делай РОВНО так:** грейс обязан покрывать потолок ожидания ПЛЮС время жёсткой фазы. Входы формулы
называю я: `max(attempt_max_s)` по всем провайдерам `backend/configs/models.yaml` (сегодня 1240 с) +
время жёсткой фазы + запас. Само число выбери сам и **обоснуй его в отчёте арифметикой**, а не круглостью: откуда взял потолок, сколько заложил на жёсткую
**Делай РОВНО так:** грейс обязан покрывать потолок ожидания ПЛЮС время жёсткой фазы.
**Входы формулы — и здесь ОДНА ловушка, из-за которой я сам чуть не задал неверную.** Брать
`max(attempt_max_s)` по провайдерам НЕЛЬЗЯ: ключ **инертен, когда не задан** (`backend/internal/llm/attemptcut.go`,
греп `is inert when unset` и `p.AttemptMax > 0`), а в `backend/configs/models.yaml` его нет у **пяти
провайдеров из восьми** (`zai` · `xai` · `openai` · `mistral` · `local`; есть у `deepseek` · `kimi` ·
`gemini`). У пятерых потолок ожидания даёт не ключ, а сама формула — `queue_slack_s + max_tokens/tok_s_floor`.
**потолок считай ПО КАТАЛОГУ, а не по одному ключу:** максимум по всем провайдерам от `DeadlineFor`
(`backend/internal/llm/attemptcut.go`, греп `func (p RetryProfile) DeadlineFor`) на НАИБОЛЬШЕМ бюджете,
который движок может попросить. Функция экспортирована ровно для такого вопроса — «сколько ждёт вызов
такого размера у этого профиля», и её доккоммент это говорит. Сегодня наибольшая крышка — 1240 с
(deepseek), у провайдеров без ключа значение выводится формулой. **Пере-считай своей рукой и назови
число**; арифметика — в отчёт.
⚠ Валидатор каталога держит лишь абсолютную границу (`backend/internal/config/models.go`, греп
`maxAttemptSeconds`) — она в часах и вопроса не решает.
Дальше — время жёсткой фазы + запас. Само число выбери сам и **обоснуй его в отчёте арифметикой**, а не круглостью: откуда взял потолок, сколько заложил на жёсткую
фазу, что будет, если провайдер сменит `attempt_max_s`. ⚠ Отдельно скажи, как число не протухнет: сегодня
оно живёт константой в твоей зоне, а зависит от конфига в чужой.