textmachine/docs/archive/reports/COLDRUN_B_DEBUG_2026-08-02.md

75 KiB
Raw Blame History

⟶ РЕВЮ-ШАПКА ОРКЕСТРАТОРА №10 (02.08.2026, приёмка → D39.86). ВЕРДИКТ: ПРИНЯТО. Заморозка фазы C — легитимный исход по D39.83, не провал.

Пере-проверено исполнением (не чтением): батарея вся зелёная независимо — build/vet/vet -tags live exit 0 · go test -race -count=1 ./... все пакеты ok · майнер-парити EXACT (n=13618 catastrophe{方源:0 蛊:1 蛊师:2 古月:22} recall@proposed=0.9655) · labels-фриз 5/5 ячеек (k2 34/1/6/51 · k4_inverse 3/0/1/71 · k4a 0/0/0/348 · k4b 10/1/36/99 · K6 AFTER 1/6/0/251) · голден PASS · 5 новых тестов наблюдаемости PASS. Деньги пере-выведены мной из СЫРЬЯ (sqlite3 read-only по четырём БД пробы, пересчёт провайдерских usage-колонок по вендор-ценам мимо ledger.CostUSD): леджер $0.114378, независимый путь $0.099267, разница $0.015111 = три estimated-строки декод-фейлов (строка 78 живьём); инвариант committed ≡ Σ checkpoints держится во всех четырёх проектах до 6-го знака (не только на optB). Живая проверка новой строки BANKNOTE на БД coldrun-a воспроизвела lines=182 over 18/20 chunk(s) · parse-fail chunks=3, sha256 БД до/после идентичен. Все несущие счётчики §3.2/§3.4а пере-выведены из chunk_status/request_log и сошлись (18/20 · 20/22 stop · эхо 3/20 и 4/20 · терминолог 1/5 и 5/5 · 0 из 9 при 8496 · 4 из 5 пустых при 16992). Порог 6/6 подтверждён артефактом, и оговорка честна: 元石 (4 вхождения) и 灵泉 (1) стоят в prompts/zh-ru/classifier.md дословно, остальных четырёх там 0 ⇒ дискриминирующая часть 4/4 — настоящая.

Вердикты 9-осевого refute-воркфлоу (скептик + независимый арбитр на каждую ось): CONFIRMED — Д1 (механизм и якорь chunkrun.go:52 точны, воспроизведено на самом артефакте) · Д2 · Д4 · Д3 (слом live-рига бисектнут до коммита D39.64) · карантин пробы C (боевой models.yaml побайтно = git show HEAD:, гейт цел и функционален) · стенд ≡ эталону. PARTIALLY_CONFIRMED — §3.1 и §3.3 (поправки ниже).

