From 90d589bc9addb131a62215eb5a9765ff6516fe1a Mon Sep 17 00:00:00 2001 From: heaven Date: Fri, 11 Sep 2026 06:03:34 +0300 Subject: [PATCH] Take the cold run's report and the polygon's own record into the tree: a real book carried from intake to a file a person read, priced to the micro-dollar --- docs/PROGRESS.md | 70 +-- docs/experiments/24-door-to-file.md | 854 +++++++++++++++++++++++++++- 2 files changed, 888 insertions(+), 36 deletions(-) diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index e5f8f166..84466181 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -3496,50 +3496,50 @@ polygon, `mined_delta`/`mined_rejects` — в 17 конфигах из 31, по ### ХОЛОДНЫЙ ПРОГОН A — КНИГА ДОШЛА ДО КОНЦА (11.09, полигон-сессия, пак `POLYGON_COLD_RUN_A_SESSION_PROMPT.md`) **Строка бэклога 16 закрыта замером: доведённая до конца книга стоит $0.419424.** 蛊真人, главы 1–3, -zh→ru, от интейка до файла, прочитанного человеком. Отчёт (пре-рег + результаты) — -`docs/experiments/24-door-to-file.md`, инструменты — `eval/door_to_file/`, фризы `be53cc8` и `44b33d9`. +zh→ru, от интейка до файла, прочитанного человеком. Отчёт (пре-рег + результаты + три прохода +критиков) — `docs/experiments/24-door-to-file.md`, инструменты — `eval/door_to_file/`, фризы `be53cc8` +(пре-рег и инструменты) и `44b33d9` (драйвер); бинари собраны из кода `b0f5d89`. Сырые платные +выходы — `books/gu-zhenren/door-to-file/` (33 файла, не коммичены: репозиторий книг отдельный). - **Прогон:** 25 мин 31 с, две попытки (банк-стоп exit 3 → резюм exit 0), `status: ready`, `paused_reason` пусто, 4 юнита из 4 `translated`, `exports.complete = t` у txt (54 151 Б) и epub (20 187 Б). Сборка: семь полей чисты. Стоп-правила не срабатывали ни разу. -- **Деньги сошлись ШЕСТЬЮ путями** (движок 419 423 µUSD, платформа 419 424 — округление вверх при - конверсии), открытых резерваций 0. -- ⛔ **Четверть денег купила пустоту:** 4 вызова из 33 вернулись пустыми на потолке `max_tokens` - ($0.106472 = 25.4 %), включая самый дорогой вызов книги ($0.071009, `edit`/`deepseek-v4-pro`). - Движок лечит перевыпуском с удвоенным потолком — 4 раза из 4 успешно, то есть путь не рвётся, а - дорожает вдвое. Вторая точка того же явления (08.09 было 32 %). -- ⛔ **Терминологический контур оплачен дважды** (до стопа и после резюма): 15.6 % книги, из них - 6.9 % — второй заход. Разделения этих денег раньше не было. -- ⛔ **`run_attempts.spend_micro_usd` — величина накопленная:** сумма по попыткам завышает цену книги - на 38 %. -- **Множитель «смета движка → факт» = ×4.99** (0.084122 → 0.419424); на опорном прогоне 08.09 был ×3.6. -- **Строка бэклога 224 воспроизведена живьём:** на банк-стопе `.bank.json` несёт `terms: []` и - `proposed[]` из 69 термов; проекция платформы — 0 до закрытия прогона и 69 строк после. -- **Строка бэклога 406 получила первый прибор по ОТГРУЖЕННОМУ тексту** (`eval/door_to_file/spread.py`): - 0 терминов из 40 отданы более чем одной формой; слепое пятно прибора вскрыто и измерено (29 термов - из 69 не видит из-за склонения первого слова), рецепт починки — §13 отчёта. -- **Две находки про развёртывание, обе куплены даром:** книга, которую пайплайн переводит бесплатно, - НЕ ПРОДАЁТСЯ (`step_max_usd = 0` → `409 not_priced`); шаблон книги по рецепту стенда роняет каждый - старт `c1` без `langpack_root` (exit 10). Ряды заводит оркестратор. -- **Фриз-процедура пака была вырожденной:** бинарь из линкованного git-воркри не несёт `vcs.*` - вообще, и правило «отказать при `vcs.modified=true`» на нём выполняется всегда. Заменено клоном. +- **Деньги сошлись СЕМЬЮ путями** на 419 424 µUSD; ⚠ независимый среди семи — ОДИН: движок считает, + движок пишет, платформа материализует из его же потока. Открытых резерваций 0. +- ⭐ **ВПЕРВЫЕ КОНСИСТЕНТНОСТЬ ТЕРМИНОВ ЗАМЕРЕНА ПО ТЕКСТУ ЧИТАТЕЛЯ, а не по черновику.** Движок сам + называет две популяции вопроса (`spread≥2` — 9 термов, `INVENTED(no draft proposed it)` — 11, из + них 7 вне первой): **16 из 69**. Исход: **9 доехали формой банка · 6 отданы НЕ банковской формой + (`高脚吊楼`: банк «дом на сваях», в файле «свайный дом» ×4, главы 1 и 3) · 1 отдан двумя формами** + («церемония открытия апертуры» ×9 и «великая церемония…» ×1, обе в главе 1). Механизм работает и + работает не везде — и теперь у этого есть числа. Это прямой ответ на приоритет владельца №1. +- ⛔ **Четверть денег купила пустоту:** 4 вызова из 27 вернулись на потолке `max_tokens` + ($0.106472 = 25.4 %), три из них — РОВНО 0 символов ($0.094835 = 22.6 %), включая самый дорогой + вызов книги ($0.071009, `edit`/`deepseek-v4-pro`, 16 000 оплаченных выходных токенов). Движок лечит + перевыпуском с удвоенным потолком — 4 раза из 4 успешно: путь не рвётся, а дорожает вдвое. Вторая + точка того же явления (08.09 было 32 %). - ⛔ **Пин цены `deepseek-v4-flash` протух:** вендорская страница сегодня даёт вход 0.30 / cache-hit 0.006 / выход 1.20 против наших 0.44 / 0.014 / 1.32 (у `pro` совпадает точно). Прогон по живым числам стоил бы $0.397246 — **наш прайс завышает на 5.6 %**. Прогон шёл 01:29–01:54 UTC в пятницу, - то есть внутри вендорского пикового окна 01:00–04:00 UTC, — пиковое основание было верным. + внутри вендорского пикового окна 01:00–04:00 UTC ⇒ пиковое основание было верным. - ⛔ **`model_actual` = `deepseek-flash` на 28 строках из 33**, а шлём `deepseek-v4-flash`: нас считают под именем, которого в нашем реестре нет. Алиас это или другая модель — НЕ установлено. -- ⭐ **Подпись доехала до файла:** «горная крепость Гуюэ» 5 из 5 при нуле конкурирующих черновых форм - («городище Гуюэ» и прочие — 0); «Фан Юань» 38 + 20 склонений, конкурирующих транслитераций 0. - Контур банка отработал свои $0.0287 на отгруженном тексте. -- ⛔ **Отказы не видны через `err`** (пуст на всех 33 строках, включая четыре провальных) — только - через `degraded`; три вызова вернули РОВНО 0 символов на $0.094835 = 22.6 % прогона. - - -#### ⚠ ПИНГ ОРКЕСТРАТОРА №23 (10.09) — ПЯТЬ ЯКОРЕЙ В ВАШИХ ДОКАХ УКАЗЫВАЮТ НЕ ТУДА - -`docs/experiments/` — ваша зона, рукой не трогаю. Адреса пере-снял своим прибором по тому же токену: - +- ⛔ **Терминологический контур оплачен дважды** (до стопа и после резюма): 15.6 % книги, из них + 6.9 % — второй заход. Разделения этих денег раньше не было. +- ⛔ **Три ловушки для того, кто станет считать деньги по этим таблицам:** + `run_attempts.spend_micro_usd` — величина НАКОПЛЕННАЯ (сумма по попыткам завышает цену на 38 %); + `err` пуст на ВСЕХ 33 строках, включая четыре провальные (отказ виден только в `degraded`); + Σ `chunk_status.cost_usd` недобирает ровно терминологию ($0.354127 против $0.419423). +- **Строка бэклога 224 воспроизведена живьём:** на банк-стопе `.bank.json` несёт `terms: []` и + `proposed[]` из 69 термов; проекция платформы — 0 до закрытия прогона и 69 строк после. +- **Две находки про развёртывание:** книга, которую пайплайн переводит бесплатно, НЕ ПРОДАЁТСЯ + (`step_max_usd = 0` → `409 not_priced`); шаблон книги по рецепту стенда роняет каждый старт `c1` + без `langpack_root` (exit 10). Ряды 411 и 412 завёл оркестратор. +- **Фриз-процедура пака была вырожденной:** бинарь из линкованного git-воркри не несёт `vcs.*` + вообще, и правило «отказать при `vcs.modified=true`» на нём выполняется всегда. Заменено клоном. +- ⚠ **Круги НЕ сошлись:** три прохода критиков дали 13 → 4 содержательных находок, и третий нашёл, + что мой заказ следующей сессии чинил не ту функцию прибора, а знаменатель был не один. Всё внесено; + сходимость не объявляю. Слабое место прогона названо в §11 отчёта — прибор расхождения форм и то, + что защиты (стоп-правила, потолки) на боевой руке ни разу не выстрелили. - `00-provider-quirks.md:163` → `backend/internal/llm/httpllm.go:517-522` → **739–751**, токен `SystemMessagesSingle`; - `00-provider-quirks.md:164` → `backend/configs/models.yaml:137` → **173** (`system_messages: single`) и `backend/internal/llm/httpllm.go:528` → **750** (`func toOpenAIMessages`); diff --git a/docs/experiments/24-door-to-file.md b/docs/experiments/24-door-to-file.md index 8e2285e8..f1fd907c 100644 --- a/docs/experiments/24-door-to-file.md +++ b/docs/experiments/24-door-to-file.md @@ -104,6 +104,858 @@ * `eval/door_to_file/stub/` — $0-заглушка провайдера `local` (перенос штатной `fakeProvider` стенда). * `eval/door_to_file/zeropipe/` — рендер $0-пайплайна (перенос штатного `zeroCostPipeline`). -**Позитивный контроль каждого прибора исполнен ДО платной фазы** (§«Фаза 0» в результатах): подсаженный +**Позитивный контроль каждого прибора исполнен ДО платной фазы** (исход по пунктам — §18): подсаженный ненулевой банк, удержанный юнит и открытая резервация красят сборщик; книга с дырой красит отчёт сборки; чужой и беcштамповый бинарь красят гейт; самотест `spread.py` ловит подсаженную вторую форму. + +--- + +# РЕЗУЛЬТАТЫ (дописано ПОСЛЕ прогона; ничего выше не правлено) + +⭐ **ГЛАВНОЕ ПОМИМО ЦЕНЫ: впервые в проекте консистентность терминов замерена ПО ТЕКСТУ, КОТОРЫЙ +ПОЛУЧИЛ ЧИТАТЕЛЬ, а не по черновику и не по фикстуре — и ответ вышел не «всё хорошо», а СЧЁТ.** +Движок сам называет термины, у которых форма банка и форма черновика могли разойтись, и называет их +ДВУМЯ пометками в `bank-stop.txt`: `spread=N` (черновик дал N разных форм) — таких **9**, и +`INVENTED(no draft proposed it)` (форму банка не предложил НИ ОДИН черновик) — таких **11**, из них +**7** вне первой девятки. **Итого популяция вопроса — 16 терминов из 69.** Что с каждым стало в +отгруженном файле, проверено поимённо (§7.1 и §7.2): + +* **9 из 16** отданы формой БАНКА (`古月山寨` — 5 из 5 при трёх черновых формах, `甲等资质` — 6 при + трёх, `三转蛊师`, `魔道巨擘`, `丙等`, `乙等资质`, `江城子`, `邪魔`, `话事人`); +* **6 из 16** отданы одной формой, но НЕ банковской (`高脚吊楼`: банк «дом на сваях» — в файле + «свайный дом» ×4, главы 1 и 3; `凤雏`: банк «Молодой Феникс» — в файле «Юный Феникс», глава 2; + `老嬷嬷`: банк «старая мамка» — в файле «нянька» ×2, глава 3; плюс три коротких формы); +* **1 из 16** отдан ДВУМЯ формами («церемония открытия апертуры» ×9 в главах 1–3 и «великая + церемония открытия апертуры» ×1 в главе 1 — обе формы сосуществуют в одной главе). + +⇒ **Механизм РАБОТАЕТ и работает не везде, и теперь у этого есть числа.** Счёт форм, не суждение о +качестве. Разбор — §7.1 и §16.8; цена контура — §5.3. + +**Книга дошла до конца.** 蛊真人, главы 1–3, zh→ru, прогон `run_FTHA7S6SUCJIXS2A` над книгой +`bk_ROEHZBD46ALFI43E`: старт 04:29:19, финиш 04:54:50 (**25 мин 31 с**), две попытки (банк-стоп и +резюм), `status = ready`, `paused_reason` пусто, `failure_reason` пусто. Все **4** юнита `translated`, +`exports.complete = true`, файл скачан и прочитан. + +## 5. Что стоила доведённая до конца книга + +**$0.419424** — и по платформе, и по движку. ⛔ **ПЕРВАЯ РЕДАКЦИЯ ЭТОГО АБЗАЦА БЫЛА НЕВЕРНА, снимаю +её:** я написала «419 424 по платформе против 419 423 по движку, разница — округление при конверсии». +Расхождения нет вовсе. **419 423 — это МОЙ floor от float-суммы `request_log`, и такого числа нет ни в +одном артефакте движка.** Движок объявляет свою цифру сам, кадром `spend`: последний кадр +`events.jsonl` несёт `{"committed_micro_usd": 419424}`, и он ceil-ит КАЖДОЕ накопительное значение +(первый кадр: 12045 при 12044.12). Поймал критик чисел; я приписала платформе округление, которое +делает движок, и выдумала несуществующее расхождение между ними. + +**Семь путей счёта, и все семь сошлись:** + +| Путь | µUSD | +|---|---| +| Σ `request_log.cost_usd` (движок, телеметрия; дробное) | 419 423.288 | +| `spend.committed_usd` (движок; дробное) | 419 423.288 | +| Σ `checkpoints.cost_usd` (движок, 33 чекпойнта; дробное) | 419 423.288 | +| **кадр `spend` движка, последний** (`events.jsonl`) — целое, движок ceil-ит | **419 424** | +| Σ `credit_ledger.settlement` платного аккаунта | **419 424** | +| грант − баланс того же аккаунта | **419 424** | +| `run_attempts.spend_micro_usd` ПОСЛЕДНЕЙ попытки | **419 424** | + +⚠ Три дробных пути — это ОДНО число 419 423.288, не три разных; четыре целых — то же число после +ceil, который делает движок на каждом кадре. Спора между ними нет и не было. + +⚠ **И сразу честно про эти «семь путей»: независимый среди них ОДИН.** `request_log`, `checkpoints` и +`spend` — три записи одного и того же вычисления движка; `settlement` и баланс — два чтения одного +леджера; а сам леджер взял число У ДВИЖКА (через `run_attempts.spend_micro_usd` ← кадр `spend`). +Сходимость доказывает, что никто по дороге ничего не потерял и не удвоил, — и ровно это, не больше. + +⛔ **Ловушка, на которую я наступила и называю: `spend_micro_usd` попытки — величина НАКОПЛЕННАЯ, а не +приращение.** Сумма по попыткам даёт 579 635 µUSD — на 38 % больше правды, потому что вторая попытка +несёт в себе первую (`spend_baseline_micro_usd` второй попытки = 160 211 = вся трата первой). Кто +просуммирует эту колонку по попыткам, получит завышенную цену книги и не заметит. + +**Открытых резерваций на конце — 0** (контроль: резерваций этого аккаунта любого состояния — 2). + +### 5.0. Что сообщил САМ провайдер — токены, а не доллары + +Доллары в этом отчёте посчитаны нами (§16.1). Провайдер сообщил вот это, и только это: + +| модель | вызовов | вход | из них из кэша | выход | +|---|---|---|---|---| +| `deepseek-flash` | 22 | 71 244 | 22 784 | 126 751 | +| `deepseek-v4-pro` | 5 | 29 175 | 9 088 | 51 403 | +| **итого** | **27** | **100 419** | **31 872** | **178 154** | + +**41 488 выходных токенов (23.3 % всего выхода) куплены четырьмя ответами, которые были выброшены.** +⚠ Колонка `reasoning_tokens` равна нулю на **всех 33 строках**. Что это значит — вендор её не +отдаёт, или наш адаптер её не разбирает — по этим данным НЕ РАЗЛИЧИТЬ, и я не гадаю. Практическое +следствие одно и оно твёрдое: **«сколько из выхода было размышлением» по нашей телеметрии не видно ни +на одном вызове**; видно только, что выход упирался в потолок. Для мины §5.2 это существенно — +причину «размышление съело потолок» мы читаем из журнала движка (`reason=empty`), а не из счётчиков. + +### 5.1. Куда ушли деньги + +| Стадия и роль | вызовов | $ | +|---|---|---| +| `draft` / translator (`deepseek-v4-flash`) | 15 | 0.123656 | +| `edit` / editor (`deepseek-v4-pro`) | 5 | 0.230471 | +| `terminology` / classifier | 6 | 0.035803 | +| `terminology` / terminologist | 7 | 0.029494 | +| **итого** | **33 строки = 27 ВЫЗОВОВ + 6 подстановок из чекпойнтов** | **0.419423** | + +⚠ Сумма четырёх округлённых подытогов даёт 0.419424 — на 1 µUSD больше настоящего итога 0.419423. +Это округление ЧЕТЫРЁХ строк до шестого знака, а не потерянный вызов: при полной точности подытоги +0.123656064 + 0.230470592 + 0.035802968 + 0.029493664 = 0.419423288. Названо, чтобы читатель не искал +пропавший цент. + +### 5.2. ⛔ ЧЕТВЕРТЬ ДЕНЕГ КУПИЛА ПУСТОТУ + +**4 вызова из 27 вернулись с `finish_reason = length` и `ok = 0`, и стоили $0.106472 — 25.4 % всей +траты книги.** (Строк в `request_log` 33, но шесть из них — бесплатные подстановки из чекпойнтов, а не +вызовы: «вызовов 27» и «строк 33» — разные величины, и первая редакция отчёта их смешивала.) Это ровно задокументированная мина `00-provider-quirks.md` §катовер п.1–2: размышление +съедает `max_tokens`, `content` приходит пустым. Поимённо: + +| id | стадия / место | модель | `max_tokens` на входе | флаг движка | $ пустого вызова | перевыпуск | $ перевыпуска | +|---|---|---|---|---|---|---|---| +| 1 | draft ch1/chunk0 | `deepseek-v4-flash` | **8496** | `empty` | 0.012044 | **16992** | 0.021068 | +| 5 | draft ch2/chunk1 | `deepseek-v4-flash` | **8496** | `length` | 0.011637 | **16992** | 0.017260 | +| 7 | draft ch3/chunk0 | `deepseek-v4-flash` | **8496** | `empty` | 0.011782 | **16992** | 0.018656 | +| 31 | **edit ch2/chunk0** | **`deepseek-v4-pro`** | **16000** | `empty` | **0.071009** | **32000** | 0.046861 | + +⚠ **Флага ДВА, и они разные:** `empty` — ответ пуст (размышление съело весь потолок), `length` — текст +оборван на потолке. В `request_log` оба приходят как `finish_reason = length`, то есть по одной +телеметрии их не различить — различает их журнал движка (`disposition=flagged reason=…`). +⚠ **На edit пустой вызов дороже своего же удачного повтора** ($0.071009 против $0.046861 при вдвое +большем потолке): неудачный сжёг весь бюджет 16000 токенов на размышление и молчал 249 секунд. + +⚠ **Самый дорогой одиночный вызов прогона не дал ничего.** $0.071009 — это 17 % бюджета книги, и +это ровно тот класс, про который `pipeline-c1.yaml:81` пишет в комментарии: «thinking ate max_tokens: +content="", finish=length». Конфиг ставит на draft `reasoning: "low"` именно против этой мины — +**мина сработала ВСЁ РАВНО, и на draft (3 раза), и на edit, где ручка не выставлена вовсе.** + +⭐ **Но лечение в движке ЕСТЬ и оно работает:** `stage flagged, regenerating with a larger budget … +reason=empty next_max_tokens=16992` — движок опознаёт пустой ответ как флаг `empty` и перевыпускает +вызов с удвоенным потолком. Все четыре раза второй вызов вернул текст. То есть путь не рвётся — он +дорожает: **платим дважды и выкидываем первый платёж.** + +### 5.3. Терминологический контур оплачен ДВАЖДЫ + +Роли банка исполнились до банк-стопа (строки 10–16, $0.036554) **и снова после резюма** (строки 23–28, +$0.028742). Итого $0.065297 — **15.6 % книги** ушло на контур банка, и **$0.028742 (6.9 %) — это второй +заход того же контура на той же книге**. Заново ли он нужен после движения банка — вопрос к движку; +здесь он просто НАЗВАН и посчитан, потому что раньше эту цену никто не отделял. + +### 5.4. Смета против факта — второй замер множителя + +| Оценка | $ | множитель к факту | +|---|---|---| +| `expected_usd` движка (нижняя граница по построению: без ретраев и ремонта) | 0.084122 | **×4.99** | +| Ожидание пака, ИСПР. 16 дословно | **0.35–0.50**, хвост до 0.65 | факт **внутри вилки** | +| Вилка оркестратора по историческому множителю ×3.6 от прогона 08.09 (релей 11.09) | 0.30–0.49 | факт **внутри вилки** | +| **ФАКТ** | **0.419424** | — | + +⚠ **У «ожидания» три написания, и они различаются на 2 µUSD — назову, чтобы это не читалось как спор:** +сумма глав манифеста **84 120** · строка `books` (`expected_micro_usd − book_once_micro_usd`) **84 121** · +ответ `run-options` **84 122**. Множитель посчитан от 84 122 (то, что видит покупатель); от 84 120 он +был бы ×4.9860 вместо ×4.9859 — на вывод это не влияет, а на доверие к числам влияет. + +⇒ Множитель «смета движка → факт» на этой книге **×4.99** при ×3.6 на опорном прогоне 08.09. Это +ВТОРАЯ точка, а не подтверждение: две точки дают разброс, а не закон. Причина расхождения названа +выше — четверть траты ушла на пустые ответы, которых смета не знает по построению. + +## 6. Исход каждой строки пре-рег-таблицы + +| # | Узел | Ожидание | ФАКТ | Сошлось | Чем предъявлено | +|---|---|---|---|---|---| +| 1 | стенд мой | pid на порту | `tmplatformd` pid 1049523 на 8097; на 11434 не слушает НИКТО (контроль: 7 слушателей на хосте) | ✅ | `ss -ltnp` | +| 2 | код из фриза | три условия | `vcs.revision=b0f5d89…`, `modified=false`, строк `vcs.*` = 3 у всех трёх бинарей | ✅ | `go version -m` | +| 3 | гость и деньги | грант одной строкой | `u_ZWUVTETPZL2D6LML`, грант 2 500 000 µUSD, строка `kind='grant'` | ✅ | `credit_ledger` | +| 4 | интейк | 201, 3 главы, `character_count` ≈ 8759 | `chapter_count: 3` ✅; `character_count: 9677`, а 8759 — это `source_chars` ⚠ | ✅ по главам, **пин по знакам удовлетворён ДРУГИМ полем** | тело 201 + `books` | + +⚠ **Пин строки 4 как он был написан — НЕ сошёлся, и это надо сказать прямо.** Я ждала ≈8759 от +`character_count`, а он равен **9677**: это счёт ИНТЕЙКА по байтам потока, и платформа сама называет +его приблизительным (`internal/pgstore/books.go`, и на проводе рядом едет `character_count_exact`). +Точный счёт знаков живёт в `source_chars` = 8759 и сошёлся с манифестом до единицы. Дефекта нет, +но пин был написан на поле, которое на него не отвечает. +| 5 | срез совпал | `units_total` 4, по главам 2/1/1 | 4, по главам 2/1/1 | ✅ | `chapters`+`units` | +| 6 | цена и бонд | `funded: true`, холд ≈2 241 629 | `funded: true`, `covers_all`, холд **2 241 631**, expected **84 122** | ✅ (мимо на 2 µUSD) | `run-options` | +| 7 | старт | 202 + `bond_funded=t` | 202; `runs.bond_funded = t` | ✅ | ответ + `runs` | +| 8 | ключи живы | первый вызов не отказан | первый вызов оплачен ($0.012044), отказов по авторизации 0 из 33 | ✅ | `request_log.err` пусто во всех 33 строках | +| 9 | кадры | шесть типов | 50 кадров: `hello` 2 · `progress` 10 · `spend` 27 · `unit_done` 8 · `bank_stop` 1 · `finished` 2 | ✅ | `events.jsonl` | +| 10 | банк-стоп | `awaiting_bank`, exit 3, непустой `proposed[]` | наступил в 04:39; exit 3; `proposed[]` = **69** термов, `terms[]` = 0 | ✅ | `runs` + `run_attempts` + копия сайдкара | +| 11 | проекция банка | 0 до закрытия, >0 после | **0** в момент `awaiting_bank`; **69** строк (2 `approved`) после | ✅ | `GET /v0/books/{id}/bank` дважды | +| 12 | дверь правок | preview → apply → файл решений | `changed: true`, оба решения `state: applied`, `mined-delta.yaml` 886 байт | ✅ | тело ответа + файл | +| 13 | резюм | вторая попытка, exit 0 | попытка 2, exit 0, `last_seq` 22 | ✅ | `run_attempts` | +| 14 | книга переведена | 4 юнита `translated` | 4 из 4 (контроль: юнитов книги — 4) | ✅ | `units` | +| 15 | сборка | семь полей чисты | `complete: true`, `pending/withheld/incomplete/stale/ghost = 0`, `stale_unknown: false`, `config_drift: false`, `total_units: 4` | ✅ | stdout `tmctl build` | +| 16 | выгрузка | `complete = t`, байты сходятся | txt: 54 151 байт, `complete = t`; epub: 20 187 байт, `complete = t` | ✅ | `exports` + `%{size_download}` | +| 17 | ФАЙЛ | байты + структура | txt sha256 `c3dcf291…`; epub sha256 `720fd782…`, 7 записей zip, `nav` объявлен, 3 itemref, оглавление «Глава 1/2/3» | ✅ | разбор zip | +| 18 | человек прочитал | связный русский | прочитан первый разворот главы 1 — связный русский текст, имена согласованы с подписанным банком | ✅ | цитата ниже | +| 19 | деньги сошлись | четыре счёта + 0 резерваций | **семь** счётов сошлись на 419 424 µUSD (§5), открытых резерваций 0 при 2 резервациях этой учётки; ⚠ независимый среди семи — один | ✅ | таблица §5 | +| 20 | ничего не реплеено | нет `local-*` | `distinct model_actual` = `deepseek-flash`, `deepseek-v4-pro`; `tm_hit = 1` у 6 строк, ВСЕ шесть — `banknote_export` второй попытки, все по $0 | ✅ | `request_log` | +| 21 | расхождение форм | замер | **0 терминов из 40 отданы более чем одной формой** (контроль: канонических термов 69, найдено в тексте 40); прямой счёт по двум подписанным термам — 5 из 5 и 58 из 58 в одной форме, конкурирующих 0 (§16.8) | замер | `spread.py` + счёт по `book.txt` | + +**Первый абзац отгруженного файла (узел 18), дословно:** + +> Пусть тело погибнет — сердце демона не раскается. +> — Фан Юань, покорно отдай Цикаду Весны и Осени, и я дарую тебе лёгкую смерть! + +Это связный русский текст. **О качестве перевода пак суждений не делает** (претрейн). + +## 7. Счёт расхождения форм по ОТГРУЖЕННОМУ тексту (строка бэклога 406) + +`spread.py` над `tmctl export --json --pairs`: **69** канонических термов, у всех 69 исходник +встречается в тексте, **40** найдены отрендеренными, и из этих сорока **НИ ОДИН не отдан более чем +одной формой**. + +### 7.1. ⛔ ЗНАМЕНАТЕЛЬ ЛЕЖАЛ В МОЕЙ ЖЕ УЛИКЕ, И БЕЗ НЕГО «0» НИЧЕГО НЕ ЗНАЧИЛ + +«0 из 40» отвечает на вопрос «нашёл ли прибор разнобой среди того, что видит». Настоящий вопрос +другой: **что стало с теми терминами, про которые ИЗВЕСТНО, что они разошлись.** Ответ лежал в +`evidence/bankstop-paid/project.db.bank-stop.txt`, который я сняла в момент стопа и не дочитала: +движок печатает там `spread=N` и перечисляет черновые формы по КАЖДОМУ терму. + +**Распределение: `spread` 1 → 60 · 2 → 6 · 3 → 2 · 4 → 1** (контроль: записей `spread=` ровно 69, по +числу термов). ⇒ **разошлись в черновике 9 терминов из 69.** Проверила все девять по отгруженному +файлу (поиск по стемам слов, каждое попадание открыто глазами): + +| термин | черновик дал | подписано/сведено | в отгруженном файле | исход | +|---|---|---|---|---| +| `三转蛊师` | 2 формы | «гу-мастер третьего оборота» | 3 · конкурент 0 | ✅ одна форма | +| `古月山寨` | **3** формы (поселение · городище · горная крепость) | «горная крепость Гуюэ» **подписана мной** | 5 (главы 1 и 2) · конкуренты 0, 0 | ✅ одна форма | +| `甲等资质` | 3 формы (дар цзя · дарование первого ранга · талант класса А) | «талант первого разряда» | 6 · конкуренты 0, 0, 0 | ✅ одна форма | +| `魔道巨擘` | 2 формы | «корифей пути демонов» | 2 · конкурент 0 | ✅ одна форма | +| `高脚吊楼` | 2 формы | «дом на сваях» | **0**, зато «свайный дом» **×4** (главы **1 и 3**) | ⛔ в файле НЕ банковская форма | +| `家老` | 2 формы | «старейшина рода» | 0; в тексте «старейшины» ×13 без «рода» | ⚠ короткая форма, последовательно | +| `舅母` | 2 формы | «жена дяди по матери» | 0; в тексте «тётя» ×16 | ⚠ короткая форма, последовательно | +| `舅父舅母` | 2 формы | «дядя по матери и его жена» | 0; «дядя с тётей» | ⚠ короткая форма, последовательно | +| `开窍大典` | `spread=4`, перечислено **3** формы | «церемония открытия апертуры» | 9 (главы 1·2·3) + «великая церемония открытия апертуры» ×1 (**глава 1**) | ⛔ ДВЕ формы, и обе в одной главе | + +**⇒ 4 из 9 сведены и доехали · 4 из 9 отданы одной, но НЕ банковской формой · 1 из 9 отдан двумя.** +⚠ **Главы названы, как требует §4.5 п.2 пака, и они меняют смысл двух строк:** обе формы `开窍大典` +живут в ОДНОЙ главе (читатель встречает разнобой на одной странице), а не-банковский «свайный дом» +идёт через главы 1 и 3 — то есть последовательно по всей книге. + +⚠ И самое важное из этой таблицы: **`高脚吊楼` — случай, где закон банка на проводе (`D39.104`: банк +есть закон для ВСЕХ строк независимо от статуса) в тексте не виден.** Банк нёс «дом на сваях», файл +несёт «свайный дом» четырежды. Доехал ли банк до промпта редактора на этих юнитах, по БД **не +ответить**: у редакторской стадии нет своего счётчика подтверждённых инъекций (`n_exact_hits` и +`injected_ids` заполняются на черновике, где глоссарий ещё пуст). **Замерено** — расхождение формы; +**не установлено** — где именно оно возникло. + +⛔ **Слепое пятно прибора я вскрыла, а не спрятала: 29 термов из 69 прибор не нашёл вовсе, и это его +слабость, а не свойство книги.** Открыла глазами восемь таких единиц: `三转蛊师` отгружен как +«гу-мастера третьего оборота», `丫头片子` — «девчонку», `仙师` — «бессмертными наставниками», +`侧室` — «наложницей». Каноническая форма В ТЕКСТЕ ЕСТЬ, но склонена — а прибор её не видит. +⇒ «0 форм-расхождений» — утверждение о сорока термах, которые прибор видит, а не обо всех шестидесяти +девяти. + +⛔⛔ **И ПРИЧИНУ СЛЕПОТЫ Я НАЗВАЛА НЕВЕРНО — это доказано исполнением, не спором.** Первая редакция +писала, что виновато правило сравнения общих префиксов (`same_rendering`), и заказывала следующей +сессии переписать именно его. Критик полноты применил мой же рецепт к прибору на этих самых данных: +**не вернулся НИ ОДИН из 29 потерянных термов** (осталось те же 40). Потому что `same_rendering` +участвует только в СКЛАДЫВАНИИ уже найденных форм, а теряются они раньше — на ПОИСКЕ кандидатов: +`spread.py` берёт кандидатов регуляркой `[А-ЯЁ][а-яёА-ЯЁ\-]+`, то есть **только слова С ЗАГЛАВНОЙ**. +«гу-мастера», «девчонку», «наложницей» — строчные и отпадают ДО того, как правило сравнения вообще +спросят. Починка генерации кандидатов (окна нужной длины, любой регистр) на тех же данных даёт +**48 найденных вместо 40** — то есть слепое пятно действительно ЗДЕСЬ. ⇒ мой «0» держался в том +числе на том, что прибор не смотрел, и правильный заказ следующему — §13, переписан. + +⛔ **Но число расхождений у починенной копии я публиковать не стала, и вот почему — пере-снято +своими руками, а не принято от критика.** Критик сообщил «шесть строк со `spread ≥ 2`»; моя +реализация той же починки даёт **девять**, и все девять — мусор: оконный поиск глотает соседние +слова и считает каждое окно отдельной формой («старейшины и», «старейшин Он», «Фан не», «глава рода +он»). ⇒ **покрытие 40 → 48 — замер; счёт расхождений у починенного прибора — шум.** Улика: +`checks/spread-candidate-fix-probe.txt`, где рядом стоят вывод фриза (0) и вывод копии (9) и назван +недостающий кусок: окну нужен ФИЛЬТР, отвергающий лишние слова. + +### 7.2. ⛔ ЗНАМЕНАТЕЛЬ ОКАЗАЛСЯ НЕ ОДИН: движок называет ВТОРУЮ популяцию, и я её пропустила + +`spread=N` отвечает на вопрос «разошлись ли ЧЕРНОВИКИ между собой». Он по построению НЕ ловит терм, у +которого все черновики согласны — и все согласно расходятся с банком. Такие термы движок помечает +отдельно, тем же файлом: **`INVENTED(no draft proposed it)` — форму банка не предложил ни один +черновик.** Их **11 из 69**; четыре уже внутри девятки, **семь — вне её**, и вопрос у них ровно тот +же. Проверила все семь (контроль: `INVENTED` встречается в стоп-таблице 11 раз при 69 записях +`spread=`): + +| терм | банк | что в файле | исход | +|---|---|---|---| +| `丙等` | «третий разряд» | 3 (черновиковый «третий ранг» — 0) | ✅ банк | +| `乙等资质` | «талант второго разряда» | 2 | ✅ банк | +| `江城子` | «Цзянчэнцзы» | 1 («Река Цзянчэн» — 0) | ✅ банк | +| `邪魔` | «злой демон» | 2 («злого демона», «злым демоном») | ✅ банк | +| `话事人` | «распорядитель» | 1 («распорядители» — и черновик, и склонение банка) | ✅ банк | +| **`凤雏`** | **«Молодой Феникс»** | **0**; в файле «Юный Феникс» ×1 (глава 2) — ЧЕРНОВИКОВАЯ форма | ⛔ не банк | +| **`老嬷嬷`** | **«старая мамка»** | **0** («мамк\*» в файле 0); «нянька/няньку» ×2 (глава 3) | ⛔ не банк | + +⛔ **Моя ошибка по дороге, названная: `邪魔` я сперва посчитала «не банковским».** Мой стеммер режет +хвост по длине слова и на прилагательном «злой» промахивается мимо «злого/злым» — счёт дал 0. +Открыла текст глазами: обе формы на месте. **Инструмент промахнулся в сторону ложной тревоги, а не +ложного спокойствия**, но промахнулся. + +⇒ **Объединённая популяция — 16 терминов из 69: 9 доехали формой банка · 6 отданы не-банковской +формой · 1 отдан двумя.** И главное следствие для §13: **знаменатель у прибора по отгруженному +тексту обязан быть ДВОЙНОЙ** — `spread ≥ 2` И `INVENTED`. На `spread` одном половина случаев не +видна, включая два из шести. + +## 8. Находки прогона — с разметкой уверенности + +| # | Находка | Где | Разметка | +|---|---|---|---| +| 1 | **Бинарь, собранный в ЛИНКОВАННОМ git-воркри, не несёт `vcs.*` ВООБЩЕ** (0 строк из 24), и правило «отказывать при `vcs.modified=true`» на нём выполняется всегда. Контроль: та же сборка из главного дерева даёт `vcs.revision` + `modified=true` | фриз-процедура пака | **замерено** | +| 2 | **Книга, которую пайплайн переводит бесплатно, не может быть продана.** На $0-паре `step_max_usd = 0`, `ingest.Manifest.priced()` отказывает при `<= 0` ⇒ `409 not_priced`, старт недостижим; в логе ERROR «this book has no price projection, so it cannot be sold» | `internal/ingest/manifest.go:349` | **замерено** | +| 3 | **Шаблон книги по рецепту стенда роняет КАЖДЫЙ старт `c1`:** без `langpack_root` движок отказывает с exit 10 «gates.terminology is enabled but this book cannot mine a bank». Ключа нет ни в `backend/example/book.yaml`, ни в рецепте `STACK_DECISIONS` | `internal/pipeline/runner.go:358` | **замерено** | +| 4 | **Четверть денег купила пустоту** — 4 вызова из 33, $0.106472, все `finish_reason=length`; самый дорогой вызов книги ($0.071009) не дал ничего. Лечение в движке есть и сработало 4/4: перевыпуск с удвоенным потолком | §5.2 | **замерено** | +| 5 | **Терминологический контур оплачен дважды** (до стопа и после резюма): $0.036554 + $0.028742 | §5.3 | **замерено** | +| 6 | **`run_attempts.spend_micro_usd` — величина накопленная**; сумма по попыткам завышает цену книги на 38 % | §5 | **замерено** | +| 7 | **Ответ старта прогона говорит `term_consistency_funded: false`, когда строка прогона уже несёт `bond_funded = t`** — и через минуту тот же прогон на `resume` отвечает `true`. Наблюдено на обоих прогонах (дымовом и платном) | `POST /v0/books/{id}/runs` | **замерено** (причина — **подозрение**: ответ, вероятно, рендерится из состояния ДО допуска) | +| 8 | **`409 not_priced` сразу после интейка — гонка, а не дефект:** проекция цены материализуется асинхронно, через несколько секунд ручка отвечает нормально. Клиент, спросивший сразу, увидит отказ | `run-options` | **замерено** | +| 9 | **Строка бэклога 224 воспроизведена живьём:** на банк-стопе `.bank.json` несёт `terms: []`, `total: 0` и `proposed[]` с **69** термами; платформа читает `terms` ⇒ экран подписи видит 0 ровно тогда, когда открыт ради этих 69 | улика `evidence/bankstop-paid/` | **замерено** | +| 10 | **`TM_PLATFORM_ENGINE_CEILING_ARG` пустым старты не ломает** — у переменной есть дефолт `--ceiling-usd {{usd}}`; прогон прошёл целиком, пока она не задана | `internal/config/config.go:550` | **замерено** | +| 11 | Резюм после банк-стопа **не берёт второй книжный бонд**: холд 2 081 420 = 2 241 631 − 160 211, то есть остаток бюджета этого прогона | `credit_ledger` id 15 | **замерено** | +| 12 | Улика банк-стопа **уничтожается резюмом**: sha256 `.bank.json` `8fdd7d54…` на стопе → `0881055a…` после резюма (и после двери правок она ещё цела) | три sha подряд | **замерено** | +| 13 | **Пин цены `deepseek-v4-flash` в `models.yaml` выше сегодняшней вендорской страницы** (вход 0.44 против 0.30, cache-hit 0.014 против 0.006, выход 1.32 против 1.20); у `pro` совпадает точно. Этот прогон по вендорским числам стоил бы $0.397246 вместо $0.419423 — пин завышает на **5.6 %** | §16.1, вендор-дока снята 11.09 | **замерено** (что пин стал выше страницы) + **прочитано** (сама страница) | +| 14 | **`model_actual` = `deepseek-flash` на 28 строках из 33**, тогда как шлём `deepseek-v4-flash` и такого слага в вендорской прайс-таблице нет — нас считают под другим именем | `request_log`, две колонки | **замерено** (факт), **не установлено** (алиас или другая модель) | +| 15 | **`err` пуст на всех 33 строках, включая четыре провальных** — признак отказа живёт только в `degraded`. Аудит, написанный через `err`, прочитает прогон как чистый | `request_log` | **замерено** | +| 16 | **Три вызова вернули РОВНО 0 символов** (`length(response_text) = 0` в чекпойнтах): $0.094835 = 22.6 % прогона. Флор `min_max_tokens: 16000`, поднятый именно против этого, дал ОДИН такой вызов на 16.9 % счёта — больше, чем инцидент, ради которого его поднимали | `checkpoints`, `models.yaml` | **замерено** | +| 17 | **`accept_rebill_micro = 2 241 631` на резюме** — согласие на пере-оплату всего бюджета прогона при фактической пере-покупке $0.028742 (разрыв 78×); спасли чекпойнты | `runs` | **замерено** | +| 18 | **Σ `chunk_status.cost_usd` = $0.354127**, недостача — ровно терминология: таблица выглядит пятым путём счёта денег и им не является | `project.db` | **замерено** | +| 19 | ⭐ **Подписанные термины доехали до файла:** «горная крепость Гуюэ» 5 из 5, конкурирующие черновые формы 0; «Фан Юань» 38 + 20 склонений, конкурирующих транслитераций 0 | §16.8, счёт по `book.txt` | **замерено** | + +## 9. «Дыр нет» — замерено, а не промолчано + +Дверь выгрузки СТРОИТ ВСЕГДА (`--partial`, `D39.178`), поэтому «файл собрался» само по себе не значит +ничего: неполная книга ушла бы тем же 200 и с теми же байтами, только с пометкой внутри. Пометка — +данные языка ЧИТАТЕЛЯ (`configs/langpacks/ru/reader.txt`), и она проверяется на отсутствие вместе с +контролем, который доказывает, что искали существующее: + +| файл | строк с `⚠` | «ещё не переведён» | «Перевод не завершён» | всего строк | +|---|---|---|---|---| +| **отгруженный `book.txt`** | **0** | **0** | **0** | 330 | +| та же книга, собранная из её ПРЕД-ПРОГОННОЙ копии БД (контроль) | **5** | 4 | 1 | 20 | + +Контрольная сборка — тот же бинарь, тот же langpack, та же книга, только БД из `backups/` до прогона: +`complete: false`, `pending_units: 4`, и файл честно говорит читателю: «⚠ Перевод не завершён: +фрагментов с пропусками — 4 из 4. Каждый пропуск отмечен в тексте знаком ⚠». ⇒ ноль в первой строке +таблицы — измеренный ноль, а не молчащий прибор. + +## 10. Что НЕ удалось, не проверено и не измерено + +0. ⛔ **ВЕРНЫЕ ЧИСЛА ПРИ НЕВЕРНОМ МЕТОДЕ — и это худшее, что случилось в моей работе, потому что оно + не краснеет нигде.** Разбивку попыток я строила по ВРЕМЕНИ (`ts` против `started_at`), а `ts` в + sqlite секундной гранулярности: `01:40:45` против `01:40:45.012584` — все шесть подстановок + формально «раньше» старта своей же попытки. Числа при этом вышли правильные, по счастливому + порядку строк. До этого тот же метод сломался грубее (пробел против `T` в разделителе дал 33/0), и + я его «починила», не заметив, что он негоден в принципе. **Настоящий различитель лежал в той же + строке и не требует арифметики вовсе: `trace_id` несёт номер попытки.** Нашёл критик чисел; сама + бы я не нашла — верный результат не даёт повода перепроверить способ, которым он получен. +1. **`epubcheck` не гонялся.** `java` на хосте нет, поставить без sudo не пробовала (пак это прямо + разрешает — ИСПР. 6). EPUB судится структурно: zip · `mimetype` · `container.xml` · `nav` · + 3 `itemref` · оглавление. Валидность по спецификации EPUB — **не измерена**. +2. **Эскалация не исполнялась ни разу** — `escalation.budget_usd: 0` в боевом конфиге. Про её работу + этот прогон не говорит НИЧЕГО. +3. **Гейт `coverage` выключен** (`gates.coverage.enabled: false`) — работали четыре гейта из пяти. + Судейской стадии на этом пути нет вовсе. +4. **Одна книга, одна пара, три главы, четыре юнита.** Множитель «смета → факт» ×4.99 — это ОДНА + точка (вторая в проекте). Двух точек мало для закона, и обе сняты на одном исходнике. +5. **Причина расхождения `term_consistency_funded` на старте не установлена** (находка 7): замерено, + что ответ `POST /runs` говорит `false`, когда строка прогона уже несёт `bond_funded = t`; ПОЧЕМУ — + подозрение (вероятно, ответ рендерится из состояния до допуска), кодом не подтверждено. +6. **Нужен ли второй заход терминологического контура — не выяснено.** Замерено, что он случился и + сколько стоил; законен ли он после движения банка — вопрос к движку, не к этому прогону. +7. **Прибор расхождения форм видит 40 термов из 69** (§7). «0 расхождений» — утверждение о сорока. +8. **Книжный потолок ($1.25) и стоп-правила ни разу не срабатывали** — трата $0.419. Значит их + поведение этим прогоном НЕ проверено: они стояли, но не стреляли. +9. **Ручка `POST /runs/{id}/stop` не трогалась вовсе.** +10. **Про качество перевода не сказано ничего и не может быть сказано** — 蛊真人 в претрейне. +11. **Дымовая фаза считала НОМИНАЛЬНЫЕ деньги.** Локальной модели дана цена (иначе книга не + продаётся — находка 2), поэтому суммы дымового аккаунта — это арифметика механизма, а не траты. + Платный аккаунт заведён отдельно, и в денежную сверку §5 дымовые строки не входят. +12. ⛔ **НИ ОДНО HTTP-ТЕЛО ПЛАТНОГО ПРОГОНА НЕ СОХРАНЕНО, и я узнала это от критика, а не от себя.** + Под `evidence/` 61 файл, и ни в одном нет `covers_all`, `term_consistency_funded`, + `affordable_chapters`, `accepted`, `ordered_chapters`. Уцелели только `capabilities.json` и + `bank-after.json`. ⇒ висят без носителя: ответ `run-options` (узел 6; сам ХОЛД предъявлен строкой + `reservations`, а тело — нет) · `202` старта (узлы 7 и 13; в `runs` и логе демона есть «run + admitted … ordered_chapters:3» — это сильнее нуля, но не то тело) · `changed: true` и + `state: applied` двери правок (узел 12; уцелел ЗАПРОС `stand/corrections.json`, ответ — нет) · + и целиком **находка 7 §8**, которая ТОЛЬКО из тела ответа и состоит. Драйвер печатал их на экран + и не писал в файл — это дефект моего харнесса, а не прогона, и чинить его надо в `drive.sh` + (каждый ответ ручки — в `evidence/http/<шаг>.json`). +13. **Слабость МОЕГО прибора живости:** `drive.sh watch` печатал `max(last_seq)` по попыткам, и + во время второй попытки число выглядело замершим на 28 (значении первой), пока работа шла. + Читать надо по попыткам — что я и делала во второй половине вахты. + +## 11. Что я сама считаю слабым местом этого прогона + +**Первое и главное: счёт расхождения форм — самая новая и самая слабая цифра отчёта.** Всё остальное +здесь предъявлено механизмом, который писали не в этом паке; прибор §7 написан мной за час, и его +правило сравнения форм разваливается ровно там, где русский язык делает то, что делает всегда, — +склоняет первое слово. Его «0» я бы не понесла дальше без пере-строенного правила. + +**Второе: «сошлось семью путями» звучит сильнее, чем есть.** Шесть из семи путей — одна и та же +цепочка: движок посчитал, движок записал, платформа материализовала из его же потока. Настоящая +независимость в этом отчёте одна — **скачанные байты и их sha256**; провайдерского биллинга у нас нет +вовсе. ⛔ И вторую половину этой фразы я тоже переписываю после критика чисел: «$0.419424» — это даже +не то, что нам сказал провайдер. Провайдер сообщил ТОКЕНЫ; доллары мы умножили сами, на свой пин, и +пин на flash оказался выше вендорской страницы (§16.1). **Настоящее число — «столько-то токенов»; +доллары в этом отчёте — наша модель поверх них.** + +**Третье: прогон прошёл слишком гладко, чтобы проверить свои же защиты.** Стоп-правила, книжный +потолок, отказ допуска — всё это стояло заряженным и ни разу не выстрелило. Я проверила их подсадками +до денег (§4), но на боевой руке они остались непроверенными, и это надо помнить, а не записывать +себе в актив. + +## 12. Девиации от пака — объявлены, не подразумеваются + +1. **Фриз-дерево — локальный КЛОН, а не `git worktree add`.** Причина замерена: бинарь из линкованного + воркри несёт **0** строк `vcs.*` из 24 (контроль: та же сборка из главного дерева даёт + `vcs.revision` и `vcs.modified=true`), и правило «отказать при `vcs.modified=true`» на нём + выполняется ВСЕГДА. Клон даёт настоящий каталог `.git` и штамп с зубами. Санкционировано + оркестратором до первого цента. +2. **Драйвер правлен ПОСЛЕ первого фриз-коммита** — второй фриз `44b33d9`: гейт должен был требовать + слушателя на `127.0.0.1:11434`, что верно для дыма и ВРЕДНО для платной фазы (чужая заглушка, + поглощающая вызовы, — ровно то, чего нельзя допустить). ⇒ бинари стоят на `b0f5d89`, харнесс — + на `44b33d9`. Правка сделана ДО первого платного вызова; форма соблюдена (новый фриз), но + расхождение двух sha названо здесь, а не подразумевается. +3. **Дымовой стенд дал локальной модели номинальную цену** (`models-smoke.yaml`, отличается от + боевого `models.yaml` РОВНО одной строкой). Без этого дым через HTTP-дверь невозможен — находка 2. + Платная фаза шла на боевом `models.yaml` фриза, и платный аккаунт заведён отдельно от дымового. +4. **`epubcheck` не гонялся** — `java` на хосте нет (§10 п.1), пак это разрешает. +5. ⛔ **ДВА МОИХ ИНСТРУМЕНТА СОБРАНЫ НЕ ИЗ ФРИЗА, и гейт их не проверяет.** `bin/stub` и + `bin/zeropipe` несут `vcs.revision=468ed4d…` и **`vcs.modified=true`** (контроль: три гейтованных + бинаря — `b0f5d89…` и `false`): они собраны из ГЛАВНОГО дерева, где лежит их исходник, а + `step_gate` смотрит только на `tmctl · tmplatformd · tmplatformctl` (`drive.sh`). Денег это не + касается — заглушка работала только в дыму, а `zeropipe` $0-рендер; но пин фазы 0 «0 достижимых + платных моделей» произведён бинарём из грязного дерева, и это надо знать. ⚠ Смягчающее и + проверяемое: ИСХОДНИК обоих закоммичен фризом `be53cc8`, то есть код пинен, даже если штамп + бинаря — нет. Нашёл критик полноты. +6. ⚠ **У фриза ДВА разных числа, и путать их нельзя.** `b0f5d89…` — sha КОДА, которым собраны + бинари (HEAD клона). `be53cc8` — КОММИТ, которым заморожены пре-регистрация и инструменты; + `44b33d9` — второй такой коммит. Первое отвечает на «что исполнялось», второе и третье — на «чем + судили». ⚠ И третье число, которое встречалось на стенде: `~/tm-coldrun-a/FROZEN_SHA.txt` до + конца смены нёс `88f1344…` — sha БРОШЕННОГО воркри, из которого для прогона не собрано ничего. + Гейт этот файл не читает, так что он никого не обманул; исправлен и снабжён объяснением. + +## 13. Заказ следующему: как чинить прибор расхождения форм + +⛔ **ПЕРВАЯ РЕДАКЦИЯ ЭТОГО ЗАКАЗА БИЛА МИМО, и это проверено исполнением, а не спором.** Она велела +переписать правило сравнения (`same_rendering`) на пословную стеммизацию. Критик применил рецепт к +прибору на боевых данных: **не вернулся ни один из 29 потерянных термов.** Правило сравнения решает, +СКЛАДЫВАТЬ ли две уже найденные формы; термы теряются раньше. + +**Чинить надо ГЕНЕРАЦИЮ КАНДИДАТОВ.** `spread.py` ищет формы регуляркой +`[А-ЯЁ][а-яёА-ЯЁ\-]+(?:\s+[А-ЯЁ][а-яёА-ЯЁ\-]+)*` — то есть **только слова с ЗАГЛАВНОЙ буквы**. Имена +она ловит, а «гу-мастера третьего оборота», «девчонку», «наложницей» — нет, потому что они строчные. +Правильный поиск: брать из целевого текста **окна длиной в число слов известной передачи, в любом +регистре**, и сравнивать их с известными формами — и только ПОТОМ складывать найденное. На тех же +данных это даёт **48 найденных термов вместо 40** (замерено мной, `checks/spread-candidate-fix-probe.txt`). +⛔ **И сразу вторая половина рецепта, без которой первая вредна:** окну нужен ФИЛЬТР, отвергающий +окна, чьи лишние слова не входят в передачу. Без него та же починка печатает девять «расхождений», +из которых ни одно не расхождение («старейшины и», «Фан не»). + +**И второе, что заказ обязан нести: знаменатель, и он ДВОЙНОЙ.** Движок уже печатает по каждому терму +и `spread=N` со списком черновых форм, и пометку `INVENTED(no draft proposed it)` +(`.bank-stop.txt`), то есть САМ называет обе популяции вопроса. Прибор по отгруженному +тексту должен считать не «сколько разнобоя я вижу», а **«что стало с теми, про кого известно, что +форма банка и форма черновика могли разойтись»** — на этой книге 9 + 7 = **16 из 69**. ⚠ На одном +`spread` половина случаев невидима: `凤雏` и `老嬷嬷` отданы черновиковой формой при `spread=1` +(§7.2), и прибор, построенный на одном знаменателе, их не увидит никогда. + +**Третье — устойчивость.** Нынешний «0» не пере-снят ни при одном другом пороге складывания; под +пословным правилом терм `沈翠` распадается на «Шэнь»/«Шэнь Цуй» и заголовочное число становится 1. +Прибор обязан печатать свой порог и давать число при двух-трёх значениях. + +Самотест уже несёт три клетки (вторая форма ловится, склонение не двоится, неотрендеренный терм даёт +ноль). К ним добавить две: **строчную многословную передачу** (на которой нынешний прибор слеп) и +**терм из `spread ≥ 2` движка**, чтобы знаменатель тоже был под пином. + +## 14. Разбор после критика полноты — что он нашёл и что с этим стало + +Критик полноты прошёл по паку и по артефактам. Три его находки были про ПРИБОР и потребовали работы, +а не текста; они исполнены здесь. + +### 14.1. ⛔ `tm_hit` — разбивка по попыткам, которой требует ИСПР. 20 (исполнена) + +Сборщик печатал СУММУ попаданий в чекпойнты (`collect.py`: `tm_hit=1 …: 6 (control: rows = 33)`), а +ИСПР. 20 называет единственным различителем именно РАЗБИВКУ: попадание ВНУТРИ одной попытки — +подозрение (прогон переигрывает сам себя и мог измерить пустоту), попадание второй попытки в +чекпойнты первой — норма резюма. Разбивка снята запросом к `project.db` (`mode=ro`): + +| попытка (по `trace_id`, который несёт её номер) | строк | `tm_hit = 1` | Σ cost | +|---|---|---|---| +| `tm-stream-run_FTHA7S6SUCJIXS2A-1` | 16 | **0** | $0.160210 | +| `tm-stream-run_FTHA7S6SUCJIXS2A-2` | 17 | **6** | $0.259213 | +| контроль: всего | 33 | 6 | $0.419423 | + +⇒ **Внутри попытки не переиграно НИЧЕГО; все шесть попаданий — вторая попытка, читающая чекпойнты +первой, и все шесть стоят $0.** Сверх того: суммы по попыткам ($0.160210 и $0.259213) ложатся на +две строки `settlement` платного аккаунта (160 211 и 259 213 µUSD) — с тем же ceil на первой (+1 +µUSD), который §5 объясняет; на второй он совпал в ноль. Это не «совпадение», а сходимость с +названным правилом округления. + +⛔ **Две мои ошибки в методе этой самой таблицы, обе названы, потому что они одного класса — «верный +прогон при неверной гипотезе».** (1) Сначала я делила попытки сравнением `ts < '2026-09-11T01:40:45'`, +а колонка хранит `'2026-09-11 01:40:45'` — с ПРОБЕЛОМ, который сортируется раньше `T`: все 33 строки +оказались «меньше границы», и разбивка напечатала 33/0 — правдоподобно и неверно. (2) Починив +разделитель, я всё ещё делила по ВРЕМЕНИ, а `ts` в sqlite секундной гранулярности: `01:40:45` против +`started_at` попытки `01:40:45.012584` — то есть все шесть подстановок буквально «раньше» её старта. +Числа при этом вышли правильные по счастливой случайности порядка. **Настоящий различитель лежал в +той же строке и не требует арифметики вовсе: `trace_id` НЕСЁТ номер попытки.** Таблица выше +пере-снята по нему; вторую ошибку нашёл критик чисел, не я. + +### 14.2. ⛔ Сборщик считает деньги ПО ВСЕМ учёткам сразу + +`collect.py` спрашивает `credit_ledger` и `reservations` без фильтра по пользователю — поэтому в его +разделе C стоит `grants: 5000000 µUSD` (два гранта по $2.50: дымовой учётке и платной) и «резерваций +всех состояний 5» (три дымовых плюс две боевых). **Пре-рег §1 развёл учётки именно для того, чтобы +этого не было, а прибор их всё равно смешал.** Числа §5 этого отчёта сняты ОТДЕЛЬНЫМ запросом с +фильтром `where user_id = 'u_ZWUVTETPZL2D6LML'` (платная учётка) и потому верны; исправлять +замороженный прибор после денег я не стала — **гап назван, и он в его же зоне ответственности.** +Контроль, доказывающий, что речь о смешении, а не о лишних деньгах: у платной учётки ровно **один** +грант 2 500 000 µUSD и ровно **две** резервации, обе `settled`. + +### 14.3. Шесть строк `banknote_export` — не ошибка, а бесплатный реплей + +В списке «строк с `err` или `finish_reason ≠ stop`» их 6 из 10. Все шесть: `tm_hit = 1`, `cost_usd = 0`, +вторая попытка, `ok = 1`. Это извлечение банкнотного блока, взятое из чекпойнта первой попытки, а не +неудачный вызов. ⇒ **денежный класс §5 п.4 — это ЧЕТЫРЕ строки `length`, а не десять**; остальные шесть +названы здесь, чтобы никто не считал их дважды. + +### 14.4. Прибор расхождения форм — второй прогон, на материале, названном паком + +§4.0 п.5 велит строить прибор на `coldrun-v16`. Строился и самотестировался он раньше, а на этом +материале прогнан теперь (копия проекта, читающий верб, $0): **14 юнитов, 11 pending, 3 с текстом** +(это и есть история 31.08: три юнита из четырнадцати до остановки снапшот-гардом), 50 канонических +термов, 49 с исходником в тексте, **11 отрендеренных, 0 отданных более чем одной формой**. + +⛔ **И снова моя ошибка по дороге, названная:** первый заход я сделала с `book_id`, который придумала +сама (`v16-readonly`), — а строки БД ключуются ИСХОДНЫМ `guzhenren-coldrun-v16`. Экспорт честно отдал +14 pending и 0 текста, и это выглядело как «в артефакте нет текста». Правильный `book_id` дал 3 юнита +с текстом. **Ноль отрендеренных термов был свойством моего запроса, а не книги** — ровно тот класс +ошибки, ради которого рядом с нулём печатается контрольная величина. + +### 14.5. Артефакты проверок, которые раньше жили только в моём выводе + +Сохранены в `~/tm-coldrun-a/evidence/checks/` — **тринадцать файлов, список полный**: +`gate-paid.txt` (гейт платной фазы целиком, включая «port 11434: nothing listens (control: 7 listeners +on this host)») · `gate-negative-controls.txt` (**три подсадки и текст каждого отказа**: чужая ревизия +с грязным деревом · бинарь БЕЗ штампа · неверный ожидаемый sha) · `zeropipe-count.txt` (8 достижимых +платных моделей в `pipeline-c1.yaml` против 0 в рендере) · `pipeline-zero-recheck.yaml` (сам рендер) · +`spread-selftest.txt` · `spread-v16.txt` · `poscontrol-collector.txt` (**подсадка банка/юнита/ +резервации с откатом — сборщик краснеет по трём осям**) · `capabilities.json` (непустой +`export_formats`) · `bank-after.json` · `epub-structure.txt` (7 записей, `nav`, 3 `itemref`, +`testzip() = None`) · `run_FTHA7S6SUCJIXS2A-1.exit` и `-2.exit` (маркеры systemd) · `spread-candidate-fix-probe.txt` +(моя проверка починки прибора: покрытие растёт, счёт расхождений — шум). Плюс +`evidence/poscontrol-paid-holes/` — контрольная сборка книги с дырами. + +### 14.6. Формула холда закрыта ТОЧНО, и расхождение пре-рега в 2 µUSD объяснено + +Пре-рег предсказал холд 2 241 629 µUSD, факт — **2 241 631**. Разница не в формуле, а в слагаемом: +я взяла ожидание из суммы глав манифеста (84 120), а платформа хранит его как +`expected_micro_usd − book_once_micro_usd` = **84 121**. Проверено запросом к её собственной строке: + +``` +⌈84 121 × 1.25⌉ + step_max 136 479 + book_once 2 000 000 = 105 152 + 136 479 + 2 000 000 = 2 241 631 +``` + +— и ровно 2 241 631 стоит в `reservations.amount_micro_usd` первой попытки. ⇒ **холд = ⌈ожидание +текста × 1.25⌉ + `step_max` + книжный бонд**, сходится до микро-доллара; формула пака +«грант ≥ 1.25×expected + step_max + 2.00» подтверждена точным замером, а не приблизительно. + +### 14.8. Третий носитель следа — systemd-маркеры выхода + +§4.3 называет третьим носителем `/runs/-.exit` — маркер ЮНИТА systemd, а не +переводческого юнита. Оба сняты и сохранены (контроль: маркеров в каталоге состояния всего 5, из них +два — этого прогона): + +``` +run_FTHA7S6SUCJIXS2A-1.exit {"result":"exit-code","code":"exited","status":"3", "at":"…01:38:48Z"} +run_FTHA7S6SUCJIXS2A-2.exit {"result":"success", "code":"exited","status":"0", "at":"…01:54:44Z"} +``` + +⇒ Банк-стоп (3) и успех (0) подтверждены ОПЕРАЦИОННОЙ СИСТЕМОЙ, а не только строкой `run_attempts`, +которую платформа пишет сама. Это единственное место в отчёте, где выход прогона предъявлен +источником вне её собственной цепочки. + +### 14.9. Файл — это ТОТ САМЫЙ текст, а не его пересказ + +Последняя сверка, которой в первой редакции не было: каждый из четырёх переведённых юнитов взят из +`units.target` платформы и найден в скачанном `book.txt` **дословно, подстрокой** — 5761, 5558, 10 206 +и 8361 знак, все четыре `True`. Арифметика сходится: Σ юнитов 29 886 знаков, файл 29 913, разница +**27** — заголовок книги, три заголовка глав и пустые строки между ними. ⇒ между тем, что заплачено, +и тем, что скачано, ничего не потеряно и ничего не добавлено. + +### 14.10. Журнал ДВИЖКА сохранён — без него половина §5.2 висела в воздухе + +Критик полноты заметил: числа `max_tokens` на входе (8496 / 16000), потолки перевыпуска (16992 / +32000), строка «stage flagged, regenerating with a larger budget … reason=empty» и отказ по +`langpack_root` (exit 10) жили только в моём выводе — в `evidence/` их не было. Журнал юнитов выгружен +и лежит в `evidence/journal/`: `run-attempt-1.log` (170 строк), `run-attempt-2.log` (246), +`smoke-langpack-exit10.log`. Проверено счётом, что цитируемое там есть: `next_max_tokens=16992` — 3 +(ровно три черновых перевыпуска), `next_max_tokens=32000` — 1 (редакторский), `max_tokens=8496` — 6, +`max_tokens=16000` — 4, «bank-mining stopped on new terms» — 1, «cannot mine a bank» — 1. + +⭐ И журнал подтверждает разметку флагов из БД **независимым носителем**: ровно четыре события +«stage flagged» — `empty` (draft ch1/0) · **`length`** (draft ch2/1) · `empty` (draft ch3/0) · +`empty` (edit ch2/0), то есть та же четвёрка и те же причины, что в колонке `degraded`. + +### 14.7. «Ноль до закрытия» предъявлен артефактом, а не выводом на экране + +Критик справедливо заметил, что нуля проекции банка в момент `awaiting_bank` в файлах не осталось. +Он предъявлен сильнее — тем самым артефактом, ИЗ КОТОРОГО платформа этот ноль и берёт: +`evidence/bankstop-paid/project.db.bank.json`, снятый в 04:39:43, несёт `terms: []`, `total: 0`, +`signed: 0` при `proposed[]` из **69** термов. Платформенный `SaveBank` читает `terms`, поэтому её +ноль — не пропажа, а точная проекция того, что ей дали. После закрытия прогона: `bank-after.json` +показывает `total: 69`, `signed: 2` — те самые два терма, подписанные через дверь. + +## 15. Где лежат артефакты + +| Что | Где | В git? | +|---|---|---| +| Инструменты (драйвер, сборщик следов, прибор форм, $0-заглушка, рендер $0-конфига) | `eval/door_to_file/` | **да**, фризы `be53cc8` и `44b33d9` | +| Пре-регистрация и этот разбор | `docs/experiments/24-door-to-file.md` | пре-рег — да (`be53cc8`); результаты лендит оркестратор | +| **Сырые платные выходы**: отгруженные `book.txt`/`book.epub`, улика банк-стопа, полный след, счёт форм, сохранённые проверки | `books/gu-zhenren/door-to-file/` | отдельный репозиторий книг, **НЕ коммитила** — лендит владелец/оркестратор | +| Стенд, копии БД, контрольные сборки, дымовая фаза | `~/tm-coldrun-a/` (вне git, но не в `/tmp` — переживает уборку скретчпадов) | нет | + +Стенд оставлен ПОДНЯТЫМ для проверки: `tmplatformd` на `127.0.0.1:8097` (pid записан в +`~/tm-coldrun-a/stand/daemon.pid`), база `tm_coldrun_door` в кластере `/tmp:55433`, клон фриза — +`~/tm-coldrun-a/freeze`. Гасить по слову оркестратора; убивать ТОЛЬКО по pid. + +## 16. Разбор после критика ЧИСЕЛ — что он опроверг и что добавил + +Второй критик пере-вывел каждое число из сырья своими командами. Две мои формулировки он опроверг +(обе сняты выше по тексту), и ещё девять вещей нашёл сам. Ниже — то, что я перепроверила своими +руками, а не приняла на слово. + +### 16.1. ⛔ ЦЕНА РАБОТЫ ПОСЧИТАНА ПО ПИНУ, А ПИН ПРОТУХ НА FLASH + +Критик заметил, что $0.419424 — не счёт провайдера, а результат прайса из `models.yaml`, и что +DeepSeek держит пиковую и офф-пиковую цену. Проверено по вендор-доке (`api-docs.deepseek.com/quick_start/pricing`, +снято 11.09.2026, два независимых захода дали одни и те же числа): + +> «Off-peak rates are half of the peak rates. **Peak hours are 01:00 - 04:00 and 06:00 - 10:00 UTC, +> Monday through Friday** (all other hours are off-peak).» + +**Прогон шёл 01:29–01:54 UTC в пятницу ⇒ ВНУТРИ пикового окна**, и пиковый прайс для него — верное +основание. Это снимает половину тревоги. Но вторая половина осталась и она дороже: + +| за 1M токенов | наш пин `models.yaml` | вендор сегодня (пик) | расхождение | +|---|---|---|---| +| flash, вход (cache miss) | **0.44** | **0.30** | ×1.47 | +| flash, вход (cache hit) | **0.014** | **0.006** | ×2.33 | +| flash, выход | **1.32** | **1.20** | ×1.10 | +| pro, вход / cache-hit / выход | 1.32 / 0.044 / 3.96 | 1.32 / 0.044 / 3.96 | **совпадает точно** | + +**Пере-считала все 27 настоящих вызовов дважды.** По пину сходится с движком **до нуля микро-долларов** +(арифметика движка безупречна). По живым вендорским числам тот же прогон стоил бы **$0.397246**: + +``` +pinned $0.419423 (flash 22 вызова $0.188953 · pro 5 вызовов $0.230471) +vendor $0.397246 (flash $0.166776 · pro $0.230471) +⇒ пин ЗАВЫШАЕТ этот прогон на $0.022177 = 5.6 %; по flash — ×1.133, по pro — ×1.000 +``` + +⇒ **«$0.419424» — это то, что насчитала НАША модель цен; провайдер по своей сегодняшней странице +взял бы ≈$0.397.** Разницу не чиню (не моя зона и не мой пак), но называю: у пина flash есть дата +(«ПИК с 16.08.2026 16:00 UTC», `models.yaml:218`), и за три недели вендор его сдвинул вниз. + +### 16.2. ⛔ СЛАГ, КОТОРОГО НЕТ В НАШЕМ РЕЕСТРЕ + +`model_requested` = `deepseek-v4-flash` (наш конфиг), `model_actual` = **`deepseek-flash`** — на **28** +строках из 33 (у pro обе колонки совпадают). Слага `deepseek-flash` в `models.yaml` нет вовсе, а +вендорская прайс-страница называет модель именно так. То есть **имя, под которым нам отвечают и по +которому вендор нас считает, отличается от имени, которое мы шлём и по которому считаем себя.** +Правило проекта здесь однозначно — «слаг живой ≠ модель та же», — и это вопрос бэкенду, а не вывод +прогона. **Замерено**: счёт строк по паре колонок. **Не установлено**: алиас это или другая модель. + +### 16.3. Отказы не видны через `err` — только через `degraded` + +`err` пуст на **всех 33** строках, включая четыре провальные (контроль: `err <> ''` → 0). Признак +отказа живёт в колонке `degraded`: `empty` ×3, `length` ×1, пусто ×29. ⇒ **любой аудит денег или +отказов, написанный через `err`, прочитает этот прогон как идеально чистый** — и не увидит четверти +траты. Мой сборщик спасся тем, что смотрел на `finish_reason` и `ok`, а не на `err`. + +### 16.4. Три вызова из четырёх вернули РОВНО НОЛЬ символов + +В `checkpoints` у их `request_hash` `length(response_text)`: id 1 → **0**, id 7 → **0**, id 31 → **0**, +id 5 → 4203 (обрезок, выброшен и перекуплен). ⇒ **$0.094835 = 22.6 % прогона куплено за ноль знаков**, +и ещё 2.8 % — за выброшенный обрезок. У id 31 ноль знаков стоил **16 000 оплаченных выходных токенов**. + +⚠ **И самое неприятное: флор, поднятый ИМЕННО против этого, не помог.** `models.yaml` у +`deepseek-v4-pro` несёт `min_max_tokens: 16000`, поднятый с 8000 после прошлого инцидента, и рядом +записана его цена: «$0.0177, то есть 15.5 % всего счёта прогона, ушло в две выброшенные генерации». +Здесь ОДИН вызов на поднятом флоре сжёг 16 000 токенов и вернул ноль: **$0.071009 = 16.9 % счёта — +доля БОЛЬШЕ, чем у инцидента, ради которого флор поднимали.** + +### 16.5. `chunk_status` — четвёртый «путь счёта», который был бы неверен + +Σ `chunk_status.cost_usd` = **0.354127** против 0.419423. Недостача — **ровно** терминологический +контур ($0.065297): в `chunk_status` 10 строк и только стадии `draft` и `edit`, строк терминологии там +нет по построению. Таблица напрашивается как ещё один «независимый» счёт денег и им не является. + +### 16.6. Резюм выдал согласие на пере-оплату ВСЕГО бюджета + +`runs.resnapshot = true`, `runs.accept_rebill_micro = **2 241 631**` ($2.24) — санкция на пере-покупку +всего, что прогон уже купил. Фактически пере-куплено $0.028742 (терминология), потому что все шесть +черновых единиц вернулись из чекпойнтов бесплатно. **Разрыв между выданным согласием и потраченным — +78×.** Промахнись хэши промптов — черновая волна была бы куплена заново по полной цене, и согласие на +это уже стояло в строке. **Замерено**; законен ли такой размах согласия — вопрос не этого прогона. + +### 16.7. Мелочи, каждая с числом + +- **`bank_stop_presented` = 70 при 69 предложенных** (и 69 строках `glossary`, и 69 в `bank_terms`). + Лишняя предъявленная поверхность — `方源的` (терм + частица 的), строки глоссария за ней нет. + «Предъявлено» и «предложено» — разные величины, и одна на единицу больше. +- **6 черновых чанков → 4 редакторских юнита** — это нарезка, а не потеря: манифест несёт + `units_total 2 / chunks 2` у главы 1 и `units_total 1 / chunks 2` у глав 2 и 3. Проверено и по + тексту: все четыре `units.target` входят в `book.txt` дословно. +- **Округление ВВЕРХ на каждом кадре `spend`, а не только в конце** (12044.12 → 12045 и так далее). + На этом прогоне пере-плата +0.7 µUSD, но знак у неё постоянный. +- **Метод, которым я делила попытки, был слабым.** Я сравнивала `ts` с `started_at`, а `ts` в sqlite + секундной гранулярности: `01:40:45` против `01:40:45.012584` — буквальное сравнение уводит все шесть + подстановок в первую попытку. Правильный различитель лежал в той же строке: **`trace_id` несёт номер + попытки** (`tm-stream-run_FTHA7S6SUCJIXS2A-2`). Вывод §14.1 верен, метод в нём заменён на `trace_id`. + +### 16.8. ⭐ ПОДПИСЬ ДОЕХАЛА ДО ТЕКСТА — и это лучший результат прогона после самого файла + +Вопрос, который я не задала, а критик задал: **дошли ли подписанные термины до отгруженного файла?** +Проверено по `book.txt` прямым счётом: + +| термин | что было в ЧЕРНОВИКЕ | что в ОТГРУЖЕННОМ файле | +|---|---|---| +| `古月山寨` | **ТРИ** формы, `spread=3`: «поселение Гуюэ» ×1 · «городище Гуюэ» ×1 · «горная крепость Гуюэ» ×1 (`bank-stop.txt`) | **«(г/Г)орная крепость Гуюэ» — 5 из 5**; «поселение Гуюэ» — **0**, «городище Гуюэ» — **0** | +| `方源` | «Фан Юань» | «Фан Юань» 38 + склонения 20 (Юаня 17 · Юаню 2 · Юанем 1); конкурирующих транслитераций («Фань Юань», `Fang Yuan`) — **0** | + +⇒ **контур банка со стопом и подписью отработал свои $0.0287 живьём:** разнобой, который черновик +дал по месту, в файле читателя отсутствует. Это НЕ суждение о качестве перевода — это счёт форм. + +⛔ **Две поправки к этому же абзацу, обе от критика полноты.** (1) Черновик дал `古月山寨` не две +формы, а **три** — я цитировала `other proposals` карты подписи (две) и не открыла `bank-stop.txt` +того же прогона, где стоит `spread=3` и перечислены три черновика. ⚠ И тот же класс расхождения +нашёлся ВНУТРИ одного артефакта: у `开窍大典` стоит `spread=4`, а в строке `drafts:` рядом перечислены +**три** формы. Проверено по всем 69: у **68** термов `spread=N` равно числу перечисленных форм до +единицы, и `开窍大典` — единственное исключение. **Дефект это или разные определения — НЕ +УСТАНОВЛЕНО**; для §7.1 я брала число перечисленных форм, а не счётчик. Правильное число делает вывод +СИЛЬНЕЕ, а расхождение двух артефактов движка по одному терму (`other proposals` = 2 против `drafts:` += 3) — **разные определения или дефект, НЕ УСТАНОВЛЕНО**. (2) Обобщать этот успех на книгу нельзя: +полный счёт по всем девяти разошедшимся терминам (§7.1) даёт 4 доехавших, 4 отданных не-банковской +формой и 1 отданный двумя. + +## 17. Что сказал критик по КАЖДОЙ фазе + +Критиков было два (оба — отдельные сессии-опровергатели, модель задана явно): **критик полноты** шёл +по паку пункт за пунктом против артефактов, **критик чисел** пере-выводил каждое число из сырья +своими командами. Ниже — по фазам, как требует §5 пака. + +| Фаза | Что сказал критик | Что с этим стало | +|---|---|---| +| **0 — $0-дым** | Позитивные контроли исполнены (подсадка банка/юнита/резервации, книга с дырой, две подсадки в гейт бинарей, самотест прибора форм), НО их вывод жил только в моём экране, а не в файлах. Прибор форм пинен на дымовых парах, а не на материале, названном §4.0 п.5 | Все контроли пере-сняты и сохранены в `evidence/checks/` (§14.5); прибор прогнан на `coldrun-v16` (§14.4), и по дороге вскрыта моя же ошибка с чужим `book_id` | +| **1 — предусловия** | Закрыто артефактом: манифест до фриза, контраст-артефакт по sha, пять переменных (одна из пятёрки опровергнута — у `CEILING_ARG` есть дефолт), langpack-находка | Без изменений; находки 2 и 3 (§8) заведены оркестратором рядами 411 и 412 | +| **2 — фриз** | Форма верна: клон, три условия гейта, `/tmp/.git`, штамп по каждой попытке. Но девиация «драйвер правлен ПОСЛЕ фриза» (`44b33d9`) в отчёте не названа | Названа отдельным пунктом §12.2 с обоими sha | +| **3 — пре-регистрация** | Таблица есть, но **исхода не было ни у одной строки** (отчёт на момент проверки состоял из одного пре-рега) | Написан §6 — исход у всех 21 строки, с фактом и предъявлением | +| **4 — платный прогон** | Числа денег верны, НО: «419 423 по движку» — мой floor, а не число движка; «33 вызова» — это 33 строки при 27 вызовах; разбивка `tm_hit` по попыткам не построена, хотя ИСПР. 20 называет её единственным различителем; агрегаты денег в сборщике не отфильтрованы по учётке | Две формулировки сняты (§5, §16), разбивка построена и пере-снята по `trace_id` (§14.1), гап сборщика назван (§14.2) | +| **5 — $0-разбор** | Цена посчитана по ПИНУ, а у DeepSeek есть пик/офф-пик — «прогон стоил» без вендор-сверки не заслужено; `err` пуст на всех строках; `chunk_status` недобирает терминологию; согласие на пере-оплату выдано на весь бюджет; не спрошено, доехала ли подпись до текста | Вендор-дока снята (§16.1): окно пиковое, основание верное, но пин flash протух на 13 % — новая находка; остальное внесено §16.3–16.8, включая ⭐ проверку подписи по тексту | + +### 17.1. Итог ТРЕТЬЕГО прохода — круги НЕ сошлись, и я этого не прячу + +Третий проход шёл по ЗАМОРОЖЕННОМУ документу (857 строк, sha256 `feac01e0…c8059`; критик сверил sha +дважды — в начале и в конце). Он подтвердил внесение восьми находок предыдущих проходов «точно» и +пере-снял §7.1 целиком: девятка верна, исход по каждой из девяти клеток сошёлся. **И дал четыре +новые находки:** + +1. **Второй знаменатель `INVENTED`** — 11 термов, 7 вне девятки, и среди них ещё ДВА случая + не-банковской формы в файле. Внесено: §7.2, популяция стала 16, исход 9 · 6 · 1, §13 требует + двойного знаменателя. +2. **«Шесть строк `spread ≥ 2`» — число без носителя.** Я процитировала его от критика чисел дважды; + моя собственная проверка даёт девять, и все девять — шум. Внесено: §7 и §13 переписаны, улика — + `checks/spread-candidate-fix-probe.txt`. +3. **`spread=4` у `开窍大典` при трёх перечисленных формах** — единственное расхождение счётчика со + списком на 69 термов. Внесено: §16.8. +4. **Пак требует «и в каких главах», атрибуции не было.** Внесено: §7.1 — обе формы `开窍大典` в одной + главе, не-банковский «свайный дом» через главы 1 и 3. + +Плюс две правки, внесённые НЕВЕРНО и теперь исправленные: §14.5 объявлял одиннадцать файлов, +перечисляя двенадцать при тринадцати на диске (теперь тринадцать и перечень полный), и **запись в +`docs/PROGRESS.md` была снимком ДО обоих критиков** — она несла три уже отозванных утверждения +(«шесть путей», «4 вызова из 33», «слепота из-за склонения первого слова»). Журнал читают РАНЬШЕ +отчёта, так что это была худшая из двух. Переписана. + +⇒ **Честный итог: круги не сошлись ни на первом проходе, ни на втором, ни на третьем.** Каждый +следующий критик находил меньше и мельче (13 → 4 содержательных), но НЕ ноль, и объявлять сходимость +я не имею права. Четвёртого прохода не запускала — и это решение, а не забывчивость: находки третьего +внесены, документ снова изменился, и следующий проход по изменённому документу снова найдёт +опечатки; **граница по существу пройдена там, где перестали находиться ошибки в ЧИСЛАХ и в МЕТОДЕ — +третий проход не нашёл ни одной.** + +## 18. Фаза 0 и предусловия — исход по пунктам пака + +Критик полноты заметил, что §4 ссылался на секцию «Фаза 0», которой не было: исход дыма был рассыпан +по находкам. Собран здесь. + +### 18.1. Чек-лист §4.0 п.2 — что дым обязан был доказать ДО денег + +| Пункт | Исход | Чем предъявлен | +|---|---|---| +| стенд поднят и порт отвечает ТВОЕМУ pid | ✅ | `ss -ltnp` показывал `tmplatformd` моим pid на 8097 и `stub` моим pid на 11434 | +| гость заведён | ✅ | `POST /auth/dev-login` → 204, строка в `users` | +| книга принята | ✅ | `POST /v0/books` → 201, `chapter_count: 3` | +| прогон стартовал | ✅ | `POST …/runs` → 202 · ⛔ и **не с первой попытки**: первый старт умер с exit 10 (нет `langpack_root`), второй — с `409 not_priced` до того, как локальной модели дали цену | +| кадры доехали | ✅ | `events.jsonl` дымовой книги: 29 кадров шести типов | +| узел подписи ответил | ✅ | `awaiting_bank`, exit 3, `.bank.json` с `proposed[]` | +| резюм прошёл | ✅ | вторая попытка, exit 0 | +| **выгрузка собралась и файл скачался** | ✅ | txt 4522 Б `complete = t`, epub 2984 Б (7 записей zip, `nav`, 3 `itemref`) | +| все сборщики следов печатают обещанное | ✅ | `collect.py` прошёл по дымовой книге целиком; позитивный контроль — `checks/poscontrol-collector.txt` | + +### 18.2. §4.0 п.4 — «дым меняет три фактора разом» + +Пак предупреждает, что дым меняет провайдера, книгу и базу сразу, и потому при провале платной руки +не разделит причину. **Мера принята и названа в записке-плане: базу из размена я убрала.** Платная +фаза шла на ТОЙ ЖЕ базе, ТОМ ЖЕ демоне и ТЕХ ЖЕ трёх бинарях, что дым; сменились ровно два фактора — +пайплайн (`pipeline-zero` → `pipeline-c1`) и книга (синтетический дым → срез). Оба названы в §1 с sha. +⚠ Честная оговорка: вместе с пайплайном сменился и `models.yaml` (дымовой нёс номинальную цену +локальной модели), и учётка — то есть факторов всё-таки четыре, а не два. Первые два выбраны, +вторые два вынуждены находками 1 и денежной правкой оркестратора. + +### 18.3. §4.1 п.8 — ключи провайдера + +**Исход: предусловие закрыто оркестратором, файл НЕ читался ни мной, ни платформой, живость доказана +первым платным вызовом.** Путь `TM_PLATFORM_ENGINE_KEYS_PATH=/home/ubuntu-26/projects/textmachine/backend/.env` +выдан релеем; платформа не открывает этот файл, а передаёт путь движку аргументом `--keys-file` на +`translate`. Дым шёл БЕЗ переменной намеренно — чтобы никакая ошибка конфигурации не могла дотянуться +до платного провайдера; контроль этого выбора в логе: два дымовых бута несут WARN «no +TM_PLATFORM_ENGINE_KEYS_PATH: the engine is passed no provider keys», платный бут — не несёт, а +печатает путь с `source=environment`. Первый платный вызов прошёл без отказа по авторизации +(`request_log.err` пуст на всех 33 строках) ⇒ **ключи живы**. +⚠ Паковское «без него платного пути не существует» я **прочитала в коде, но не замерила**: без +переменной движок искал бы `.env` рядом с `book.yaml`, которого SaaS-путь не пишет, и отказал бы на +проверке ключей при загрузке конфига (`CheckKeys` внутри `forWrite`). Проверять это исполнением +значило бы купить заведомо провальный старт — не стала. + +### 18.4. §4.2 — что печатается в отчёт без пере-фриза + +- **Грант:** $2.50 платной учётке, одной строкой `credit_ledger.kind='grant'` (2 500 000 µUSD). +- **`TM_PLATFORM_HOLD_FACTOR_PERCENT`:** 125, источник `default` (боевой лог бута); подтверждён + арифметикой холда до микро-доллара в §14.6. +- **TTL выгрузки:** `TM_PLATFORM_EXPORT_TTL = 24h0m0s`, источник `default`; на обеих строках + `exports` `expires_at` ровно на сутки позже `finished_at` (12.09 04:55 и 04:56). + +## 19. Состояние сдачи + +**Сделано и предъявлено:** книга проведена от двери до файла и прочитана; исход есть у каждой из 21 +строки пре-рег-таблицы (§6) и у каждого пункта §4 пака (§18 и §12); деньги сведены семью путями с +названной оговоркой про независимость (§5) и пере-проверены против вендорской страницы (§16.1); +находки размечены «замерено / прочитано / подозрение» (§8, 19 строк); девиации объявлены (§12, шесть +пунктов); что НЕ удалось — §10; слабое место прогона — §11; итог трёх проходов критиков — §17 и §17.1. + +**Что унесено в дерево:** инструменты — `eval/door_to_file/`, закоммичены фризами `be53cc8` и +`44b33d9`. Этот отчёт — `docs/experiments/24-door-to-file.md`; его результаты НЕ коммичены, лендит +оркестратор. Сырые платные выходы — `books/gu-zhenren/door-to-file/` (33 файла), репозиторий книг +отдельный, тоже не коммичены. Запись в журнал — секция «Полигон» `docs/PROGRESS.md`. + +**Что оставлено включённым и почему:** стенд жив (`tmplatformd` на `127.0.0.1:8097`, база +`tm_coldrun_door` в кластере `/tmp:55433`, клон фриза в `~/tm-coldrun-a/freeze`) — чтобы любое число +этого отчёта можно было пере-снять теми же командами. Гасить по слову оркестратора, и **только по +pid**. + +**Чего я НЕ делала и не буду:** не чинила ничего из найденного — ни пин цены, ни прибор расхождения +форм, ни свой драйвер, ни `langpack_root` в рецепте стенда. Пак запрещает прогону чинить, и это +правильно: половина находок — чужих зон, а вторая половина требует замера, а не правки. + +**Работа завершена, править не планирую.**