123 lines
46 KiB
Markdown
123 lines
46 KiB
Markdown
# Промт бэкенд-сессии: РУЧКА ЭФФОРТА + ЭКРАН ЦЕЛЕВОГО ЯЗЫКА + ДОБИВКА ХОЛОДНОГО ПРОГОНА (строки 104 · 46 · 16)
|
||
|
||
**Выдан 02.08.2026, оркестратор №10; решение владельца по развилке строки 74 (D39.87): вариант (б) — явный `reasoning_effort: "low"` для черновика ПЛЮС правка Go, дающая ручку тем ролям, у которых её нет.** Зона: `backend/` + стенд `~/books/gu-zhenren/coldrun-b/` + свой отчёт в `docs/archive/reports/`. **НЕ коммитить** — лендит оркестратор. **Первый деливерабл — эхо-блок ≤10 строк** (первым сообщением ДО работы: как понял скоуп / три работы и их СТОП-точки / потолки денег / что вне скоупа; подтверждения не жди — работай до СТОП-условий).
|
||
|
||
**Деньги (жёстко):** работа A = **$0**. Работа B = **$0**. Проба банка на `low` (§3.4) ≤ **$0.10**. Работа C (прогон) ≤ **$5.00** суммарно. ⚠ **$5 — ВНЕШНИЙ предохранитель, и он НЕ первый.** Внутри прогона стоят два суб-бюджета, которые связывают раньше и **гаснут МОЛЧА, без ошибки**: `gates.terminology.budget_usd: 0.05` (≈4 прохода терминолога — WARN `budget would be exceeded by the next batch; the remaining terms are left unconsolidated` + `break`) и `escalation.budget_usd: 0.10` (≈11 хопов — WARN `escalation hop denied by a USD ceiling; keeping the primary flag`, деградация без падения; ровно это усекло наблюдение эскалаций на прошлой пробе). Оба — в `~/books/gu-zhenren/coldrun-b/pipeline.yaml`. **Не спутай молчащий суб-бюджет с отказом модели** — иначе поставишь ложный СТОП; и не подними их молча — правку суб-бюджета объяви в отчёте с причиной. Потолки продублированы в `book.yaml ceilings`: `book_usd: 5.00` И `day_usd: 5.00` (ключа `budget_usd` не существует — строгий декодер упадёт; ⚠ `day_usd` считается по КАЛЕНДАРНОМУ дню UTC и по ЭТОЙ БД, `store/ledger.go:39,47` — через полночь ось обнуляется, несущий предохранитель = `book_usd`). Превышение любого потолка = СТОП+релей. Проба §3.4 живёт в СВОЁМ проекте (свой `book_id`, свой `project_db`) ⇒ её леджер отдельный и в потолок $5 работы C **не входит** — $0.10 сверх; в отчёте выведи ТРИ числа: проба · прогон C · сумма пака. В отчёте деньги — **двумя независимыми путями** (леджер И собственный пересчёт провайдерского `usage` по вендор-ценам); помни: **леджер = НИЖНЯЯ граница** (строка 78: 2xx с битым декодом списывается и в `request_log` не попадает — на прошлой пробе это было $0.0151 неизвестности на 17 оплаченных вызовов).
|
||
|
||
---
|
||
|
||
## §0. Рамка и ГЛАВНЫЙ мандат этого пака
|
||
|
||
**Слово владельца дословно: «элегантно встроить в текущее решение по коду. Чтоб было чисто».** Это не украшение — это приёмочный критерий. Перевожу его в проверяемые вопросы, на каждый из которых отчёт обязан ответить:
|
||
|
||
1. **«Это новый механизм или использование существующего?»** Правильный ответ — второй. Поле `Stage.Reasoning` существует с самого начала (`config/pipeline.go:208`), проброс на провод существует (`stagerun.go` → `llm/capability.go`), капабилити-слой различает провайдеров данными. Ничего из этого изобретать заново НЕ надо.
|
||
2. **«Появится завтра ЧЕТВЁРТАЯ синтетическая стадия — она унаследует ручку сама или её опять забудут?»** Это главный вопрос пака. Корень дефекта — не «забыли ключ», а **рукописные литералы `config.Stage`, каждый из которых молча теряет поля родителя**: в шиппинг-коде их ровно три (`terminologist.go:515` — обе бэнк-роли; `terminologist.go:568` — не-проводная, из неё читается только `Name`; `internal/pipeline/repair.go:384` — ⚠ в дереве ДВА `repair.go`, нужен пакет pipeline; здесь родительская стадия РЕАЛЬНАЯ и несёт выбор владельца, который просто теряется), **плюс ЧЕТВЁРТЫЙ в live-риге** (`internal/pipeline/live_reprobe_test.go`), и он не декоративный — см. §3.4. Правка, чинящая места копипастой, дефект НЕ закрывает — она его тиражирует. Перед стройкой пере-проверь список сам: `grep -rn 'config\.Stage{' --include='*.go' backend/`.
|
||
3. **«Заработает ли пара, которой в репо ещё НЕТ, без правки Go?»** и **«вторая книга той же пары — без ложных флагов?»** — обязательны на каждый фикс, как всегда.
|
||
4. **«Не появилось ли второго способа сказать то же самое?»** Один шов, одно место решения, никаких параллельных путей.
|
||
|
||
**Дисциплина:** никаких хаков и ворэраундов; каждый фикс — поддерживаемое мультиязычное решение с тестом. **Архитектурная дыра → СТОП+пинг с диагнозом и вариантами, не чинить на месте.** Комментарии — 1–2 строки «почему», улики — в отчёт (норма владельца 26.07). **Самопроверка исполнением обязательна** (свой код + сформированные запросы + полученные результаты); **вывод на агрегате до вскрытия единиц запрещён** — перед любым «узел работает» открой хотя бы одну живую единицу с каждой стороны. Дифф `^func Test` — **исполнением, не памятью**. В конце — адверсариальный проход author≠reviewer по своим правкам. **Канал вопросов:** непонятно / конфликт промта с кодом / замер бьёт по посылке → СТОП+пинг оркестратору через владельца, НЕ интерпретация. **Право сказать «этого делать не надо»** — есть, с аргументом в отчёте.
|
||
|
||
---
|
||
|
||
## §1. Онбординг (карта чтения, целиком доки НЕ читать)
|
||
|
||
1. `CLAUDE.md` (гардрейлы: `.env` НЕ читать · **DeepSeek thinking НЕ отключать** · аномалия провайдера → вендор-дока, не гадать) → CURRENT-STATE в `docs/PROGRESS.md` (строки **104**, **46**, **74**, **16**, **13б** — твои).
|
||
2. **`docs/architecture/05-decisions-log.md` — блоки D39.86 и D39.87 целиком** (приёмка ре-пробы со всеми числами и поправками; решение владельца по развилке + мандат «элегантно и чисто» как приёмочный критерий).
|
||
3. **`docs/experiments/00-provider-quirks.md`, секция `DeepSeek-V4-Flash-0731` целиком, особенно п.3а и п.10** — вендор-таблица маппинга эффорта и что именно замерено на боевой форме. Читать ПЕРЕД любым платным вызовом.
|
||
4. `docs/archive/reports/COLDRUN_B_DEBUG_2026-08-02.md` — **ревю-шапка обязательна** (в ней поправки приёмки; тело отчёта местами точнее шапки не является).
|
||
5. `backend/README.md` (инварианты «ЛОМАТЬ НЕЛЬЗЯ») + `docs/architecture/12-go-style-notes.md` §0 (норматив общности).
|
||
|
||
---
|
||
|
||
## §2. Что УЖЕ установлено замером — не пере-открывать (приоры, опровергаются аргументом/замером)
|
||
|
||
- **Блокер — не эхо, а ПУСТЫЕ ответы.** На боевом `max_tokens=8496` 0 из 9 вызовов пригодны: размышление (15–21 тыс. симв.) съедает общий бюджет, до ответа модель не доходит. Удвоение потолка НЕ помогает (4/5 пустых при 16992) — вариант «поднять флор» фальсифицирован и закрыт.
|
||
- **Причина — вендор-дефолт эффорта.** Дословно из `guides/thinking_mode`: *«Thinking mode is enabled by default, with the default effort being high»*. Маппинг: у `deepseek-v4-flash` `low→low`, `high→high`, `xhigh→high`, `max→max`; **у `deepseek-v4-pro` `low→high`** — то есть на pro ручка эффорта не работает вовсе. Сноска вендора: *«We will update the actual mapped effort of `deepseek-v4-pro` in early August 2026»* — то есть прямо сейчас; при аномалиях у РЕДАКТОРА идти в вендор-доку, а не гадать.
|
||
- **`reasoning: "low"` на deepseek-стадии легален и гейт `echoMineViolation` НЕ трогает** (гейт инспектирует МЕХАНИЗМ `capabilities.reasoning.control`, не значение; у deepseek `ReasoningNone`, где `off`/`""` — осознанный no-op, а `low` уходит на провод). Проверено проводом: 22 тела с `reasoning_effort:"low"`, ноль ключей `thinking`, ни одного пустого `reasoning_content` (отчёт: 24/24 разобранных; пере-счёт приёмки по сырому логу — 27/27, разница только в знаменателе) ⇒ **гардрейл «thinking не выключать» не нарушается.**
|
||
- **Замеры варианта (б) на 20 чанках:** 20/22 вызовов `finish=stop`, 18/20 чанков отгружено, волна **$0.028195** all-in ($0.019489 только flash), латентность 9–44 с. Цена: эхо 3/20 · **1 черновик из 18 пришёл ЦЕЛИКОМ НА АНГЛИЙСКОМ и прошёл как `ok`** (это и есть работа B).
|
||
- **Ре-ген лечит СТОХАСТИКОЙ, а не бюджетом:** единственный выживший вызов пробы A уложился в 8285 токенов при базовом потолке 8496 и выданных 16992 ⇒ доливать бюджет бессмысленно.
|
||
- **Терминолог на 0731 сломан:** 4 батча из 5 `length` с `completion=8000` ровно и пустым телом, банк консолидировал 1 терм из 81 (было 21/21 `stop` до смены весов). **При thinking-off он был здоров 5/5 — но thinking-off это разворот гардрейла, мы его НЕ делаем.**
|
||
- ⚠ **Терминолог на `low` НЕ ЗАМЕРЕН НИКЕМ.** Это открытый вопрос твоей §3.4, а не известный факт. Формулировку квирков п.10 «терминолог … ручкой НЕ лечится» читай вместе со следующей фразой того же буллета — «бэнк-роли не имеют ручки эффорта вовсе ⇒ всегда едут вендор-дефолтом `high`»: там сказано «ручки НЕТ», а не «`low` пробовали». Противоречия с этим промтом нет.
|
||
|
||
---
|
||
|
||
## §3. Работа A — ручка эффорта для ролей, у которых её нет (строка 104). $0 кода + ≤$0.10 пробы
|
||
|
||
**Цель:** выбор владельца «сколько думать» должен доезжать до КАЖДОГО платного вызова движка, а не только до стадий книги. Сегодня он доезжает до `draft`/`edit` и теряется у бэнк-ролей (терминолог, классификатор) и у repair.
|
||
|
||
**Делай РОВНО так (ратифицировано):**
|
||
- Значение приходит из **ДАННЫХ** (конфиг), Go не ветвится ни по провайдеру, ни по паре, ни по книге.
|
||
- Ручка ран-скоупная, **не пар-данные и не книжный канон** — в пар-пак и в `book.yaml` она не заходит.
|
||
- Правка обязана накрыть **все три** места разом и так, чтобы **четвёртое такое же место не могло появиться молча** (см. §0 п.2).
|
||
- `repair.go:384`: родительская стадия `st` РЕАЛЬНАЯ и уже несёт выбор владельца — здесь речь не о новом ключе, а о **прекращении его потери**. Доккоммент `repair.go:378-379` («no reasoning setting, so the provider default holds — on DeepSeek that means thinking stays ON and the echo mine is not armed») декларирует посылку, **которую замер фальсифицировал** — он обязан уехать вместе с правкой.
|
||
- **Ловушка хеш-оси, закрыть ТЕМ ЖЕ диффом — ОБЕ расщеплённые пары, не одна:** `bankCheckpointExists` строит `Request` БЕЗ `Temperature`/`Reasoning` (`terminologist.go:498-501`), а `runAttempt` — С ними (`stagerun.go:403-406`); `Reasoning` входит в `RequestHash` (`internal/pipeline/render.go:279,308` — в дереве ДВА `render.go`, нужен пакет pipeline). **⚠ ТА ЖЕ пара есть на пути repair:** `repairCheckpointExists` (`repair.go:350`) собирает `Request` тем же обрезанным способом, и её доккоммент (`repair.go:346-349`) прямо декларирует «mirrors runRepairAttempt's request identity exactly … the two must address the same checkpoint» — правка `:384` без `:350` этот инвариант ФАЛЬСИФИЦИРУЕТ. Сегодня оси совпадают только потому, что значения нулевые. **⚠ Расходятся они в ОБЕ стороны, и вторая — денежная, она и опаснее:** (i) `paid` ложно-**false** — на резюме уже оплаченного прохода бюджетный пред-чек засчитает оценку заново и может оборвать проход до первого вызова; (ii) `paid` ложно-**true** — на стенде, где уже лежат бэнк-чекпойнты, записанные при ПУСТОМ `Reasoning` (а такой стенд у тебя есть — `reprobe/optB`), проба адресует старый хеш и вернёт «оплачено», из-за чего гейт суб-бюджета (`terminologist.go:583`, условие `!paid && …`) не выполнится ВООБЩЕ, а `runAttempt` посчитает новый хеш, чекпойнта не найдёт и уйдёт в свежий ПЛАТНЫЙ вызов **мимо `gates.terminology.budget_usd`** — прикрывать останется только книжный потолок. Оба направления закрываются ОДНИМ диффом и оба обязаны иметь тест: (1) резюм оплаченного пасса бюджетом не режется; (2) свежий пасс на стенде со старыми чекпойнтами гейт бюджета ПРОХОДИТ, а не обходит. Пере-проверь сам, нет ли третьей такой пары: `grep -rn 'RequestHash(Request{' --include='*.go' backend/`.
|
||
- **Доккомменты эхо-гейта, тем же диффом (обязанность D39.86 п.2 / D39.87):** `config/models.go:440-448` и `llm/capability.go:52-58` утверждают инвариант «echo-prone провайдер ОБЯЗАН держать thinking на дефолте провайдера». После санкции (б) это неверно: тот же провод легален через `stages[].reasoning` и запрещён через `model.extra_body` (`thinkingControlExtraKeys` содержит сам ключ `reasoning_effort` при любом значении). Гардрейл «thinking не выключать» цел — неполна ДОКУМЕНТАЦИЯ защиты, и следующая сессия прочитает её как полную. Сам гейт **не ослаблять**.
|
||
|
||
**Реши сам и аргументируй в отчёте:**
|
||
- **Форма шва.** Мой приор (опровергается аргументом): корень — рукописные литералы `config.Stage`, теряющие поля; значит лечение — ОДИН шов деривации синтетической стадии, где по каждому полю принято ЯВНОЕ решение, и все три места идут через него. Если найдёшь форму чище — бери свою, но ответь §0 п.2 явно.
|
||
- **Гранулярность ручки внутри блока банка.** `gates.terminology` обслуживает ДВЕ роли и допускает ДВЕ РАЗНЫЕ модели (`Model` для терминолога и `ClassifyModel`/`ClassifierModel()` для классификатора). Одна ручка на обе или две — решить и обосновать: у ролей разная форма задачи (длинный рендер против короткой классификации с закрытым словарём), и замер показал, что в стену упирается именно длинная (классификатор при `high` уложился в 1323 токена вывода). Не размножай ключи без нужды, но и не склеивай молча.
|
||
- **`Temperature` тем же диффом.** Та же конструкция роняет и её (на провод уходит `temperature: 0`). Сегодня ущерба нет — DeepSeek в thinking-режиме температуру молча игнорирует (quirks) — но при смене модели бэнк-роли поедут на нуле без единой строки конфига, это описывающей. Решить осознанно: пробрасывать, или явно зафиксировать нуль комментарием «почему так правильно».
|
||
- **Мульти-провайдерность ручки.** У `control = extra_body_disable` (glm-5/5.1) ПУСТОЙ эффорт означает не «вендор-дефолт», а `thinking:{type:disabled}` — то есть thinking ВЫКЛЮЧЕН, зона эха. Конфиг это допускает: `gates.terminology.model` не ограничен семейством. Дизайн обязан закрывать оба режима осознанно, иначе ручка починит только `ReasoningNone`-семейство и оставит на glm тихий thinking-off.
|
||
- **Наш enum против вендорского.** Валидация (`config/pipeline.go:954-957`) принимает `"" | off | low | medium | high` — это НАШ набор, он per-стадийный и **слеп к провайдеру**. У DeepSeek документированы `low/high/max` (+`xhigh` в таблице маппинга): `medium` на deepseek — неопределённое поведение, а `max`/`xhigh` нашим конфигом недостижимы вовсе. Нужно ли валидировать значение против капабилити РЕЗОЛВНУТОЙ модели — твой дизайн-вызов; если да, это касается и новой ручки. Аргументируй решение либо явный отказ.
|
||
|
||
**§3.4. Проба банка на `low` (≤$0.10, ОБЯЗАТЕЛЬНА перед работой C).** Терминолог на `low` не мерил никто — это открытый вопрос, а не известный факт.
|
||
|
||
- **⚠ Хост пробы: НЕ `coldrun-a`.** Тот проект — ЗАМОРОЖЕННЫЙ ЭТАЛОН (банк-стоп, подписные сайдкары), на нём держится сравнимость цены строки 16; писать в него ЗАПРЕЩЕНО, только читать. Отдельной команды «прогнать только бэнк-стадию» не существует (`--verify-bank` лишь ОСТАНАВЛИВАЕТ после банка), а майнинг-стоп идёт после ВСЕЙ черновой волны ⇒ проба «с нуля» купила бы ещё одну черновую волну и вышла за потолок.
|
||
- **Маршрут (приор, опровергается аргументом): СВОЙ проб-проект, а не резюм чужого.** Заведи `~/books/gu-zhenren/coldrun-b/reprobe/bank-low/` по образцу `reprobe/classify6/`: свой `book_id`, свой `project_db`, свои `ceilings: book_usd 0.10 / day_usd 0.10`, `source_file` = срез coldrun-a **на чтение**, черновая стадия на выбранном уровне. Смета: черновая волна ≈$0.02 + батчи банка ≈$0.01 ⇒ порядок $0.035, влезает с запасом. Так проба изолирована, её леджер отдельный, и провалиться она может не тронув ничего. ⚠ Альтернатива «резюмнуть `optB`, у которого волна уже куплена» дешевле, НО: у него остаток потолка $0.000534 при `book_usd: 0.04` (потрачено $0.039466) — потолок пришлось бы поднимать, а в его БД лежат СТАРЫЕ бэнк-чекпойнты, написанные при пустом `Reasoning`, то есть ровно материал для ложно-true из ловушки §3. Выберешь этот путь — аргументируй и закрой оба риска явно.
|
||
- **⚠ ДВА молчащих пути обрыва — критерий обязан их различать.** Пасс бэнк-роли деградирует БЕЗ ошибки и БЕЗ падения: (i) ролевой суб-бюджет `gates.terminology.budget_usd` (`terminologist.go:583-594`) — WARN `budget would be exceeded by the next batch; the remaining terms are left unconsolidated` + `break`; (ii) книжный потолок леджера — отказ резервации. В ОБОИХ случаях `consolidated` проседает ровно так же, как при сломанной модели. **Поэтому вердикт «`low` не работает» имеешь право вынести ТОЛЬКО предъявив, что ни один из двух путей не сработал:** прочитай `RoleSpentUSD` роли, остаток суб-бюджета и `spend` ДО и ПОСЛЕ, и приведи их в отчёте рядом с числом батчей. Иначе получится ложный СТОП, отменяющий работу C на пустом месте.
|
||
- **Ответь числами:** сколько батчей `finish=stop` из скольких, сколько термов консолидировано из скольких, `off_language`, цена, и вскрой СЫРОЕ ТЕЛО хотя бы одного батча (прошлая сессия этого не сделала и сама назвала это слабостью). **Критерий:** батчи должны пролезать. Не пролезают на `low` — это НОВАЯ развилка (другой уровень / другая модель бэнк-роли) ⇒ **СТОП+релей владельцу с числами, работу C не начинать.**
|
||
- **Классификатор** проверяется тем же заходом ригом 6/6 (`internal/pipeline/live_reprobe_test.go`, build-tag `live`, ~$0.0004). ⚠ **Риг несёт тот самый ЧЕТВЁРТЫЙ рукописный `config.Stage`, а `runBankAttempt` оставляет от переданной стадии только `Name`.** После твоего шва риг ОБЯЗАН ехать через тот же шов — иначе его зелёное 6/6 не доказывает про `low` ничего (ложно-зелёный результат за $0.0004). Это и есть живая проверка вопроса §0 п.2: если риг пришлось править руками отдельно — шов недостаточно элегантен.
|
||
|
||
---
|
||
|
||
## §4. Работа B — экран целевого языка (строка 46). $0
|
||
|
||
**Предмет:** на `low` наблюдался полный связный черновик **на английском**, прошедший гейт черновой стадии как `disposition=ok`. Корень: `classify` экранирует ИСХОДНУЮ письменность, пустоту, обрыв и отказ; «не исходный и не целевой» не ловит ни один предикат. Санитайзер поймал бы, но он стоит **только на последней стадии** (`chunkrun.go:52`, `isFinal`).
|
||
|
||
**Делай РОВНО так:**
|
||
- **Область — выход не-последней стадии КНИГИ, и только её.** ⚠ `isFinal=false` — это НЕ синоним «черновик»: тем же `runAttempt(..., isFinal=false)` идут бэнк-роли (`terminologist.go`) и repair, а их ответы **законно не в целевой письменности** (таблица терминов несёт исходные ханьские ключи; repair возвращает спан). Экран, повешенный на «любую не-последнюю стадию» буквально, даст 100% ложных флагов на терминологе. Скоуп задай так, чтобы это было невозможно, и покажи в отчёте, ЧЕМ именно он ограничен (роль? позиция в `Stages`? явный признак «это шиппинговая проза»?).
|
||
- Экран **данными, не Go-ветвлением**. ⚠ **Носитель `gates.terminology.target_script` НЕ годится** — я его предлагал в черновике промта и снимаю: ключа нет ни в одном шиппинговом конфиге репо, и живёт он под ЧУЖИМ гейтом (при выключенном терминологе не валидируется) ⇒ новый экран оказался бы инертен в проде. Носитель выбери сам и обоснуй: у движка уже есть дата-план целевой стороны (`internal/lang/data/`, `checks.Checkers` с `TargetActive()`/`TargetScriptNonLatin()`, `Book.TargetLang`) — приор в том, что ответ там, а не в новом ключе конфига. Ревью-вопрос: «пара, которой в репо нет, получает экран автоматически или требует правки Go?»
|
||
- ⚠ **Это ВЕРДИКТ-ДВИГАЮЩЕЕ изменение.** Порядок: сначала дизайн и пинг с ним, **потом** код. В дизайне обязан назвать развилку, а не предрешать её: **(а)** предикат внутри `classify()` ⇒ бамп `classifierVersion` (`disposition.go:107-118`), который фолдится в снапшот (`snapshot.go:430`) ⇒ снапшот двигается у ВСЕХ книг и голден пере-захватывается; **(б)** отдельный гейт/флаг вне `classify()` ⇒ область фолда другая. Цена (а) на существующей книге — промах ВСЕХ чекпойнтов, `--resnapshot` + пере-покупка; на свежем стенде coldrun-b — ноль. Голден пере-захватывается ОДИН раз под ратифицированную смену поведения, и **маскированный структурный дифф обязан быть пуст**, если менялись только версии/хеши (голден-гард = инвариант №8, D23 п.1).
|
||
- ⚠ **labels-фриз работа B двигать НЕ ДОЛЖНА вовсе** — она не трогает предикаты k2/k4a/k4b/k4_inverse/K6. Любое отклонение от чисел §7 = регресс, а не новый базлайн ⇒ СТОП+пинг, не пере-базлайнить.
|
||
|
||
**Реши сам и аргументируй:**
|
||
- **Вторая половина дыры, и она важнее для общности.** `detectLatinInsertion` (`checks/sanitizer.go:228`) внутри санитайзера НЕ обусловлен `TargetScriptNonLatin()`, хотя доккоммент `disposition.go:302-305` объявляет именно эту защиту (реальный гард стоит только на репэйр-пути — `quality.go:215`, `repair.go:208`). Следствие: как только будущая **латинописьменная** цель поедет задокументированным путём расширения (`data/target-<tgt>.txt` в go:embed), детектор сработает на ЧИСТОЙ целевой прозе и дропнет 100% чанков; а частичный файл цели невозможен — `CompileCheckers` паникует, то есть новая цель ОБЯЗАНА включить санитайзер. Ревью-вопрос владельца для →en/→de сегодня отвечается **НЕТ**. Кандидат лечения — тот же шов, что уже применён к репэйру. Твой вызов: чинить это здесь (по-моему — да, это одна работа с первой половиной) или выносить с носителем; ответь явно.
|
||
- Что делать с пойманным юнитом: флаг+скип, ре-ген, или эскалация. Помни: `empty`/`length` сегодня retryable, но НЕ escalatable (`disposition.go:142-149`), и ре-ген лечит стохастикой (§2).
|
||
|
||
---
|
||
|
||
## §5. Работа C — добивка холодного прогона (строка 16). ≤$5
|
||
|
||
⚠ **Идёт только после того, как работы A и B ЗАКРЫТЫ И ЗАМОРОЖЕНЫ** (код + пере-захваченный голден + зелёная батарея ВМЕСТЕ с ними) и §3.4 зелёная. Причина жёсткая: работа B двигает версию, фолдящуюся в снапшот ⇒ **любая правка B после первого платного вызова C промахивает ВСЕ чекпойнты книги** — смок C1 осиротеет и C2 перекупит его целиком, а «итоговая цена холодного старта» (единственный деливерабл строки 16) станет невыводимой. Работа B застряла на дизайн-пинге → работа C НЕ стартует, это легитимный исход захода.
|
||
|
||
Стенд `~/books/gu-zhenren/coldrun-b/` собран, $0-проверен и стоит нетронутым: свежая БД, **сид НЕ подключён** (прогон холодный), `pipeline.yaml` побайтно равен эталону coldrun-a кроме шапки, ключи проверены.
|
||
|
||
**Правка стенда, которую делаешь ТЫ (не подразумевается — делай явно):** в `~/books/gu-zhenren/coldrun-b/pipeline.yaml` черновая стадия сейчас несёт `reasoning: "off"` — **это и есть тот no-op, который отправил прошлый прогон в стену 0/9.** Поставь туда выбранный владельцем уровень; комментарий строки («NO-OP у deepseek … эхо-мину НЕ вооружает») после правки неверен и должен уехать вместе с ней. Редакторскую стадию (`deepseek-v4-pro`) НЕ трогай: у pro эффорт не настраивается (§2), `"off"` там останется no-op'ом. Бэнк-роли — по итогам §3.4. Каждую правку стенда перечисли в отчёте построчно.
|
||
|
||
**Механика ступеней (не гадать):** майнинг-стоп идёт после ВСЕЙ черновой волны. **C1 смок** = `source_file` из 2 глав. **C2 добор** = ДОПИСАТЬ остальные главы в тот же `source_file`, ту же БД, тот же проект — **вторую БД НЕ создавать**, непрерывность автобанка и есть предмет отладки. ⚠ **ЛЕГИТИМНО при доборе:** рост автобанка двигает draft-снапшот; байт-неизменные юниты спасает re-pin (`repin.go`), а изменённые инъекции глав смока перекупятся ПОД порогом консента (`min($0.50, 5%)`, `rebill.go`) — это НЕ тихая перепокупка и НЕ дефект: посчитай, объясни, ложного СТОПа не делай.
|
||
|
||
⚠ **Предохранитель редакторской волны (узел без рычага).** Редактор стенда — `deepseek-v4-pro`, у которого по §2 ручка эффорта НЕ работает (`low→high`), а сама редакторская волна **не гонялась НИ РАЗУ** — ни до смены весов, ни после (coldrun-a закрылся на банк-стопе). То есть в C1 ты впервые запускаешь узел того же класса отказа, что убил черновик и терминолога, и рычага у тебя там нет. **Останови после ПЕРВЫХ 2 edit-юнитов и посмотри `finish_reason`, `completion_tokens` и непустоту `content` на каждом** прежде чем пускать волну целиком. Упор в потолок / пустое тело / `completion` ровно в лимит = тот же блокер ⇒ **СТОП+пинг с числами**, не подбор числа и не «поднимем флор».
|
||
|
||
- **C1.** Черновая волна → майнинг-стоп → терминолог → банк-пауза `--verify-bank` как ТВОЯ инспекционная точка (не подпись владельца — банк автономен, D39.77): вскрой банк (язык dst · экран целевой письменности · размеры · KWIC-санити · доля ⟨проверить⟩), вскрой ГЛАЗАМИ 2–3 черновика, сверь деньги двумя путями. Всё объяснимо → продолжай с НЕподписанным банком (пере-запуск `translate` без `--verify-bank`). Редакторская волна → гейты/чекеры → экспорт → вскрой 2–3 финала глазами.
|
||
- **C2.** Остальные ~8 глав тем же порядком (банк-пауза на твоё усмотрение, аргументируй).
|
||
- **Обязательные наблюдения per-узел:** счётчики волн/ретраев/эскалаций · эхо-события · упоры `max_tokens` · банкнота: кандидаты→банк и потери на пути · инъекция банка — **подтверждать байт-диффом СЫРОГО ТЕЛА: `LOG_LEVEL=debug LOG_LLM_BODIES=1 ./bin/tmctl translate …` (ТОЛЬКО вместе — при дефолтном `LOG_LEVEL` тела не пишутся вовсе, `main.go:66`), НЕ по `injected_ids`** (там только exact-хиты); ⚠ тела в логе УСЕЧЕНЫ (`obs/logging.go`) — на длинных ответах JSON не парсится, поэтому деньги считай из `request_log`, а не из лога · распределение `flag_reason` · wall-clock по стадиям и итогом · деньги нарастающим итогом двумя путями · **минимум ОДИН намеренный стоп+резюм посреди волны** · бэкапы F4 на каждом платном старте.
|
||
- **⚠ ОСИ ГОЛОСА — впервые получат данные (строка 13б).** Флаггер голоса живёт на ФИНАЛЬНОЙ волне (`waverun.go:392,512`), а редакторская волна не гонялась НИ РАЗУ — поэтому на coldrun-a оси показывают `flags=0 over attributed=0 of replies=0`, и это «не считалось», а не «чисто». Твой прогон — первый, где они реально отработают: **вынеси их числа со знаменателями отдельным пунктом отчёта**, это гейт решения владельца по `speech-cue.txt`. ⚠ Помни: поле `rules=` в строке `VOICE` говорит «гейт СКОНФИГУРИРОВАН» (читается из конфига времени отчёта, `quality.go:436`), а не «отработал» — честный дискриминатор это знаменатели.
|
||
**Прогноз цены — приор, чтобы ты узнал аномалию, а не просто упёрся в потолок** (опровергается замером; считай свой по ходу): черновая волна 20 чанков на `low` ≈ $0.02 · терминолог ≈ $0.01–0.02 · редакторская волна — **никогда не гонялась**, оценка из единственного наблюдённого вызова `deepseek-v4-pro` (9059 выходных токенов, $0.008706) на ~14 edit-юнитов ⇒ ≈$0.14. **Итого порядок $0.2 на 10 глав, потолок $5 = запас ×20.** Если фактическая цена уходит за ~$1 — это не «дорого», это СИГНАЛ: останавливайся и смотри, что покупаешь, а не жди потолка. ⚠ Редактор едет на вендор-дефолте `high` и придушить его нельзя (маппинг pro `low→high`), а вендор объявил смену маппинга pro на начало августа — если редакторские вызовы начнут упираться в потолок или возвращать пустое, это тот же класс, что блокер 74, и он требует СТОП+пинга, а не подбора числа.
|
||
|
||
- **Дебаг-дисциплина:** дефект узла → СТОП волны (чекпойнты держат) → диагноз до корня (аномалия провайдера → официальная вендор-дока, НЕ гадать) → фикс по норме §0 (мультиязычный, с тестом; батарея + голден зелёные ДО resume) → точечный redrive (пере-покупка видима и посчитана). **Заморозка прогона чекпойнтом ради доработки — ЛЕГИТИМНЫЙ исход, не провал.**
|
||
|
||
---
|
||
|
||
## §6. Чего НЕ делать
|
||
|
||
Сид НЕ заводить (прогон холодный) · судья Ф2 не гоняется · DC7-остаток НЕ мерить (строка 98 требует СИДОВОГО прогона — этот бессидовый) · **`backend/configs/models.yaml`: блоки `capabilities` (включая `reasoning`, `min_max_tokens`) и `price` — ВЕРДИКТ-НЕСУЩИЕ** (резолвнутая капабилити фолдится в снапшот): любая их правка обнуляет чекпойнты и перекупает прогон ⇒ трогать ТОЛЬКО до первого платного вызова работы C, с явной записью в отчёт; ослаблять `echoMineViolation` или флаг `echoes_when_thinking_off` — **нельзя вообще** · **`docs/` — чужая зона: твоё в ней РОВНО два места** — свой отчёт в `docs/archive/reports/` и секция `## Бэкенд` в `docs/PROGRESS.md`; `docs/experiments/*` (зона полигона, включая `00-provider-quirks.md`), `docs/architecture/*`, `docs/product-requirements.md` — только ЧИТАТЬ, находки для них — пунктом отчёта, правит оркестратор · **thinking у DeepSeek НЕ выключать ни в одной конфигурации** (проба C прошлой сессии была карантинным ЗАМЕРОМ по вопросу владельца, а не разрешением; боевой гейт `echoMineViolation` цел и трогать его не надо) · **проект `~/books/gu-zhenren/coldrun-b/reprobe/optNoThink/` — СПЕНТ-проба, НЕ резюмить** (его `book.yaml` указывает на карантинную копию models.yaml с выключенным thinking) · `CheapGateVersion`/labels-фриз/голден-фикстуры двигать ТОЛЬКО под работу B по процедуре §4 · слаги моделей не менять без live-фактчека `/models` · ручка #77 (ре-ген эха перед эскалацией) сама не включается — она за владельцем · чужое в дереве не трогать: `START_PROMT.MD`, `frontend/`, `platform/`, `.gitignore` (⚠ **фронт-сессия сейчас ЖИВАЯ и коммитит** — перед любой git-операцией `git status` и опознание чужого; `reset --hard`/history-rewrite запрещены) · НЕ коммитить · тексты книги в отчёт НЕ цитировать (сырьё живёт durable в `~/books`).
|
||
|
||
---
|
||
|
||
## §7. Отчёт и СТОП
|
||
|
||
`docs/archive/reports/EFFORT_HANDLE_<дата>.md`: эхо-шапка · **работа A** (форма шва + ответы на четыре вопроса §0 + числа пробы §3.4) · **работа B** (дизайн, что решено по второй половине дыры, маскированный дифф голдена) · **работа C** — per-узел наблюдения, **оси голоса со знаменателями**, **итоговая цена холодного старта ЦЕЛИКОМ, включая редактуру** (это и есть закрытие строки 16) двумя путями · дефекты: найдено / починено (с тестами) / отложено (с носителем) · **критик полноты против себя** (обязательная секция) · **адверсариальный проход по своим фиксам** · **заявление = команда**: каждое число сопровождено командой, которой получено — приёмка их пере-ранит · git-список тронутого (только своё).
|
||
|
||
Батарея в отчёт числами: `go build ./...` · `go vet ./...` · `go vet -tags live ./internal/pipeline/` · `go test -race -count=1 ./...` · майнер-парити `TM_MINER_PARITY=1 … -run Parity` EXACT · labels-фриз `TM_CHECKER_LABELS=1` (k4b 10/1/36/99 · k4_inverse 3/0/1/71 · k2 34/1/6/51 · K6 1/6/0/251 · k4a 0/0/0/348) · голден `TestGoldenDeterminism` · `gofmt -l`.
|
||
|
||
Краткий итог — `docs/PROGRESS.md`, секция `## Бэкенд`, допиши СВЕРХУ; бэклог-таблицу и CURRENT-STATE НЕ трогать. D-номер лендинга проставит оркестратор. **СТОП — приёмка оркестратора.**
|