Поправки приёмки — читать вместе с телом (тело НЕ переписано, дисциплина «отчёт — артефакт сессии»):

  1. §3.3 «посылка строки 74 неверна» — верно ТОЛЬКО про стадийную ручку. Для бэнк-ролей посылка ЖИВА: поля reasoning у синтетической config.Stage нет, а единственный дата-путь model.extra_body гейт запрещает — thinkingControlExtraKeys включает сам ключ reasoning_effort при ЛЮБОМ значении (models.go:446-448). ⇒ на поверхности, ради которой строка 74 и писалась (терминолог, cap 8000), выбор прежний: правка Go либо амендмент гейта. Вариант (б) — НЕ «правка одной строки конфига».
  2. §3.3, второе: после санкции (б) один и тот же провод легален через stages[].reasoning и запрещён через model.extra_body; доккомменты гейта (models.go:440-448, capability.go:52-58) при этом продолжают утверждать инвариант «echo-prone провайдер ОБЯЗАН держать thinking на дефолте провайдера». Санкция (б) обязана тем же решением привести доккомменты в соответствие — иначе следующая сессия прочитает защиту как полную.
  3. §3.1 «нет автоматического пути восстановления ВООБЩЕ» — слишком сильно; но «больший бюджет не лечит» — ВЕРНО, и арбитраж это усилил. Путь есть и был включён: regenerate_before_escalate: 1 (stagerun.go:177) вылечил гл.3/чанк 1 (attempt=1, stop, отгружен). Но вылечил не бюджет: победивший вызов уложился в 8285 токенов — НИЖЕ базового потолка 8496, при выданных 16992 ⇒ добавка не была потрачена и причиной быть не могла. Лечит стохастика вызова, а не потолок — то же свойство, что квирки п.6 («эхо/думание стохастичны ПО ВЫЗОВУ при побайтно одном запросе»). Следствия для развилки: (i) вариант (а) фальсифицирован ещё и механизмом, не только ценой; (ii) regenerate_before_escalate: 2 (×4) бессмыслен — доливать нечего; (iii) реальный дешёвый рычаг того же класса — N ре-ролов на БАЗОВОМ потолке (ручка #77, строка 77), но при наблюдённой отдаче ~1/5 ожидание ≈5 роллов/чанк ≈ $0.0125 — дороже и (б), и (г), так что рычаг понят, а не рекомендован. Путь к ДРУГОЙ модели закрыт КЛАССОМ ФЛАГА, и это доказано сильнее, чем в отчёте: хоп был настроен и профинансирован (escalate_to: deepseek-v4-pro, escalation.budget_usd: 0.10 при расходе $0.0596), а escalated=0 на всех восьми юнитах. Ещё: из 7 терминальных флагов 3 — decode_error, третий класс, не retryable и не escalatable; и «14 оплаченных вызовов» в §3.1 занижает счёт на три — оплачено 17 (сам отчёт это признаёт строкой о списанных декод-фейлах, но в сводное число их не берёт).
  4. Д2: шов назван на 2/3. Третья идентичная синтетическая стадия — repair.go:384, и её доккомментарий (repair.go:377-378) декларирует ровно ту посылку, которую этот отчёт фальсифицировал («no reasoning setting, so the provider default holds — thinking stays ON»). Латентно (ключа gates.repair нет ни в одном шиппинг-конфиге), но штатная правка Д2 её пропустит. Адресация: проводной шов ровно ОДИН — :515; :568 до провайдера не доезжает (оттуда читается только st.Name), а :515 общий для ОБЕИХ ролей.
  5. Д1: «это не тихая порча» — верно только там, где санитайзер ВКЛЮЧЁН и цель = ru. Условие тройное (isFinal && Gates.Sanitizer.Enabled && checkers.TargetActive()), отчёт назвал одно. ⚠ Контрпример «есть легальная сборка без секции sanitizer» я в черновике приёмки взял неверно и снимаю: configs/pipeline-c2.yaml НЕИСПОЛНЯЕМ (CheckRunnable рубит core: C2 и стадию role: judge, config/pipeline.go:469-486), а его отсутствующий санитайзер уже забукован условием оживления (строка 33 / 13-tech-debt-anchors.md:45-47). Настоящая дыра — на оси ЦЕЛИ и она ДВУСТОРОННЯЯ: (i) без данных цели весь слой 7 инертен ПО ОТСУТСТВИЮ (осознанный дизайн, disposition.go:302-305) ⇒ для не-русской цели рубежа нет вовсе; (ii) но как только будущая ЛАТИНОПИСЬМЕННАЯ цель поедет задокументированным путём расширения (data/target-<tgt>.txt в go:embed), detectLatinInsertion (checks/sanitizer.go:228) сработает на ЧИСТОЙ целевой прозе и дропнет 100% чанков — внутри санитайзера он НЕ обусловлен TargetScriptNonLatin(), хотя доккоммент disposition.go:302-305 объявляет именно эту защиту (реальный гард стоит только на репэйре — quality.go:215, repair.go:208), а частичный файл цели невозможен (CompileCheckers паникует) ⇒ новая цель ОБЯЗАНА включить санитайзер. ⇒ ревью-вопрос «заработает ли пара, которой в репо нет, без правки Go?» для →en/→de отвечается НЕТ. Плюс: даже на сегодняшнем ru-пути худший исход — не потеря юнита, а ТИХО ОТГРУЖЕННЫЙ релейный перевод (zh→en→ru), если билингв-редактор отрендерит русский с английского черновика; ни один гейт этого не различает.
  6. Деньги черновой волны варианта (б): $0.028195, а не $0.0257. Число отчёта не воспроизводится ни из одного естественного среза; из сырья: chunk_status draft ≡ Σ чекпойнтов ≡ мой независимый пересчёт = $0.028195 (все попытки, включая хоп на pro $0.008706 и два выброшенных length $0.005085); только flash — $0.019489. Для сравнения проба C: $0.012287 волна / $0.009265 flash-only. Вывод отчёта «цена на уровне до-0731-базлайна» уцелевает только в flash-only-чтении.
  7. Вариант (г) стоит ≈×9, а не ×3.1. «×3.1» — отношение вендор-ЦЕН за токен; отчёт не учёл, что pro на том же чанке выдал 9059 выходных токенов против медианы 2330 у flash-low. Из единственного наблюдённого хопа: $0.008706/чанк ⇒ ≈$0.174 на волну 20 чанков, ×8.9 к (б) и ×7.0 к базлайну coldrun-a. n=1 — прогноз, не замер; но подавать владельцу «×3.1» нельзя.
  8. Вендор-факт, которого в отчёте НЕТ, и он бьёт по (г): та же страница guides/thinking_mode (пере-снята мной, HTTP 200) даёт маппинг per-модельно — у deepseek-v4-flash low→low, а у deepseek-v4-pro low→highна pro ручка эффорта не работает, придушить его думание нечем. И сноска (3) дословно: «We will update the actual mapped effort of deepseek-v4-pro in early August 2026» — то есть прямо сейчас; тезис «pro вендором не тронут» имеет срок годности. Обе записи внесены в experiments/00-provider-quirks.md (п.3а).
  9. Строка VOICE: поле версии говорит «гейт СКОНФИГУРИРОВАН», а не «гейт отработал»quality.go:436 читает Gates.Voice.Enabled из конфига ВРЕМЕНИ ОТЧЁТА, а счётчики приходят из строк, записанных ВО ВРЕМЯ прогона; воспроизведено: включить gates.voice в pipeline.yaml ПОСЛЕ прогона — и tmctl report напечатает rules=voice-v1-… при нулях, то есть «измерено, чисто» для книги, которую никто не мерил. Это ровно тот провал coldrun-a §7, ради которого строка вводилась. Честный дискриминатор — ЗНАМЕНАТЕЛИ: живое чтение coldrun-a даёт flags=0 over attributed=0 of replies=0, а оси там никогда не считались (флаггер живёт на ФИНАЛЬНОЙ волне, waverun.go:392,512; редакторская волна не гонялась) ⇒ бэклог 13б по-прежнему без данных (не «оси пустые»). Тем же классом: §10 утверждает «гейт выключен — строки нет» — ложно, условие печати дизъюнктивно, и SpoilerLeaks>0 при выключенном гейте голоса строку напечатает (поведение кода верное, формулировка отчёта и комментария — нет). И знаменатель BANKNOTE = len(states), включая ПРИЗРАЧНЫЕ строки retrieval_state, тогда как соседний агрегатор их фильтрует (quality.go:259-260) — на coldrun-a совпало (20 строк = 20 чанков), поэтому живая верификация это не поймала; после пере-чанковки покрытие занижается. Всё три — строка 105.
  10. Остаточный артефакт карантина: проект optNoThink стоит на банк-паузе (рассчитан на резюм), и его book.yaml:28 навсегда указывает на ungated models-PROBE-ONLY.yaml — любой резюм ИМЕННО этого проекта снова поедет с выключенным thinking. Боевые проекты его не подхватывают; помечено как СПЕНТ-проба, не резюмить. Мелкие овер-атрибуции (не меняют выводов, исправлены в D-ноте): ledger.go:47 — это internal/store/ledger.go, а не пакет internal/ledger/ · «ja-фрагмент мерился zh-таблицей» исторически неверно (до D39.64 cjkShare был Han+кана, то есть к кане слеп НЕ был; слеп был к ko/en) · classifierVersion — строковый литерал, сам не бампается, дисциплина ручная, а его бамп = смена snapshot id ⇒ промах ВСЕХ чекпойнтов книги (--resnapshot + пере-покупка) — цена, которую Д4 не назвал · новый тихий отказ в live-риге: lang.LangScripts на незарегистрированном srcLang возвращает nil без ошибки, и 100%-эхо ПРОХОДИТ пробу (сегодня безвредно — zh/ja зарегистрированы).

Ратифицировано в D39.86; новые строки бэклога 104 (ручка reasoning у бэнк-ролей + repair) и 105 (мис-вердикт классификатора); строка 46 получила живой носитель и повышенный класс; 44 закрыта фальсификацией; 13б уточнена; 16 НЕ закрыта (фаза C не гонялась). Развилка строки 74 — у владельца.

coldrun-b: отладочный холодный прогон — ФАЗА A · ФАЗА B (блокер строки 74 ВОСПРОИЗВЕДЁН) · ФАЗА C ЗАМОРОЖЕНА развилкой владельца

Сессия: бэкенд, 02.08.2026. Промт: docs/BACKEND_COLDRUN_DEBUG_SESSION_PROMPT.md (оркестратор №9, D39.83). Сессия НЕ коммитит. Деньги фазы B: $0.114378 из потолка $0.15 (76.3%), двумя независимыми путями (§4). Фаза C денег не тратила.

Эхо-блок скоупа (как понят): зона backend/ + стенд ~/books/gu-zhenren/coldrun-b/ + этот отчёт · фаза A = верификация готовности $0 · фаза B = ре-проба flash ≤$0.15 · фаза C = прогон ≤$5 · вне скоупа: сид, судья Ф2, DC7, полигон-слоты, движение CheapGateVersion/labels/голдена, ручка #77, чужие файлы, коммиты, цитирование текста книги.


§0. Итог одной страницей

  1. Фаза A зелёная. Батарея воспроизведена числами; сквозной $0-путь и CLI-читаемость проверены исполнением; в чек-листе наблюдаемости найдены и починены $0 две дыры (счётчики голос-флаггера и канала банкноты считались движком, но не имели НИ ОДНОЙ поверхности вывода).
  2. Фаза B: боевая форма НЕ здорова — блокер строки 74 воспроизведён на проводе. При боевом потолке max_tokens=8496 0 из 9 черновых вызовов дали пригодный ответ (8 empty, 1 length с обрывком). Вариант (а) «флор 16000» ФАЛЬСИФИЦИРОВАН: на удвоенном потолке 16992 — 4/5 тоже пустые, размышление растёт и съедает добавку.
  3. Найден работающий путь, и он дешевле, чем ожидалось: явный reasoning_effort: "low"правкой ОДНОЙ строки ран-конфига, БЕЗ правки Go и БЕЗ амендмента echoMineViolation (посылка бэклога 74 о необходимости амендмента неверна — обоснование в §3.3, проверено исполнением). На нём 18 из 20 чанков отгружены (20 из 22 свежих вызовов finish=stop), цена волны на уровне до-0731-базлайна.
  4. Цена этого пути названа честно: эхо 3/20 (15%) против 2/20 у coldrun-a, и один черновик из 18 пришёл целиком НА АНГЛИЙСКОМ — класс, которого до-0731 в прогонах не было.
  5. Терминолог вариантом (б) НЕ лечится: у бэнк-ролей вообще нет ручки reasoning, они всегда едут вендор-дефолтом high. 4 из 5 батчей вернулись пустыми, банк консолидировал 1 терм из 81. Любая резолюция строки 74 обязана накрыть терминолога отдельно — это требует правки Go, которую сессия НЕ делает до решения владельца.
  6. Классификатор 6/6 — порог взят ($0.000390, finish=stop), с честной оговоркой о 2 «подсказанных» термах (§3.5).
  7. Фаза C не запускалась: промт делает её условной на «здоров по ВСЕМ критериям», а критерий «0 пустых ответов» нарушен. Стенд coldrun-b построен, проверен $0 и стоит нетронутым — прогон стартует одной командой сразу после решения владельца.

Что прогон уже ДОКАЗАЛ о бэкенде (живыми деньгами, а не тестами): нарезка · черновая волна на 4 воркерах · classify/disposition (поймал 3/3 эха, все length/empty) · эскалация одним хопом с ре-гейтом · канал банкноты (129 строк на 14/20 чанков) · майнер+слияние банка (76 кандидатов, 100% dst в кириллице, 0 утечек письма) · банк-пауза --verify-bank (exit 3 + сайдкары) · деньги (committed ≡ Σ checkpoints, потолок физически выстрелил на 98.7%) · F4-бэкап перед каждым платным стартом · graceful SIGINT посреди волны · $0-резюм (20 юнитов из chunk_status + 5 чекпойнтов, 0 вызовов, леджер байт-в-байт тот же).


§1. Фаза A — верификация готовности ($0)

A1. Батарея — числа и команды

Проверка Команда Результат
Сборка go build ./... exit 0
Вет go vet ./... · go vet -tags live ./internal/pipeline/ exit 0 (второй — после фикса, см. §5-Д3)
Сьют go test -race -count=1 ./... все пакеты ok (pipeline 82.4 с, store 16.1 с)
Майнер-парити TM_MINER_PARITY=1 go test ./internal/miner/ -run Parity -count=1 -v PASS · n=13618 catastrophe{方源:0 蛊:1 蛊师:2 古月:22} recall@proposed=0.9655 (56/58 GT)
Labels-фриз TM_CHECKER_LABELS=1 go test ./internal/checks/ -run TestCheckerLabelsBaseline -count=1 -v k4b 10/1/36/99 ✓ · k4_inverse 3/0/1/71 ✓ · k2 34/1/6/51 ✓ · k4a 0/0/0/348
Labels-фриз K6 TM_CHECKER_LABELS=1 go test ./internal/membank/ -run TestK6LabelsBaseline -count=1 -v AFTER tp=1 fp=6 fn=0 tn=251
Голден go test ./internal/pipeline/ -run TestGoldenDeterminism -count=1 -v PASS

Все 5 фрозен-ячеек промта воспроизведены точно. Батарея пере-прогнана ПОСЛЕ моих правок — зелёная (§5).

A2. Сквозной $0-путь и CLI-читаемость

  • Сквозняк = TestGoldenDeterminism (полный пайплайн draft→edit на фейк-провайдере, 8 юнитов, 4 flagged; book run finished … run_usd=0.000000). Отдельного CLI-достижимого фейк-провайдера нет — согласен с приором промта.
  • CLI-читаемость проверена НЕ локальной моделью, а read-only чтением БОЕВОЙ БД coldrun-a — это строго сильнее: реальные данные, реальный drift, $0, и заодно проверка инварианта «OpenReadOnly ничего не мутирует». sha256 guzhenren-coldrun-a.db до и после трёх команд — 770488e241d4… идентичен. tmctl status → CONFIG-DRIFT + проекция пере-оплаты 20 юнитов ≈ $0.024056; tmctl report → 68 строк request_log; tmctl export--plaintext) → JSON с config_drift:true.
  • Само-поправка при разборе: первое прочтение «0/14 юнитов против 20 оплаченных = чанкер поехал» оказалось неверным. status/export считают EDIT-юниты (edit_ceiling_out: 3200), а 20 — DRAFT-чанки (draft_budget_out: 1797). Отношение 20/14 = 1.43 сходится с пар-калибровкой 56/37 = 1.51. Нарезка не менялась.

A3. Чек-лист наблюдаемости — «чем смотрю» / что починил

Узел Есть? Чем смотрю
Логи, тела запросов есть LOG_LEVEL=debug + LOG_LLM_BODIES=1 (main.go:65-70, приватность по умолчанию). ⚠ Тела усечены (obs/logging.go:103 truncateForLog) — на ответах с 20k reasoning JSON не парсится; для денег это лечится путём №2 через request_log (§4)
Деньги есть tmctl status (committed/reserved/потолок/%/прогноз) · tmctl report (per-call usage+cost+finish) · estimated-cost rows — отдельная строка для оценочных списаний · инвариант committed ≡ Σ checkpoints проверен SQL
Эскалации, ре-биллы есть reportROUTING/MONEY: escalation hops=… · spend by model: … · WARN-строки stage escalated… / escalation hop denied by a USD ceiling
Статус на ЖИВОЙ БД есть NewReadOnlyRunnerstore.OpenReadOnly без flock (runner.go:159-167,218-223) — проверено на боевой БД (см. A2)
Чекпойнты / resume / redrive есть redrive --dry-run ($0, валидирует ключи+конфиг) · $0-резюм проверен живьём (§3.4)
F4 pre-flight есть preflightBackup в диспетчере run() (main.go:74-79,88-93) — этот прогон его первый боевой клиент: 3 бэкапа созданы, integrity_check зелёный
Волны / ретраи есть draft wave started … chunks=N workers=N · stage flagged, regenerating with a larger budget … next_max_tokens=…
Майнер, банк-пауза есть bank-mining: … + сайдкары *.db.mined-signature.yaml / *.db.bank-stop.txt
Терминолог-батчи есть terminology … estimate before any call · terminology finished … consolidated/unanswered/off_language/cost_usd
flag_reason есть report → секция FLAGS; statusworst_flag по главам
Канал банкноты ДЫРА → починил $0 счётчики n_banknote_lines/banknote_parse_fail/banknote_truncated писались в retrieval_state с пака-20, но ни одна поверхность их не печатала — прошлый холодный прогон читал их SQL-ом руками
Счётчики голос-флаггера ДЫРА → починил $0 VoiceFlags/VoiceReplies/VoiceAttributed/VoicePairRegister/SpoilerLeaks агрегируются в quality.go:269-276, но renderQuality их не печатал, report --json не существует ⇒ единственный прогон с включённым гейтом не мог прочитать свои же оси
Диск есть df -h ~/books → 854 G свободно; весь стенд 101 M

Фиксы наблюдаемости (оба — только слой рендера, вердиктов и снапшота не касаются):

  • cmd/tmctl/render.go — секция === BANKNOTE …===: lines=N over K/M chunk(s) · parse-fail chunks=… · truncated chunks=…. Покрытие по чанкам печатается рядом с суммой намеренно: 12 строк на 12 чанках и 12 строк на одном — разные факты, и общая сумма второй случай прячет.
  • cmd/tmctl/render.go — строка VOICE (axes AC…): счёт вместе со знаменателями (2 из 31 атрибутированных реплик ≠ 2 из 3), ось D отдельно, версия правил рядом с числами (гейт голоса намеренно не фолдится в снапшот).
  • Обе печатаются только когда каналу есть что сказать ⇒ книга без них байт-идентична прежнему выводу. Голден их не пинит (renderQuality/renderReport не входят в testdata/golden/), CheapGateVersion не тронут.
  • Тесты: cmd/tmctl/render_observability_test.go, 5 штук — включая тест молчания на каждую строку и тест «гейт отработал и нашёл ноль» (различение «не измерено» и «измерено, чисто» — ровно тот провал, который coldrun-a §7 честно назвал).
  • Верификация на живых данных: новая строка BANKNOTE на БД coldrun-a печатает lines=182 over 18/20 chunk(s) · parse-fail chunks=3 — независимо воспроизводит числа, которые прошлая сессия добывала руками («18/20», «parse_fail на 3 чанках из 20»).

A4. Стенд

~/books/gu-zhenren/coldrun-b/ — свежая БД, сид не подключён (ключа glossary_seed нет), book.yaml от эталона coldrun-a (лейблы/жанр/register_blocklist как в эталоне), ceilings: book_usd 5.00 / day_usd 5.00. pipeline.yaml побайтно равен эталонному, кроме шапки-комментария ⇒ цена фазы C будет сравнима со строкой 16 напрямую. Срез: главы 12 (строки 1171 среза coldrun-a, 12 706 байт); добор допишет главы 310 в ТОТ ЖЕ файл, после чего он станет побайтно равен срезу coldrun-a (sha256 0b5f9b02…c89f37). Ключи проверены $0: tmctl redrive --config … --dry-run → «No flagged chunks match the selector».

Две находки стенда, обе исправлены на месте:

  1. coldrun-a/pairs/zh-ru.yamlне мусор, а несущий файл: LoadPair ищет пар-слой рядом с ран-конфигом, и он несёт АБСОЛЮТНЫЙ prompts_root. Без копии в coldrun-b конфиг падает fail-loud'ом («no prompt for pair zh-ru role editor»). Тело файла сверено с репозиторным — идентично, кроме prompts_root. (Мой первый разбор назвал каталог «мёртвым остатком» — неверно, поправлено исполнением.)
  2. ceilings.day_usd считается по КАЛЕНДАРНОМУ дню UTC и по ЭТОЙ БД (ledger.go:47,62-72). Через полночь UTC ось обнуляется ⇒ несущий предохранитель прогона — book_usd, а не day_usd. Записано в комментарий book.yaml; на длинном прогоне это надо помнить.

A5. Веха

Дыр класса «нужно чужое решение» на фазе A не найдено ⇒ перешёл в B без ожидания.


§2. Носитель ре-пробы — почему НЕ расширение live-рига (девиация от промта, с аргументом)

Промт предлагал расширить live_conformance_test.go боевым рендером. Я сделал сильнее и проще: поднял отдельный проект reprobe/ (своя БД, свой потолок $0.15, принуждаемый ДВИЖКОМ) и погнал по нему сам боевой путьtmctl translate --verify-bank.

Почему так:

  • Вопрос строки 74 звучит «расходится ли БОЕВАЯ форма». Ручной риг мог бы разойтись с ней по любой из осей (сборка сообщений, флор applyModelFloor, добавка bankTokenBudget, температура, порядок ретраев) — и тогда я бы мерил свой риг. Это ровно тот класс ошибки, который проект уже ловил у полигона (D37).
  • Боевой путь даёт бесплатно: реальные reserve→settle→checkpoint, реальный classify, реальную эскалацию, реальные сайдкары банк-паузы и деньги В ЛЕДЖЕРЕ (иначе цену пробы пришлось бы считать одним путём).
  • N=20 вместо N≈812: на эхе порядка 615% дюжина вызовов не отличает норму от регрессии.
  • Отдельная БД сохраняет право пробы провалиться, не тронув леджер и чекпойнты боевого coldrun-b.

Промт сам объявляет свои чек-листы приорами, опровергаемыми аргументом — считаю условие выполненным. Единственное, что осталось ручным ригом, — порог классификатора 6/6 (боевого верба у него нет); он тоже переведён на боевой денежный путь, см. §5-Д4.


§3. Фаза B — числа

3.1 Проба A: текущая шиппинговая форма (reasoning: "off" = вендор-дефолт high)

LOG_LEVEL=debug LOG_LLM_BODIES=1 ./bin/tmctl translate --config ~/books/gu-zhenren/coldrun-b/reprobe/book.yaml --verify-bank

Разбивка — по checkpoints.attempt (attempt 0 = боевой потолок, attempt 1 = движковое удвоение), не по глазомеру:

Потолок Свежих вызовов пригодных вердикт движка
8496 (боевой: флор 8000 + bankTokenBudget 496) 9 0 finish=length на 9 из 9; 8 × empty (контент пуст) + 1 × length (обрывок 993 симв.)
16992 (движковый ре-ген, ×2) 5 1 4 × length+пусто, 1 × stop (уложился в 8285 ток.)
2xx с нечитаемым телом (decode_error) 3 тело не декодируется, вызов списан (строка 78)

Механизм вскрыт на сыром проводе, а не выведен из счётчиков (тела из лога, LOG_LLM_BODIES=1):

# finish completion_tokens content reasoning_content
0 length 8496 (= весь потолок) 993 симв. 15 424 симв.
1 length 8496 0 18 770
2 length 8496 0 19 165
3 length 8496 0 20 884
4 length 16991 0 21 528
5 length 16991 0 21 322

Модель пере-переводит главу фразу за фразой ВНУТРИ размышленияreasoning_content — готовые русские предложения) и не доходит до ответа. Удвоение потолка добавляет ~2 000 символов размышления и не сходится: это не дегенеративный луп, а многословная обдумка (механизм D39.61 п.2, теперь при ~100% частоте на боевой форме).

Вариант (а) «поднять флор до 16000» фальсифицирован замером. Вендорская норма для эффорта high — max output 384K (quick_start/pricing), это ×45 к нашему флору; при $0.28/1M выхода один чанк стоил бы до $0.107 против сегодняшних $0.0012 (≈×90 COGS). Это не флор, это другая экономика.

Архитектурная деталь, которая делает ситуацию тупиковой без решения: empty и lengthretryable, но НЕ escalatable (disposition.go:142-149). Это правильная посылка D2 («лечение обрыва — больший бюджет на той же модели»), но 0731 её опровергает: больший бюджет НЕ лечит, а путь к другой модели для этого класса флага закрыт. ⇒ на текущем конфиге у черновой волны нет автоматического пути восстановления вообще: каждый чанк терминально флагается и книга не выезжает.

Волна остановлена мной graceful SIGINT на 14 оплаченных вызовах — дальше она пере-покупала бы уже доказанный факт. (Побочно: механика стоп/продолжить H10 проверена — чекпойнты удержали, см. §3.4.)

3.2 Проба B: явный reasoning_effort: "low" — вариант (б)

Тот же боевой путь, отдельный проект reprobe/optB/, потолок $0.04. Изменена одна строка ран-конфига: stages[draft].reasoning: "low".

Все числа — по СВЕЖИМ вызовам (request_log.tm_hit=0), чтобы $0-реплеи резюма не раздували знаменатель:

Ось Проба A (дефолт high) Проба B (low) coldrun-a 31.07 (до смены весов)
Черновые вызовы finish=stop 1 / 14 20 / 22 72 / 74 (за ЧЕТЫРЕ волны — не одна волна, в лоб не сравнивать)
Чанков отгружено (draft-юнитов ok) 1 / 8 затронутых 18 / 20 20 / 20
Эхо (cjk_artifact) 0 (до эха не доходило) 3/20 = 15% 2/20 = 10%
Терминолог: батчей stop не дошёл 1 / 5 21 / 21
Цена чистого вызова $0.000270.00135 ~$0.00124
Цена черновой волны, 20 чанков не выехала ≈$0.0257 (чистые вызовы) $0.02474
Латентность 68190 с 944 с 877 с
Wall-clock волны (4 воркера) 3 мин 06 с ~4 мин

Читать так: вариант (б) возвращает черновую волну к до-0731-поведению и к до-0731-цене (разница волн $0.0257 против $0.0247 — в пределах разброса, улучшением НЕ называю).

Цена варианта (б), названная честно:

  • Эхо вернулось на 15% (3/20) против 10% у coldrun-a. Гейт поймал все три; одну эскалация на deepseek-v4-pro вылечила ($0.008706), две остались флагнутыми — потому что потолок $0.04 (98.7% выбран) отказал в следующих хопах. То есть наблюдение эскалации усечено моим потолком, а не дефектом.
  • Один черновик из 18 пришёл ЦЕЛИКОМ НА АНГЛИЙСКОМ (ch1/chunk1: 6 078 симв., кириллица 0.000, латиница 0.792) и прошёл гейт как ok. На coldrun-a таких 0/20. Разбор класса — §5-Д1.
  • Ⓘ Число 15% — на N=20. Против «~6%» D39.61 оно не сопоставимо в лоб: та цифра снята другим харнессом на другой сборке запроса. Что 15% и 10% статистически неотличимы на таких N — тоже верно; поэтому вывод формулирую как «эхо есть и его надо считать», а не «эхо выросло».

3.3 ⚠ Посылка бэклога 74 об амендменте echoMineViolationНЕВЕРНА

Строка 74 пишет: «(б) слать reasoning_effort явно … но нужен амендмент echoMineViolation». Проверено чтением кода и исполнением — амендмент не нужен:

  • Гейт (config/models.go:485-501) инспектирует МЕХАНИЗМ, а не значение: он запрещает capabilities.reasoning.control ∈ {extra_body_disable, effort} и ключ thinking-выключателя в extra_body.
  • У DeepSeek control = ReasoningNone, и это не в запрещённом множестве.
  • При ReasoningNone (llm/capability.go:167-171): off и "" не шлют ничего (осознанный no-op — thinking остаётся ON), а low|medium|high уходят на провод как reasoning_effort как есть.
  • Исполнение: конфиг с reasoning: "low" на deepseek-стадии загрузился без ошибки и провод получил уровень (вызовы отработали за 944 с при 170300 ток. размышления вместо 1521 тыс.).
  • Вендор-дока подтверждает, что это НЕ выключение thinking: тумблер — {"thinking":{"type":"enabled/disabled"}}, эффорт — отдельный параметр {"reasoning_effort":"low/high/max"}, а none в OpenAI-формате у DeepSeek не существует вовсе.

Инвариант «DeepSeek thinking никогда не выключать» доказан НА ПРОВОДЕ, а не аргументом (разбор тел пробы B):

  • тело запроса несёт ровно ['max_tokens','messages','model','reasoning_effort','stream','temperature'], reasoning_effort = "low", ключа-выключателя thinking в теле НЕТ;
  • 24 из 24 разобранных ответов несут НЕПУСТОЙ reasoning_content (261 … 20 570 симв., медиана 925) ⇒ модель думала на каждом вызове.

⇒ Инвариант не нарушается, гейт трогать не нужно, вариант (б) — правка ран-конфига. Но это не значит, что он бесплатен: эмпирическая часть посылки (эхо деградирует непрерывно с эффортом, D39.61 п.4) подтверждена этим прогоном — 3/20 эха и 1/18 английского выхода. Решение остаётся владельца; сессия ручку в боевом coldrun-b/pipeline.yaml НЕ ставила.

3.4 Вендор-сверка (правило двух направлений — сделана ДО диагноза)

curl -sSL https://api-docs.deepseek.com/updates (HTTP 200, 02.08):

  • Новых записей после Date: 2026-07-31 НЕТ ⇒ второй смены весов вендор не объявлял; наблюдаемое — то же событие 0731, но замеренное на боевой форме.
  • Дословно из той же записи: тестировали официальный V4-Flash «using the DeepSeek Harness minimal mode … with the max effort level, topp=0.95, and temperature=1.0» — вендорская поза для 0731 — агентный высокий эффорт.

curl -sSL https://api-docs.deepseek.com/guides/thinking_mode (HTTP 200, 02.08) — ключевая и НОВАЯ для наших доков строка:

«Thinking mode is enabled by default, with the default effort being high»

и таблица маппинга для deepseek-v4-flash: low→low, high→high, xhigh→high, max→max.

⇒ Мы не шлём reasoning_effort ⇒ едем на вендор-дефолте high ⇒ на плотной ханьской прозе он не укладывается ни в 8496, ни в 16992. Запись квирков от 04.07 («только high/max, low/medium→high») устарела: low — документированный отдельный уровень. Это факт для 00-provider-quirks.md; правку файла оставляю оркестратору (чужая зона).

3.4а Проба C: thinking ВЫКЛЮЧЕН (extra_body {"thinking":{"type":"disabled"}}) — пере-замер эхо-мины на весах 0731

Повод: вопрос владельца «а выключить ризонинг нельзя?». Ответ доктриной был бы нечестным: вся наша эмпирика «thinking off → эхо» снята на V4-Flash-Preview, весов которых больше нет, а канон проекта требует пере-проверять клейм о поведении модели живой пробой. Замерил.

Проект reprobe/optNoThink/, потолок $0.03, тот же срез 10 глав. Пробная копия models-PROBE-ONLY.yaml (вне git, с громкой шапкой) снимает флаг echoes_when_thinking_off и включает вендорский выключатель; боевой configs/models.yaml не тронут, гейт echoMineViolation в репо цел. Движок на старте сам напечатал WARN про эхо-зону (sourceEchoExposure) — второй рубеж громкий.

Ось (тот же текст, 20 чанков, N=20) A: дефолт high B: reasoning_effort: low C: thinking OFF
Чанков отгружено 1 / 8 затронутых 18 / 20 18 / 20
Пустых/обрывов среди вызовов 13 из 14 2 из 22 0 из 22
Эхо (cjk_artifact) — (до эха не доходило) 3 / 20 = 15% 4 / 20 = 20%
Выход не на целевом языке 1 / 18 (английский) 0 / 18
Терминолог, батчей stop не дошёл 1 / 5 5 / 5
Деньги за весь заход $0.059590 $0.039466 $0.014932

Что это значит:

  1. Эхо-мина на 0731 ЖИВА — 4/20 при выключенном thinking. Клейм, который кодирует флаг echoes_when_thinking_off, пере-подтверждён на новых весах, а не унаследован от старых.
  2. Но механизм её отрабатывает: гейт поймал 4 из 4, эскалация на deepseek-v4-pro вылечила 2 по $0.0024; оставшиеся 2 не были вылечены только потому, что МОЙ пробный потолок $0.03 отказал в хопах (escalation hop denied by a USD ceiling; keeping the primary flag — деградация, а не падение). На боевом потолке $5 вылечились бы все четыре, добавив ~$0.010.
  3. Терминолог при выключенном ризонинге здоров: 5/5 против 1/5 у варианта (б). Это единственная из трёх конфигураций, где стадия банка работает БЕЗ правки Go.
  4. Разница 15% vs 20% эха между (б) и (C) на N=20 статистически неразличима — «непрерывная деградация защиты с эффортом» (D39.61 п.4) этими данными направленно согласуется, но НЕ разделяется.

Чего проба C НЕ измеряла и что решает всё: качество прозы. Все три пробы мерили детерминированные оси (finish/пусто/эхо/письмо/деньги). Канон «reasoning-off непригоден для роли переводчика на плотном CJK» (D19.1/D21.9) стоит НЕ только на эхе, и черновик без размышления может быть заметно хуже как текст, проходя при этом все $0-гейты. Это предмет судьи Ф2, который не гонялся. Поэтому C — измеренная опция, а не рекомендация: её принятие означает разворот ратифицированного гардрейла и обязано опираться на читку качества, а не на мои счётчики.

3.5 Порог классификатора 6/6 — ВЗЯТ

TM_LIVE=1 TM_CLASSIFY6_CONFIG=…/classify6/book.yaml go test -tags live -run TestLiveClassifierHarmSet -v ./internal/pipeline/

hits=6/6 (元石·元海·蛊室·池塘·灵泉·酒肆 → term), finish=stop, max_tokens=8000, usage 1143/1024 cached/1323 compl, $0.000390, bad_lines=0, латентность 16.4 с.

Кандидаты намеренно поданы с НЕВЕРНЫМ черновым типом (name/place) — иначе тест прошла бы и модель, просто повторяющая вход.

Честная оговорка, снижающая вес числа: 元石 и 灵泉 стоят дословно в prompts/zh-ru/classifier.md как примеры класса term. Дискриминирующее подмножество — 元海/蛊室/池塘/酒肆, и оно тоже 4/4. Читать как «4 решено + 2 вспомнено», а не как 6 независимых решений.

Ⓘ Классификатор в стену размышления НЕ упирается (402→1323 ток. вывода): его задача короткая и с закрытым словарём. Стена специфична для ДЛИННОЙ генерации на плотном хане.

3.6 Терминолог — вариантом (б) НЕ вылечен (несущее ограничение развилки)

В той же пробе B, после черновой волны:

Батч finish completion content цена
0 length 8000 (весь потолок) пусто $0.002716
1 length 8000 пусто $0.002731
2 length 8000 пусто $0.002268
3 stop 2131 есть $0.001095
4 length 8000 пусто $0.002459

terminology finished … consolidated=1 unanswered=80 bad_lines=0 off_language=0 cost_usd=0.011270банк консолидировал 1 терм из 81.

Контраст, который делает это регрессией, а не свойством стадии: на coldrun-a (до смены весов) терминолог отработал 21 батч из 21 с finish=stop, ноль обрывов. Стадия была здорова и перестала быть.

Корень (грунтован кодом): бэнк-роли собирают синтетическую стадию config.Stage{Name, Role, Model} (terminologist.go:515, :568) — поле Reasoning пустое, и у gates.terminology ключа reasoning нет вовсе. При ReasoningNone пустой эффорт не шлёт ничего ⇒ терминолог и классификатор всегда едут вендор-дефолтом high, что бы владелец ни выбрал для черновой стадии.

Резолюция строки 74 обязана накрыть терминолога отдельным изменением, и это правка Go (см. §5-Д2). Промт это предвидел («cap 8000 бьёт и СТАДИЮ ТЕРМИНОЛОГА … резолюция обязана накрыть терминолога») — подтверждаю замером и называю точный шов.

3.7 $0-резюм и стоп/продолжить — проверены живьём

./bin/tmctl translate --config …/optB/book.yaml --verify-bank (повтор): EXIT=3 · stage resolved from chunk_status × 20 · attempt served from checkpoint × 5 · calling model × 0 · committed $0.039466 → $0.039466 (SQL: 41 чекпойнта, SUM(cost_usd) идентична до и после). Плюс graceful SIGINT посреди волны пробы A: процесс вышел через context canceled, БД цела, оплаченные попытки сохранены.


§4. Деньги — двумя независимыми путями

Проект Путь №1: леджер движка Путь №2: НЕЗАВИСИМЫЙ пересчёт Инвариант
reprobe (проба A) $0.059590 $0.044480 committed ≡ Σ checkpoints
optB (проба B) $0.039466 $0.039466 committed ≡ Σ checkpoints
classify6 $0.000390 $0.000390
optNoThink (проба C) $0.014932 $0.014932
Итого фазы B $0.114378 из $0.15 (76.3%)

Путь №2 = мой собственный пересчёт провайдерских usage-колонок из request_log по опубликованным вендор-ценам (flash $0.14/$0.0028/$0.28), read-only через sqlite3, не через ledger.CostUSD.

Расхождение $0.015110 у пробы A — не ошибка, а строка 78 бэклога в живом виде: три вызова вернули 2xx с нечитаемым телом («2xx body decode failed (call IS billed)»). Провайдер их списал, токенов не сообщил, движок консервативно засеттлил оценку $0.015111 (и честно печатает estimated-cost rows: 3 отдельной строкой). $0.044480 + $0.015111 = $0.059591 ≈ леджер. ⇒ леджер = нижняя граница реального счёта провайдера, ровно как промт предупреждал; величина неизвестности на этой сессии — $0.0151.

Потолки отработали физически: optB встал на 98.7% ($0.039466 / $0.04) и отказал в дальнейших эскалационных хопах, не уронив прогон.


§5. Дефекты: найдено / починено / отложено

Починено (с тестами, батарея зелёная)

Д3. Live-риг не собирался (пре-существующий, попал бы в любую live-пробу). go vet -tags live ./internal/pipeline/undefined: cjkShare: D39.64 заменил cjkShare на sourceScriptShare(s, scripts), а build-tagged файл не обновили ⇒ per-adapter live conformance физически не запускался с D39.64. Починено: у каждой пробы появился srcLang, доля меряется против объявленных письменностей ЕЁ языка (ja-фрагмент против zh-письменностей недосчитывал бы собственное эхо).

Наблюдаемость (§A3): строки BANKNOTE и VOICE + 5 тестов, включая тесты молчания.

Найдено, НЕ починено — требует решения владельца/оркестратора

Д1. Черновик на ТРЕТЬЕМ языке проходит гейт черновой стадии. ch1/chunk1 пробы B: полный, связный перевод на английский, disposition=ok, флага нет.

  • Корень: classify экранирует исходную письменность (sourceScriptSharecjk_artifact), пустоту, обрыв и отказ. Выход на языке, который не исходный и не целевой, ни под один предикат не попадает. Это ровно бэклог-46 («38/40 дефектов латиницы живут в черновиках вне охвата гейтов»).
  • Проверил последний рубеж, прежде чем называть это дырой: прогнал ЭТОТ текст через боевые чекеры ($0, временный харнесс, удалён) — checks.SanitizeOutput возвращает total=1, cosmetic_only=false, "Latin insertion (a phrase of consecutive Latin words)"sanitizer_defect ⇒ flag+skip. Но санитайзер стоит ТОЛЬКО на финальной стадии (chunkrun.go:52, isFinal).
  • Честная формулировка: это не тихая порча, а потеря юнита + оплаченный впустую редактор. Английский черновик доезжает до редактора (деньги уплачены); если редактор вернёт русский — самолечение; если сохранит английский — санитайзер флагнет и юнит уедет пустым.
  • Частота: 1/18 на effort: low, 0/20 на до-0731-дефолте. Класс подтверждён квирками (D39.61 п.5: «единственный за 48 вызовов выход НА АНГЛИЙСКОМ»).
  • Дизайн-вопрос, а не хак: нужен ли target-script экран на выходе ЧЕРНОВОЙ стадии (у терминолога такой уже есть — gates.terminology.target_script). Это вердикт-двигающее изменение ⇒ по промту СТОП+пинг, не чиню.

Д2. У бэнк-ролей нет ручки reasoning (§3.6). Шов назван точно: terminologist.go:515 и :568 строят config.Stage без Reasoning; у config.TerminologyGate поля нет. Минимальная мультиязычная форма — reasoning (и, возможно, classify_reasoning) в gates.terminology, прокинутая в обе синтетические стадии; общность не страдает (это ран-скоупная ручка, не пар-данные). Не строю до решения владельца по развилке — знать, ЧТО прокидывать, можно только после выбора.

Д4. Роль classifier мис-вердиктится как эхо. Проба 6/6 вернула правильный ответ, но с disposition=flagged reason=cjk_artifact: classifyOutput даёт поблажку SourceEchoExpected только roleTerminologist (chunkrun.go:37), а ответ классификатора по формату ТОЖЕ состоит из исходных ханьских термов (元石⇥term) ⇒ доля исходного письма выше порога 0.15 на каждом батче.

  • Ущерб ограничен телеметрией: runBankRoleBatches кладёт run.texts[i] = att.text без проверки диспозиции (terminologist.go:603), парсинг проходит, эскалации на этом пути нет. Но каждый батч классификатора будет светиться ok=0 cjk_artifact в request_log, завышая эхо-сигнал.
  • Латентно: classify_types выключен во всех шиппинг-конфигах. Фикс — одно слово, но он двигает вердикт (classifierVersion фолдится в снапшот) ⇒ по промту СТОП+пинг.

Д5. LOG_LLM_BODIES усекает тела (obs/logging.go:103) — на ответах с 20k размышления JSON не парсится, и лог перестаёт быть вторым путём для денег. Не дефект логгера (усечение осознанное), а граница метода: второй путь строить от request_log, а не от лога. Записал как факт метода, фикса не предлагаю.

Отложено с носителем

  • Правка 00-provider-quirks.md (дефолт эффорта = high; запись 04.07 устарела; строка 0731 п.1 о «флоре 16000» опровергнута на боевой форме) — чужая зона, оркестратору, фактура в §3.1/§3.4.
  • Строка 78 (леджер = нижняя граница) получила живое число: $0.0151 неизвестности на 14 вызовов.
  • Строка 46 (гейт черновика) получила живой носитель — Д1.

§6. Фаза C — почему не запущена и что готово

Промт: «здоров по ВСЕМ критериям → фаза C без ожидания. НЕ здоров → СТОП+релей». Критерий «0 пустых ответов» нарушен на текущей шиппинговой форме (8 из 9). Запускать прогон на $5 конфигом, который покупает пустоту, — это сжечь деньги на уже доказанный факт.

Готово к старту одной командой после решения владельца: стенд coldrun-b собран, конфиг-санити пройден исполнением, ключи проверены, БД свежая и пустая ($0.000000), потолки на месте, F4-бэкап отработает на старте.

Развилка — владельцу (числа в §3):

Вариант Статус по замеру Цена
(а) флор 16000 ФАЛЬСИФИЦИРОВАН: 4/5 пустых при 16992; вендорская норма для high — 384K вывода (×45 к флору, ≈×90 COGS)
(б) reasoning_effort: "low" работает на черновой волне: 18/20 stop, цена на уровне до-0731; амендмент гейта НЕ нужен (§3.3) эхо 3/20 · 1/18 выход на англ. · терминолога надо чинить отдельно (Д2, правка Go)
(в) ждать вендора нейтрален: новых записей changelog после 31.07 нет простой
(в′) thinking OFF (замерено, §3.4а) 0 пустых из 22 · терминолог 5/5 · $0.014932 за заход — в 2.6× дешевле (б); выключатель документирован вендором и в НАШЕМ OpenAI-транспорте эхо-мина жива: 4/20, лечится гейтом+эскалацией по $0.0024/шт; разворот ратифицированного гардрейла echoMineViolation; качество прозы не судилось никем
(г) сменить модель черновика (вне списка промта — предлагаю как реальную альтернативу) не замерен; косвенно: deepseek-v4-pro вендором не тронут обновлением 0731 и в пробе B успешно отработал эскалационный хоп на боевом рендере ($0.008706, finish=stop) ~×3.1 COGS черновика; 0 правок Go, 0 правок гейта — только строка модели в ран-конфиге

Моя рекомендация (решение — не моё): (б) для черновой стадии вместе с Д2 для терминолога; при этом Д1 (экран целевого письма на черновой стадии) становится не «когда-нибудь», а условием безопасности этого выбора, потому что low — тот режим, в котором выход на третьем языке наблюдался. Если владелец не хочет трогать Go в этом заходе — (г) даёт рабочий прогон сегодня же ценой COGS и без единой правки кода; замерить его стоит ~$0.03 (одна волна на 10 главах).

Ручку #77 (regenerate_echo_before_escalate) сам не включал — по слову владельца, тем же решением.


§7. Заявление = команда (приёмка пере-ранит)

cd backend
go build ./... && go vet ./... && go vet -tags live ./internal/pipeline/
go test -race -count=1 ./...
TM_MINER_PARITY=1  go test ./internal/miner/    -run Parity                     -count=1 -v
TM_CHECKER_LABELS=1 go test ./internal/checks/  -run TestCheckerLabelsBaseline  -count=1 -v
TM_CHECKER_LABELS=1 go test ./internal/membank/ -run TestK6LabelsBaseline       -count=1 -v
go test ./internal/pipeline/ -run TestGoldenDeterminism -count=1 -v
go test ./cmd/tmctl/ -run 'TestRenderQuality|TestRenderReport' -count=1 -v      # новые строки наблюдаемости

# $0-чтения (ничего не мутируют; sha256 БД до/после совпадает)
./bin/tmctl report --config ~/books/gu-zhenren/coldrun-a/book.yaml | grep -E 'BANKNOTE|VOICE|ROUTING'
./bin/tmctl status --config ~/books/gu-zhenren/coldrun-b/reprobe/optB/book.yaml
./bin/tmctl report --config ~/books/gu-zhenren/coldrun-b/reprobe/optB/book.yaml

# платные (уже оплачены — повтор реплеит чекпойнты за $0)
LOG_LEVEL=debug LOG_LLM_BODIES=1 ./bin/tmctl translate --config ~/books/gu-zhenren/coldrun-b/reprobe/book.yaml      --verify-bank
LOG_LEVEL=debug LOG_LLM_BODIES=1 ./bin/tmctl translate --config ~/books/gu-zhenren/coldrun-b/reprobe/optB/book.yaml --verify-bank
set -a; . ./.env; set +a; TM_LIVE=1 \
  TM_CLASSIFY6_CONFIG=/home/ubuntu/books/gu-zhenren/coldrun-b/reprobe/classify6/book.yaml \
  go test -tags live -run TestLiveClassifierHarmSet -v ./internal/pipeline/

# вендор-сверка
curl -sSL --compressed https://api-docs.deepseek.com/updates
curl -sSL --compressed https://api-docs.deepseek.com/guides/thinking_mode

Сырьё (durable, вне git): ~/books/gu-zhenren/coldrun-b/ — стенд · …/reprobe/ (БД, run-01-draft.{stdout,stderr}.log, backups/) · …/reprobe/optB/ (БД, логи двух прогонов, *.db.mined-signature.yaml 76 термов, *.db.bank-stop.txt, backups/) · …/reprobe/classify6/ (БД, classifier-6of6.json).


§8. Состояние дерева (только моё; НЕ коммичено)

M backend/cmd/tmctl/render.go                              (+2 блока рендера: BANKNOTE, VOICE)
M backend/internal/pipeline/live_conformance_test.go       (починка сборки live-тега: cjkShare→sourceScriptShare)
? backend/cmd/tmctl/render_observability_test.go           (новый: 5 тестов на обе строки, включая молчание)
? backend/internal/pipeline/live_reprobe_test.go           (новый: боевой риг порога классификатора 6/6)

Чужое не тронуто: START_PROMT.MD, frontend/, platform/, .gitignore, docs/ кроме этого отчёта и записи в PROGRESS.md. Во время сессии параллельная сессия залендила D39.84 — моя зона с ней не пересекается. Временный измерительный харнесс (internal/checks/tmp_offlang_probe_test.go) удалён. CheapGateVersion, labels-фикстуры и голден-фикстуры не двигались.


§9. Критик полноты (обязательная секция — против себя)

  • N мал. 14 вызовов пробы A и 24 пробы B — одна книга, одна пара, один срез, одно окно (UTC 23:5200:22, долина). «0 из 9» — сильное число, «эхо 15% против 10%» — слабое: на таких N эти доли статистически неразличимы, и я не утверждаю, что эхо выросло.
  • Проба A и проба B не строгий A/B. Между ними изменена одна строка конфига, но окна разные (23:52 против 00:02) и провайдер мог вести себя по-разному; общий вывод держит только потому, что дельта огромна (0 пригодных из 9 против 20 stop из 22), а не потому, что эксперимент чистый.
  • Цена варианта (б) на КАЧЕСТВЕ не измерена вовсе. Я мерил детерминированные оси (finish/пусто/эхо/письмо/деньги). Читабелен ли черновик при low так же, как при high, не судил никто — D39.61 это тоже фиксировал как незакрытое. Рекомендация (б) опирается на «работает и стоит столько же», а не на «переводит так же хорошо».
  • Вариант (г) я предлагаю, не замерив. Основание косвенное: вендор объявил v4-pro нетронутым, и один хоп на нём отработал. Один вызов — не замер; перед выбором (г) нужна волна.
  • Английский выход я видел один раз. Утверждать частоту класса по 1/18 нельзя; я утверждаю только существование класса и отсутствие гейта на черновой стадии.
  • Порог 6/6 наполовину «подсказан» промптом — сказано в §3.5; независимая часть 4/4.
  • Терминолог-стену я объясняю тем же механизмом, что и черновую, но вскрыл её счётчиками (completion=8000 ровно, content пуст) и НЕ открывал сырое тело хотя бы одного батча терминолога — это слабее, чем разбор §3.1, где тела вскрыты.
  • Автор = ревьюер. Адверсариальный проход по моим фиксам (§10) сделан мной же; внешнее ревью — за оркестратором. Два клейма я в ходе сессии опроверг сам («чанкер поехал» и «pairs/ — мусор»), и это единственное свидетельство, что проход не был формальным.

§10. Адверсариальный проход по СВОИМ фиксам

Фикс Атака Итог
Строка BANKNOTE Двигает ли голден/вердикты? Нет: renderReport не входит в testdata/golden/, вердикты не читает. Голден пере-прогнан — PASS
Строка BANKNOTE Сломает ли книгу без канала? Нет: печатается при lines>0 parse_fail>0 truncated>0; тест молчания TestRenderReportStaysSilentWithoutTheBanknoteChannel
Строка BANKNOTE Верны ли числа? Независимо воспроизвела руками добытые числа coldrun-a (182 / 18 из 20 / parse-fail 3)
Строка VOICE Не выдаёт ли «чисто» за «не измерено»? Условие включает VoiceCheckVersion != "", а он ставится ТОЛЬКО при включённом гейте (quality.go:436-438) ⇒ гейт выключен — строки нет; гейт включён и ноль — печатается ноль со знаменателями. Тест …PrintsZeroWhenTheGateRan
Строка VOICE Ложится ли на неполные данные? Все поля — счётчики int, dashIfEmpty на версии; nil-путей нет
Общность обоих «Заработает ли пара, которой в репо НЕТ, без правки Go?» Да: счётчики над store, ни одного пар/книжного литерала
Общность обоих «Вторая книга той же пары — без ложных флагов?» Да: ни одна строка не флагает, обе — чистая наблюдаемость
Фикс live-рига Не изменил ли смысл пробы? Изменил в правильную сторону: доля меряется против письменностей ЯЗЫКА пробы; ja-фрагмент прежде мерился бы zh-таблицей
Риг 6/6 Не обходит ли шов егресса? Обходил — и это поймал TestProviderEgressSeamIsSingle. Переписан на runBankAttempt (боевой денежный путь) ⇒ гейт зелёный, а цена пробы попала в леджер (было — считалась мимо него)
Риг 6/6 Не подыгрывает ли тесту? Кандидаты поданы с НЕВЕРНЫМ типом; «подсказанные» промптом 元石/灵泉 вынесены отдельным счётчиком discriminating 4/4
Стенд coldrun-b Не отличается ли от эталона? pipeline.yaml побайтно равен coldrun-a кроме шапки; book.yaml отличается ровно потолками, путями и book_id — перечислено в §A4
Все правки Батарея после них build/vet/vet -tags live/-race -count=1 — зелёные; парити EXACT; labels 5/5 фрозен; голден PASS